This commit is contained in:
lunaticbum 2026-01-12 15:57:02 +09:00
parent 6e7e9685ab
commit df69d779d9
8 changed files with 3007 additions and 1969 deletions

File diff suppressed because it is too large Load Diff

View File

@ -44,6 +44,7 @@ import bums.lunatic.launcher.settings.SettingsActivity
import bums.lunatic.launcher.home.tokiz.Comics import bums.lunatic.launcher.home.tokiz.Comics
import bums.lunatic.launcher.home.tokiz.Novels import bums.lunatic.launcher.home.tokiz.Novels
import bums.lunatic.launcher.home.tokiz.Perplexity import bums.lunatic.launcher.home.tokiz.Perplexity
import bums.lunatic.launcher.home.tokiz.TokiFragment
import bums.lunatic.launcher.home.tokiz.Webtoons import bums.lunatic.launcher.home.tokiz.Webtoons
import bums.lunatic.launcher.home.tokiz.YouTube import bums.lunatic.launcher.home.tokiz.YouTube
import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.Blog
@ -479,28 +480,28 @@ open class NeoRssActivity : CommonActivity() {
} }
R.id.books ->{ R.id.books ->{
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, Novels()) .replace(R.id.fragment_container, TokiFragment.newInstanceNovels())
.commit() .commit()
} }
R.id.webtoons ->{ R.id.webtoons ->{
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, Webtoons()) .replace(R.id.fragment_container, TokiFragment.newInstanceWebtoons())
.commit() .commit()
} }
R.id.comics ->{ R.id.comics ->{
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, Comics()) .replace(R.id.fragment_container, TokiFragment.newInstanceComics())
.commit() .commit()
} }
R.id.youtube ->{ R.id.youtube ->{
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, YouTube()) .replace(R.id.fragment_container, TokiFragment.newInstanceYouTube())
.commit() .commit()
} }
R.id.perplexity ->{ R.id.perplexity ->{
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, Perplexity()) .replace(R.id.fragment_container, TokiFragment.newInstancePerplexity())
.commit() .commit()
} }
R.id.zota ->{ R.id.zota ->{

View File

@ -47,6 +47,7 @@ import bums.lunatic.launcher.R
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
import bums.lunatic.launcher.home.GeckoWeb.JxEvent
import bums.lunatic.launcher.home.NeoRssActivity.Companion.lActivity import bums.lunatic.launcher.home.NeoRssActivity.Companion.lActivity
import bums.lunatic.launcher.home.SearchBottomSheet.OnSearchListener import bums.lunatic.launcher.home.SearchBottomSheet.OnSearchListener
import bums.lunatic.launcher.home.adapters.RssItemAdapter import bums.lunatic.launcher.home.adapters.RssItemAdapter
@ -54,7 +55,6 @@ import bums.lunatic.launcher.home.adapters.SwipeToDeleteCallback
import bums.lunatic.launcher.model.RssData import bums.lunatic.launcher.model.RssData
import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.model.RssDataType
import bums.lunatic.launcher.model.WeatherForcast import bums.lunatic.launcher.model.WeatherForcast
import bums.lunatic.launcher.home.tokiz.view.JxEvent
import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.Blog
import bums.lunatic.launcher.utils.SimpleFingerGestures import bums.lunatic.launcher.utils.SimpleFingerGestures
import bums.lunatic.launcher.utils.beforeDay import bums.lunatic.launcher.utils.beforeDay
@ -581,7 +581,7 @@ internal class RssHome : Fragment() {
binding.geckoWeb.decoViews.add(activity.findViewById<ImageButton>(R.id.reload)) binding.geckoWeb.decoViews.add(activity.findViewById<ImageButton>(R.id.reload))
binding.geckoWeb.decoViews.add(activity.findViewById<ImageButton>(R.id.dl_video)) binding.geckoWeb.decoViews.add(activity.findViewById<ImageButton>(R.id.dl_video))
} }
Blog.LOGE("binding.geckoWeb.decoViews >>> ${binding.geckoWeb.decoViews.size}")
return binding.root return binding.root
} }

View File

@ -0,0 +1,698 @@
//package bums.lunatic.launcher.home.tokiz
//
//import android.content.Context
//import android.content.Intent
//import android.content.res.Configuration
//import android.net.Uri
//import android.os.Bundle
//import android.os.Handler
//import android.os.Looper
//import android.os.Message
//import android.text.InputType
//import android.text.SpannableStringBuilder
//import android.text.style.RelativeSizeSpan
//import android.view.KeyEvent
//import android.view.LayoutInflater
//import android.view.PointerIcon
//import android.view.View
//import android.view.View.GONE
//import android.view.View.VISIBLE
//import android.view.ViewGroup
//import android.widget.ArrayAdapter
//import android.widget.EditText
//import android.widget.ImageButton
//import android.widget.TextView
//import android.widget.Toast
//import androidx.activity.OnBackPressedCallback
//import androidx.appcompat.app.AlertDialog
//import androidx.core.net.toUri
//import androidx.core.view.isVisible
//import androidx.fragment.app.Fragment
//import bums.lunatic.launcher.R
//import bums.lunatic.launcher.databinding.BooktokiBinding
//import bums.lunatic.launcher.home.JxEvent
//import bums.lunatic.launcher.home.NeoRssActivity
//import bums.lunatic.launcher.home.NeoRssActivity.Companion.getRuntime
//import bums.lunatic.launcher.home.tokiz.view.JxEvent
//import bums.lunatic.launcher.home.tokiz.view.PagedTextLayout
//import bums.lunatic.launcher.home.tokiz.view.PagedTextViewInterface
//import bums.lunatic.launcher.utils.Blog
//import bums.lunatic.launcher.utils.DefaultList
//import bums.lunatic.launcher.workers.WorkersDb
//import io.realm.kotlin.Realm
//import io.realm.kotlin.UpdatePolicy
//import io.realm.kotlin.ext.copyFromRealm
//import io.realm.kotlin.ext.query
//import org.json.JSONException
//import org.json.JSONObject
//import org.mozilla.gecko.util.ThreadUtils
//import org.mozilla.geckoview.GeckoResult
//import org.mozilla.geckoview.GeckoSession
//import org.mozilla.geckoview.GeckoSessionSettings
//import org.mozilla.geckoview.WebExtension
//import java.net.URL
//import java.text.SimpleDateFormat
//import java.util.Date
//import kotlin.random.Random
//
//class UniversalToki : Fragment(), PagedTextViewInterface {
//
// // --- Configuration Arguments (각 하위 클래스의 특성을 정의) ---
// private var contentsType: String = "book" // 기본값: Novels
// private var lastNumber: Int = 468
// private var webContentsName: String = "booktoki"
// private var afterDot: String = "com"
// private var isPrivateMode: Boolean = false
// private var includeNumberInDomain: Boolean = true // 도메인에 숫자 포함 여부
// private var enableGestures: Boolean = true // 제스처 사용 여부
// private var showWebOnSwipeDown: Boolean = false // 스와이프 다운 시 웹뷰 보이기 여부
//
// // --- State Variables ---
// private var lastInfo: LastInfo? = null
// private var currentPage: ContentsPageInfo? = null
// private var saveContinuation = false
// private var lastedUrl: String? = null
// private var canGoBack: Boolean = false
// private var _binding: BooktokiBinding? = null
// private val binding get() = _binding!!
//
// private var currentTitle: String = ""
// private var currentChapter: Int = 0
//
// // WebExtension
// private var mPort: WebExtension.Port? = null
// private val mPortNam = "browser"
// private val extPath = "resource://android/assets/extensions/my_extension/"
// private val extId = "messaging@booktoki468.com"
//
// // --- Companion Object (Factory Methods for Subclass Replacement) ---
// companion object {
// private const val ARG_CONTENTS_TYPE = "type"
// private const val ARG_LAST_NUMBER = "last_num"
// private const val ARG_WEB_NAME = "web_name"
// private const val ARG_AFTER_DOT = "after_dot"
// private const val ARG_PRIVATE = "private"
// private const val ARG_INC_NUM = "inc_num"
// private const val ARG_GESTURES = "gestures"
// private const val ARG_WEB_ON_SWIPE = "web_swipe"
//
// // [팩토리 메서드] 기존 클래스들을 대체합니다.
// fun newNovels() = create("book", 468, "booktoki", "com", webOnSwipe = true)
// fun newWebtoons() = create("webtoon", 468, "newtoki", "com")
// fun newComics() = create("comics", 468, "manatoki", "net")
// fun newYoutube() = create("youtube", 143, "youtube", "com", isPrivate = true, incNum = false, gestures = false)
// fun newMagnet() = create("btsearch", 143, "btsearch", "love", incNum = false)
// fun newPerplexity() = create("perplexity", 143, "www.perplexity", "ai", incNum = false)
//
// private fun create(
// type: String, lastNum: Int, name: String, dot: String,
// isPrivate: Boolean = false, incNum: Boolean = true,
// gestures: Boolean = true, webOnSwipe: Boolean = false
// ): UniversalToki {
// return UniversalToki().apply {
// arguments = Bundle().apply {
// putString(ARG_CONTENTS_TYPE, type)
// putInt(ARG_LAST_NUMBER, lastNum)
// putString(ARG_WEB_NAME, name)
// putString(ARG_AFTER_DOT, dot)
// putBoolean(ARG_PRIVATE, isPrivate)
// putBoolean(ARG_INC_NUM, incNum)
// putBoolean(ARG_GESTURES, gestures)
// putBoolean(ARG_WEB_ON_SWIPE, webOnSwipe)
// }
// }
// }
// }
//
// override fun onCreate(savedInstanceState: Bundle?) {
// super.onCreate(savedInstanceState)
// arguments?.let {
// contentsType = it.getString(ARG_CONTENTS_TYPE, "book")!!
// lastNumber = it.getInt(ARG_LAST_NUMBER, 468)
// webContentsName = it.getString(ARG_WEB_NAME, "booktoki")!!
// afterDot = it.getString(ARG_AFTER_DOT, "com")!!
// isPrivateMode = it.getBoolean(ARG_PRIVATE, false)
// includeNumberInDomain = it.getBoolean(ARG_INC_NUM, true)
// enableGestures = it.getBoolean(ARG_GESTURES, true)
// showWebOnSwipeDown = it.getBoolean(ARG_WEB_ON_SWIPE, false)
// }
// }
//
// // --- Back Press Handling (기존 BaseToki의 뒤로가기 로직 통합) ---
// override fun onAttach(context: Context) {
// super.onAttach(context)
// requireActivity().onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
// override fun handleOnBackPressed() {
// handleBackAction()
// }
// })
// }
//
// private fun handleBackAction() {
// // 1. 뷰어(텍스트 레이어)가 켜져 있으면 끈다.
// if (binding.pagedLayer.isVisible) {
// binding.pagedLayer.visibility = GONE
// // Novels(booktoki)는 스와이프 다운이나 뒤로가기 시 웹뷰를 다시 보여줌
// if (showWebOnSwipeDown || !binding.menuWeb.isVisible) {
// binding.menuWeb.visibility = VISIBLE
// }
// onTouch(TouchArea.Center) // 터치 상태 초기화
// return
// }
//
// // 2. 웹 브라우저 뒤로가기가 가능하면 실행
// // (GeckoWeb 내부 상태가 canGoBack이면)
// if (canGoBack) {
// binding.menuWeb.session?.goBack()
// return
// }
//
// // 3. 더 이상 뒤로 갈 곳이 없으면 시스템 기본 동작(액티비티 종료 등)
// isEnabled = false // 콜백 비활성화
// requireActivity().onBackPressed()
// isEnabled = true // 다시 활성화
// }
//
// override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
// _binding = BooktokiBinding.inflate(inflater, container, false)
// return binding.root
// }
//
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// super.onViewCreated(view, savedInstanceState)
//
// setupGeckoWeb()
// setupButtons()
// setupExternalViews() // 액티비티 상단 UI 연결
//
// val nullCursor = PointerIcon.getSystemIcon(requireContext(), PointerIcon.TYPE_NULL)
// binding.root.pointerIcon = nullCursor
// }
//
// private fun setupGeckoWeb() {
// binding.menuWeb.apply {
// lastDomain = getLastedDoamin()
// privateMode = isPrivateMode
//
// setOnLongClickListener {
// if (enableGestures) onTouch(TouchArea.Center)
// return@setOnLongClickListener false
// }
//
// // --- Callbacks (GeckoWeb에서 발생한 이벤트를 여기서 처리) ---
// onLocationChangeCallback = { url ->
// val cleanUrl = if (url.split("//").size > 1) {
// url.replace("//", "/").replace("https:/", "https://")
// } else url
//
// lastedUrl = cleanUrl
//
// // 외부 뷰 업데이트 및 다운로드 가능 여부 체크
// updateAddressBar(cleanUrl)
// binding.menuWeb.checkIfDownloadable(cleanUrl)
//
// // 페이지 로드 완료 처리 (히스토리 저장 등)
// completePageLoad(LastInfo().apply {
// this.pageUrl = cleanUrl.toUri().path ?: getLastedDoamin()
// this.contentsName = webContentsName
// this.contentsType = contentsType
// this.pageIndex = 0
// })
// }
//
// onPageStartCallback = {
// binding.progress.visibility = VISIBLE
// }
//
// onPageStopCallback = { success ->
// if (success) {
// // 페이지 로드 완료 시 확장 프로그램에 리스트 요청 메시지 전송
// val message = JSONObject().put("type", "getList").put("tab", session?.settings?.screenId)
// mPort?.postMessage(message)
// }
// binding.progress.visibility = GONE
// }
//
// onSessionStateChangeCallback = { state -> onStateChange(state) }
// onPortMessageCallback = { msg -> handlePortMessage(msg) }
//
// // 제스처 연결
// jxInteface = { jxEvent ->
// if (enableGestures) {
// when (jxEvent) {
// JxEvent.SCROLL_UP -> sendScrollDown(true)
// JxEvent.SCROLL_DOWN -> sendScrollDown(false)
// JxEvent.SWIPE_LEFT -> if (contentsType == "comics") sendViewerTouch("left") else actionNextEvent()
// JxEvent.SWIPE_RIGHT -> if (contentsType == "comics") sendViewerTouch("right") else actionPrevEvent()
// else -> {}
// }
// }
// }
// }
// }
//
// private fun setupButtons() {
// // [리스트 보기 버튼]
// binding.btnList.setOnClickListener {
// val url = lastedUrl ?: getLastedDoamin()
// val path = Uri.parse(url).path ?: ""
// val processedPath = processPageUrl(path)
//
// if (processedPath.isNotEmpty()) {
// HistoryManager.getBookInfos(contentsType, processedPath) { info ->
// if (info != null && info.pages.isNotEmpty()) {
// info.pages.sortBy { it.pathUrl }
// activity?.runOnUiThread { showList(info) }
// } else {
// // DB에 없으면 현재 페이지 정보를 기반으로 재시도하거나 토스트
// showToast("목록을 불러올 수 없습니다.")
// }
// }
// } else {
// showToast("유효하지 않은 주소입니다.")
// }
// }
//
// binding.btnSetting.setOnClickListener { startActivity(Intent(requireContext(), Settings::class.java)) }
// binding.btnHistory.setOnClickListener { getHistory()?.let { showHistory(it) } }
// binding.btnHome.setOnClickListener {
// binding.pagedLayer.visibility = GONE
// goToHome()
// }
// }
//
// private fun setupExternalViews() {
// (activity as? NeoRssActivity)?.let { act ->
// // 뒤로가기 버튼
// act.findViewById<ImageButton>(R.id.back)?.setOnClickListener { handleBackAction() }
// // 새로고침
// act.findViewById<ImageButton>(R.id.reload)?.setOnClickListener { binding.menuWeb.session?.reload() }
//
// // GeckoWeb decoViews에 등록 (주소창 텍스트 업데이트용)
// binding.menuWeb.decoViews.clear()
// binding.menuWeb.decoViews.add(act.findViewById(R.id.current_address))
// binding.menuWeb.decoViews.add(act.findViewById(R.id.dl_video))
// }
// }
//
// private fun updateAddressBar(url: String) {
// (activity as? NeoRssActivity)?.findViewById<TextView>(R.id.current_address)?.let {
// it.tag = currentTitle
// it.text = url
// }
// }
//
// // --- Helper Functions ---
//
// fun openRealm(): Realm = HistoryManager.openRealm
//
// fun getLastedDoamin(): String {
// return if (includeNumberInDomain) String.format("https://%s%d.%s", webContentsName, lastNumber, afterDot)
// else String.format("https://%s.%s", webContentsName, afterDot)
// }
//
// // --- Browser State & History Logic ---
//
// fun onStateChange(sessionState: GeckoSession.SessionState) {
// // GeckoWeb의 canGoBack 상태 동기화
// canGoBack = binding.menuWeb.canGoBack ?: false
//
// if (sessionState.last().uri.length > 10) {
// lastedUrl?.let { url ->
// val path = Uri.parse(url).path ?: return@let
// HistoryManager.getBookPageInfo(contentsType, path) { info ->
// info?.let {
// currentPage = it
// currentChapter = it.chapterNum ?: 0
// HistoryManager.save(HistoryItem().putHistory(it, lastedUrl!!))
//
// updateLastInfoRealm(it)
// }
// }
// if (saveContinuation) {
// binding.menuWeb.postDelayed({ moveToNext(currentPage?.pathUrl ?: lastedUrl?.toUri()?.path) }, 10000)
// }
// }
// }
// }
//
// private fun updateLastInfoRealm(info: ContentsPageInfo) {
// openRealm().writeBlocking {
// val query = this.query<LastInfo>("contentsType == $0", contentsType).find()
// if (query.isNotEmpty()) {
// query.last()?.let { last ->
// last.title = currentTitle
// last.chapter = currentChapter
// last.contentsType = info.contentsType
// this@UniversalToki.lastInfo = copyFromRealm(last)
// }
// } else {
// LastInfo().let { last ->
// last.title = currentTitle
// last.chapter = currentChapter
// last._id = contentsType
// last.contentsType = info.contentsType
// copyToRealm(last, UpdatePolicy.ALL)
// this@UniversalToki.lastInfo = last
// }
// }
// }
// }
//
// private fun processPageUrl(pageUrl: String): String {
// try {
// if (pageUrl.isEmpty()) return ""
// var workingUrl = pageUrl
// if (workingUrl.startsWith("http")) {
// try { workingUrl = URL(workingUrl).path } catch (e: Exception) {}
// }
// // URL 경로 처리 (숫자만 있는 세그먼트 유지 등 기존 로직)
// val paths = workingUrl.split("/").filter { it.isNotEmpty() }.toMutableList()
// if (paths.isNotEmpty()) {
// val last = paths.last()
// // 기존 로직: 마지막이 숫자가 아니면 제거 (목록 페이지 등에서 필요)
// if (!last.all { it.isDigit() }) {
// // paths.removeAt(paths.size - 1) // 필요 시 주석 해제하여 사용
// }
// }
// return "/" + paths.joinToString("/")
// } catch (e: Exception) {
// e.printStackTrace()
// return pageUrl
// }
// }
//
// // --- Book Info & List Handling (오버로딩 포함) ---
//
// // [중요] PageInfosJ를 처리하는 오버로딩 (기존 로직 누락 방지)
// fun onBookInfos(infosj: PageInfosJ) {
// val realm = openRealm()
// realm.writeBlocking {
// try {
// infosj.bookPageUrl = processPageUrl(infosj.bookPageUrl ?: "")
// infosj.pages.forEach { it.pathUrl = processPageUrl(it.pathUrl ?: "") }
//
// // DB에 정보 업데이트/저장 로직
// // (기존 BaseToki.kt의 복잡한 로직을 간소화하여 호출)
// HistoryManager.getBookInfos(contentsType, infosj.bookPageUrl!!) { savedInfos ->
// if (savedInfos != null) {
// // 기존 정보가 있으면 병합
// val managedInfos = copyToRealm(savedInfos, UpdatePolicy.ALL)
// for (item in infosj.pages) {
// if (!managedInfos.hasItem(item.getRealm())) {
// managedInfos.pages.add(item.getRealm())
// }
// }
// } else {
// // 없으면 새로 생성
// val newInfos = infosj.getR()
// if (newInfos != null) {
// val managedInfos = copyToRealm(newInfos, UpdatePolicy.ALL)
// infosj.pages.forEach { managedInfos.pages.add(it.getRealm()) }
// }
// }
// }
// } catch(e: Exception) { e.printStackTrace() }
// }
// // 저장 후 리스트 표시
// onBookInfos(infosj.getR())
// }
//
// fun onBookInfos(aInfos: ContentsCollection) {
// activity?.runOnUiThread { showList(aInfos) }
// }
//
// fun showList(infos: ContentsCollection) {
// if (infos.pages.isEmpty()) return
//
// val items = ArrayList(infos.pages).apply { sortBy { it.chapterID } }
//
// DefaultList.showDefaultList(
// requireContext(),
// "현재: $currentTitle ($currentChapter 화)",
// items,
// currentChapter,
// { pos -> items[pos].chapterTitle ?: "제목 없음" },
// { pos -> moveTo(items[pos]) },
// { state ->
// if (state < 0) {
// saveContinuation = true
// moveToNext(currentPage?.pathUrl)
// }
// }
// )
// }
//
// private fun moveTo(item: ContentsPageInfo?) {
// item?.pathUrl?.let { contentsLoad(it) }
// }
//
// fun contentsLoad(pathUrl: String) {
// val fullUrl = if (pathUrl.startsWith("http")) pathUrl else getLastedDoamin() + pathUrl
// binding.menuWeb.loadUrl(fullUrl)
// }
//
// // --- History Handling ---
//
// private fun getHistory(): List<HistoryItem>? {
// return try {
// openRealm().query<HistoryItem>().query("contentsType == $0", contentsType).find().copyFromRealm().reversed()
// } catch (e: Exception) { e.printStackTrace(); null }
// }
//
// fun showHistory(infos: List<HistoryItem>) {
// val builder = AlertDialog.Builder(requireContext())
// builder.setTitle("$currentTitle : $currentChapter")
//
// val adapter = ArrayAdapter<String>(requireContext(), android.R.layout.select_dialog_singlechoice)
// infos.forEach { adapter.add(it.title) }
//
// builder.setAdapter(adapter) { dialog, which ->
// val item = infos[which]
// AlertDialog.Builder(requireContext())
// .setTitle("${item.title}로 이동?")
// .setPositiveButton("이동") { _, _ -> contentsLoad(item.pageUrl); dialog.dismiss() }
// .setNeutralButton("삭제") { _, _ ->
// openRealm().writeBlocking {
// this.query<HistoryItem>().query("title == '${item.title}'").find().lastOrNull()?.let { delete(it) }
// }
// dialog.dismiss()
// }
// .setNegativeButton("취소", null)
// .show()
// }
// builder.setNegativeButton("닫기", null)
// builder.show()
// }
//
// // --- Port Message Handling ---
// private fun handlePortMessage(msg: bums.lunatic.launcher.home.tokiz.PortMessage) {
// when(msg.type) {
// "getListResult" -> msg.bookInfos?.let { onBookInfos(it.sort()) }
// "BookContents" -> {
// msg.book?.chapterTitle?.let { onFindTitle(it) }
// msg.book?.bookContents?.let { onLoadedContents(it) }
// }
// "NotRegistered", "WebtoonContents" -> binding.pagedLayer.visibility = GONE
// "MSG" -> showToast(msg.msg ?: "")
// "PRIVATES" -> msg.privates?.let { WorkersDb.insertBulkData(it) }
// "SHOWVIEWER" -> binding.progress.visibility = GONE
// }
// }
//
// // --- Viewer Logic (PagedTextView) ---
//
// fun onFindTitle(contents: String) {
// binding.textviewTitle.text = contents
// binding.textviewTitle.setOnClickListener {
// val input = EditText(requireContext()).apply {
// setText(lastedUrl ?: "")
// inputType = InputType.TYPE_CLASS_TEXT
// }
// AlertDialog.Builder(requireContext())
// .setTitle("URL 이동")
// .setView(input)
// .setPositiveButton("이동") { _, _ -> contentsLoad(input.text.toString().trim()) }
// .setNegativeButton("취소", null)
// .show()
// }
//
// val testRegex = """[^0-9]""".toRegex()
// if (contents.contains("-")) {
// currentTitle = contents.split("-")[0]
// currentChapter = testRegex.replace(contents.split("-")[1], "").toIntOrNull() ?: 0
// } else {
// currentTitle = contents
// }
// }
//
// fun onLoadedContents(aContents: String) {
// binding.pagedLayer.post {
// if (aContents.length > 10) {
// // 텍스트 정제
// val contents = aContents.replace("\\\"", "\"").replace("\\n", System.getProperty("line.separator"))
//
// binding.pagedLayer.mPagedTextViewInterface = this
// applyReaderConfig()
//
// activity?.runOnUiThread {
// binding.pagedLayer.text = contents
// binding.pagedLayer.visibility = VISIBLE
// binding.menuWeb.visibility = GONE
// }
// binding.pagedLayer.forceUpdateUI()
//
// // 현재 페이지 정보 저장
// lastedUrl?.let { url ->
// val path = Uri.parse(url).path ?: return@let
// HistoryManager.getBookPageInfo(contentsType, path) { info ->
// info?.let {
// currentPage = it
// currentChapter = it.chapterNum ?: 0
// binding.pagedLayer.currentPage = currentChapter
// HistoryManager.save(HistoryItem().putHistory(it, url))
// }
// }
// // 콘텐츠 저장 (오프라인 등 용도)
// HistoryManager.getBooPageInfoContentsSave(contentsType, path, contents)
// }
//
// if (saveContinuation) {
// binding.menuWeb.postDelayed({ moveToNext(currentPage?.pathUrl ?: lastedUrl?.toUri()?.path) }, 10000)
// }
// }
// }
// }
//
// fun applyReaderConfig() {
// val realm = HistoryManager.openRealm
// realm.query<ReaderConfig>().find().firstOrNull()?.let { config ->
// val it = realm.copyFromRealm(config)
// activity?.runOnUiThread {
// // 폰트, 스타일, 크기 등 설정 적용
// val typeface = typesfacez[getIndex(typesfacez as PairArray<Any>, it.font ?: "")]
// binding.pagedLayer.setTypeface(resources.getFont(typeface.second))
// val color = colorz[it.style ?: 0]
// binding.pagedLayer.setColorStyle(color.second)
// binding.pagedLayer.setTextSize(it.textSize?.toFloat() ?: 14f)
// // ... 기타 패딩 등 설정
// binding.pagedLayer.invalidate()
// }
// }
// }
//
// // --- Gesture & Navigation ---
//
// fun sendScrollDown(isUp: Boolean) {
// val message = JSONObject().put("type", "scrollDown").put("isUpDown", if (isUp) 1 else -1)
// mPort?.postMessage(message)
// }
//
// fun sendViewerTouch(area: String) {
// val message = JSONObject().put("type", "ViewerTouch").put("area", area)
// mPort?.postMessage(message)
// }
//
// fun actionNextEvent(fast: Boolean = false) {
// if (binding.pagedLayer.isVisible) {
// binding.pagedLayer.doNext(fast)
// updateLastInfo(binding.pagedLayer)
// } else {
// moveToNext(currentPage?.pathUrl)
// }
// }
//
// fun actionPrevEvent(fast: Boolean = false) {
// if (binding.pagedLayer.isVisible) {
// binding.pagedLayer.doPrev(fast)
// updateLastInfo(binding.pagedLayer)
// } else {
// moveToPrev(currentPage?.pathUrl)
// }
// }
//
// fun moveToNext(path: String?) {
// path?.let { HistoryManager.getNextPage(contentsType, it) { info -> moveTo(info) } }
// }
//
// fun moveToPrev(path: String?) {
// path?.let { HistoryManager.getPrevPage(contentsType, it) { info -> moveTo(info) } }
// }
//
// fun updateLastInfo(pagedTextLayout: PagedTextLayout) {
// // 현재 페이지 인덱스 저장 (책갈피 기능)
// (currentPage?.pathUrl ?: lastedUrl?.toUri()?.path)?.let {
// HistoryManager.setBookPageInfo(contentsType, it, pagedTextLayout.current())
// }
// // ... Realm 업데이트 로직
// }
//
// override fun onTouch(touchArea: TouchArea) {
// if(!enableGestures) return
// when(touchArea) {
// TouchArea.Right -> actionNextEvent()
// TouchArea.Left -> actionPrevEvent()
// TouchArea.DoubleRight -> actionNextEvent(true)
// TouchArea.DoubleLeft -> actionPrevEvent(true)
// else -> {}
// }
// }
// override fun onSwipeLeft(count: Int) { if(enableGestures) actionNextEvent(count > 1) }
// override fun onSwipeRight(count: Int) { if(enableGestures) actionPrevEvent(count > 1) }
// override fun onSwipeDown(touchCount: Int) {
// if (touchCount == 2) {
// binding.pagedLayer.visibility = GONE
// if (showWebOnSwipeDown) binding.menuWeb.visibility = VISIBLE
// }
// }
//
// override fun onLongClick() {}
// override fun onSwipeUp(touchCount: Int) {}
// override fun onTimeoverTouch() {}
//
// private fun goToHome() {
// binding.menuWeb.loadUrl(getLastedDoamin())
// }
//
// fun showToast(msg: String) {
// activity?.runOnUiThread {
// Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
// }
// }
//
// override fun onDestroyView() {
// super.onDestroyView()
// _binding = null
// }
//
// // --- Helper for Config ---
// fun loadLastInfo() {
// var targetUrl = getLastedDoamin()
// try {
// applyReaderConfig()
// openRealm().query<LastInfo>("contentsType == $0", contentsType).find().lastOrNull()?.copyFromRealm()?.let { lastInfo ->
// HistoryManager.getBookPageInfo(contentsType, lastInfo.pageUrl) { info ->
// info?.let {
// currentPage = it
// if ((currentPage?.pathUrl?.length ?: 0) > 1) {
// HistoryManager.save(HistoryItem().putHistory(currentPage, currentPage?.pathUrl ?: getLastedDoamin()))
// currentPage?.pathUrl?.let { targetPath ->
// targetUrl = if (targetPath.startsWith("http", true)) targetPath else getLastedDoamin() + targetPath
// }
// }
// }
// }
// }
// } catch (e: Exception) { e.printStackTrace() }
// finally {
// if (lastedUrl?.contains(targetUrl) != true) {
// contentsLoad(targetUrl)
// }
// }
// }
//
// override fun onResume() {
// super.onResume()
// loadLastInfo()
// }
//}

File diff suppressed because it is too large Load Diff

View File

@ -1,336 +1,336 @@
package bums.lunatic.launcher.home.tokiz.view //package bums.lunatic.launcher.home.tokiz.view
//
import android.annotation.SuppressLint //import android.annotation.SuppressLint
import android.content.Context //import android.content.Context
import android.content.Intent //import android.content.Intent
import android.os.Build //import android.os.Build
import android.util.AttributeSet //import android.util.AttributeSet
import android.view.MotionEvent //import android.view.MotionEvent
import android.view.PointerIcon //import android.view.PointerIcon
import android.view.View //import android.view.View
import androidx.core.net.toUri //import androidx.core.net.toUri
import androidx.core.view.isVisible //import androidx.core.view.isVisible
import bums.lunatic.launcher.R //import bums.lunatic.launcher.R
import bums.lunatic.launcher.helpers.ForeGroundService //import bums.lunatic.launcher.helpers.ForeGroundService
import bums.lunatic.launcher.helpers.ForeGroundService.Companion.ACTION_VIDEO_DOWNLOAD //import bums.lunatic.launcher.helpers.ForeGroundService.Companion.ACTION_VIDEO_DOWNLOAD
import bums.lunatic.launcher.helpers.ForeGroundService.Companion.EXTRA_TARGET_URL //import bums.lunatic.launcher.helpers.ForeGroundService.Companion.EXTRA_TARGET_URL
import bums.lunatic.launcher.utils.Blog //import bums.lunatic.launcher.utils.Blog
import bums.lunatic.launcher.utils.SimpleFingerGestures //import bums.lunatic.launcher.utils.SimpleFingerGestures
import com.yausername.youtubedl_android.YoutubeDL //import com.yausername.youtubedl_android.YoutubeDL
import com.yausername.youtubedl_android.YoutubeDLRequest //import com.yausername.youtubedl_android.YoutubeDLRequest
import kotlinx.coroutines.CoroutineScope //import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers //import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch //import kotlinx.coroutines.launch
import org.mozilla.gecko.util.ThreadUtils.runOnUiThread //import org.mozilla.gecko.util.ThreadUtils.runOnUiThread
import org.mozilla.geckoview.GeckoView //import org.mozilla.geckoview.GeckoView
import java.io.File //import java.io.File
import java.util.Base64 //import java.util.Base64
import kotlin.collections.iterator //import kotlin.collections.iterator
//
enum class JxEvent { //enum class JxEvent {
SCROLL_UP, // SCROLL_UP,
SCROLL_DOWN, // SCROLL_DOWN,
SWIPE_LEFT, // SWIPE_LEFT,
SWIPE_RIGHT, // SWIPE_RIGHT,
ON_CLICK, // ON_CLICK,
} //}
typealias JxInteface = (JxEvent)->Unit //typealias JxInteface = (JxEvent)->Unit
open class BWebview : GeckoView { //open class BWebview : GeckoView {
var decoViews = arrayListOf<View>() // var decoViews = arrayListOf<View>()
@SuppressLint("ClickableViewAccessibility") // @SuppressLint("ClickableViewAccessibility")
constructor(context: Context?) : super(context) { // constructor(context: Context?) : super(context) {
this.setOnTouchListener { v, event -> // this.setOnTouchListener { v, event ->
if (event.device.name?.contains( // if (event.device.name?.contains(
"JX-12", // "JX-12",
true // true
) == true || event.device.name?.equals("J06", true) == true // ) == true || event.device.name?.equals("J06", true) == true
) { // ) {
return@setOnTouchListener mSimpleFingerGestures.onTouch(v, event) // return@setOnTouchListener mSimpleFingerGestures.onTouch(v, event)
} else { // } else {
return@setOnTouchListener super.onTouchEvent(event) // return@setOnTouchListener super.onTouchEvent(event)
} // }
} // }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val nullCursor = PointerIcon.getSystemIcon(context!!, PointerIcon.TYPE_NULL) // val nullCursor = PointerIcon.getSystemIcon(context!!, PointerIcon.TYPE_NULL)
this.setPointerIcon(nullCursor) // this.setPointerIcon(nullCursor)
} // }
} // }
//
//
@SuppressLint("ClickableViewAccessibility") // @SuppressLint("ClickableViewAccessibility")
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { // constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
this.setOnTouchListener { v,event -> // this.setOnTouchListener { v,event ->
if (event.device.name?.contains("JX-12",true) == true|| event.device.name?.equals("J06",true) == true) { // if (event.device.name?.contains("JX-12",true) == true|| event.device.name?.equals("J06",true) == true) {
return@setOnTouchListener mSimpleFingerGestures.onTouch(v,event) // return@setOnTouchListener mSimpleFingerGestures.onTouch(v,event)
} else { // } else {
return@setOnTouchListener super.onTouchEvent(event) // return@setOnTouchListener super.onTouchEvent(event)
} // }
} // }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val nullCursor = PointerIcon.getSystemIcon(context!!, PointerIcon.TYPE_NULL) // val nullCursor = PointerIcon.getSystemIcon(context!!, PointerIcon.TYPE_NULL)
this.setPointerIcon(nullCursor) // this.setPointerIcon(nullCursor)
} // }
} // }
fun videoDlownLoad(videoUrl : String) { // fun videoDlownLoad(videoUrl : String) {
val actionIntent = Intent(context, ForeGroundService::class.java).apply { // val actionIntent = Intent(context, ForeGroundService::class.java).apply {
action = ACTION_VIDEO_DOWNLOAD // action = ACTION_VIDEO_DOWNLOAD
putExtra(EXTRA_TARGET_URL, videoUrl) // 전달할 데이터 // putExtra(EXTRA_TARGET_URL, videoUrl) // 전달할 데이터
} // }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(actionIntent) // context.startForegroundService(actionIntent)
} else { // } else {
context.startService(actionIntent) // context.startService(actionIntent)
} // }
} // }
//
class GKCookie { // class GKCookie {
var COOKIES : String? = null // var COOKIES : String? = null
} // }
//
var mGKCookie : GKCookie? = null // var mGKCookie : GKCookie? = null
//
fun checkIfDownloadable(url: String) { // fun checkIfDownloadable(url: String) {
CoroutineScope(Dispatchers.Main).launch { // CoroutineScope(Dispatchers.Main).launch {
runOnUiThread { // runOnUiThread {
decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let { // decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let {
it.setOnClickListener {} // it.setOnClickListener {}
it.visibility = GONE // it.visibility = GONE
}}} // }}}
Blog.LOGE("checkIfDownloadable ${url}") // Blog.LOGE("checkIfDownloadable ${url}")
CoroutineScope(Dispatchers.IO).launch { // CoroutineScope(Dispatchers.IO).launch {
try { // try {
var request = YoutubeDLRequest(url) // var request = YoutubeDLRequest(url)
(mGKCookie?.COOKIES)?.let{ // (mGKCookie?.COOKIES)?.let{
Blog.LOGE(it) // Blog.LOGE(it)
val cookies = it.split(";") // val cookies = it.split(";")
.map { it.trim() } // .map { it.trim() }
.mapNotNull { // .mapNotNull {
val parts = it.split("=", limit = 2) // val parts = it.split("=", limit = 2)
if (parts.size == 2) parts[0] to parts[1] else null // if (parts.size == 2) parts[0] to parts[1] else null
} // }
.toMap() // .toMap()
val expires = (System.currentTimeMillis() / 1000) + 3600 * 24 * 7 // 일주일 후 만료 예시 // val expires = (System.currentTimeMillis() / 1000) + 3600 * 24 * 7 // 일주일 후 만료 예시
//
val cookieFileContent = buildString { // val cookieFileContent = buildString {
appendLine("# Netscape HTTP Cookie File") // appendLine("# Netscape HTTP Cookie File")
for ((name, value) in cookies) { // for ((name, value) in cookies) {
appendLine(".${url.toUri().host}\tTRUE\t/\tTRUE\t$expires\t$name\t$value") // appendLine(".${url.toUri().host}\tTRUE\t/\tTRUE\t$expires\t$name\t$value")
} // }
} // }
val cookieFile = File(context.filesDir, "cookies.txt") // val cookieFile = File(context.filesDir, "cookies.txt")
cookieFile.writeText(cookieFileContent) // cookieFile.writeText(cookieFileContent)
request.addOption("--cookies", cookieFile.absolutePath) // request.addOption("--cookies", cookieFile.absolutePath)
} // }
//
val videoInfo = YoutubeDL.getInstance().getInfo(request) // val videoInfo = YoutubeDL.getInstance().getInfo(request)
// videoInfo 가 null 아니고, 필요한 키(예: title, url 등)가 있으면 다운로드 가능 // // videoInfo 가 null 아니고, 필요한 키(예: title, url 등)가 있으면 다운로드 가능
Blog.LOGE("checkIfDownloadable ${url}\n videoInfo : ${videoInfo}") // Blog.LOGE("checkIfDownloadable ${url}\n videoInfo : ${videoInfo}")
var canVideoDown = videoInfo != null && !videoInfo.title.isNullOrEmpty() // var canVideoDown = videoInfo != null && !videoInfo.title.isNullOrEmpty()
CoroutineScope(Dispatchers.Main).launch { // CoroutineScope(Dispatchers.Main).launch {
runOnUiThread { // runOnUiThread {
decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let { // decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let {
it.setOnClickListener { // it.setOnClickListener {
videoDlownLoad(url) // videoDlownLoad(url)
} // }
it.visibility = if (canVideoDown){ // it.visibility = if (canVideoDown){
VISIBLE // VISIBLE
} else{ // } else{
GONE // GONE
} // }
} // }
} // }
} // }
//
} catch (e: Exception) { // } catch (e: Exception) {
e.printStackTrace() // e.printStackTrace()
Blog.LOGE("checkIfDownloadable ${url} ${e}") // Blog.LOGE("checkIfDownloadable ${url} ${e}")
CoroutineScope(Dispatchers.Main).launch { // CoroutineScope(Dispatchers.Main).launch {
runOnUiThread { // runOnUiThread {
decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let { // decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let {
it.setOnClickListener {} // it.setOnClickListener {}
it.visibility = GONE // it.visibility = GONE
}}} // }}}
} // }
} // }
} // }
val mSimpleFingerGestures = SimpleFingerGestures(omfgl = object : SimpleFingerGestures.OnFingerGestureListener{ // val mSimpleFingerGestures = SimpleFingerGestures(omfgl = object : SimpleFingerGestures.OnFingerGestureListener{
//
override fun onSwipeUp( // override fun onSwipeUp(
targetView: View, // targetView: View,
fingers: Int, // fingers: Int,
gestureDuration: Long, // gestureDuration: Long,
gestureDistance: Double // gestureDistance: Double
): Boolean { // ): Boolean {
Blog.LOGE("") // Blog.LOGE("")
jxInteface?.invoke(JxEvent.SCROLL_UP ) // jxInteface?.invoke(JxEvent.SCROLL_UP )
return true // return true
} // }
//
override fun onSwipeDown( // override fun onSwipeDown(
targetView: View, // targetView: View,
fingers: Int, // fingers: Int,
gestureDuration: Long, // gestureDuration: Long,
gestureDistance: Double // gestureDistance: Double
): Boolean { // ): Boolean {
Blog.LOGE("") // Blog.LOGE("")
jxInteface?.invoke(JxEvent.SCROLL_DOWN) // jxInteface?.invoke(JxEvent.SCROLL_DOWN)
return true // return true
} // }
//
override fun onSwipeLeft( // override fun onSwipeLeft(
targetView: View, // targetView: View,
fingers: Int, // fingers: Int,
gestureDuration: Long, // gestureDuration: Long,
gestureDistance: Double // gestureDistance: Double
): Boolean { // ): Boolean {
Blog.LOGE("") // Blog.LOGE("")
jxInteface?.invoke(JxEvent.SWIPE_LEFT) // jxInteface?.invoke(JxEvent.SWIPE_LEFT)
return true // return true
} // }
//
override fun onSwipeRight( // override fun onSwipeRight(
targetView: View, // targetView: View,
fingers: Int, // fingers: Int,
gestureDuration: Long, // gestureDuration: Long,
gestureDistance: Double // gestureDistance: Double
): Boolean { // ): Boolean {
Blog.LOGE("") // Blog.LOGE("")
jxInteface?.invoke(JxEvent.SWIPE_RIGHT) // jxInteface?.invoke(JxEvent.SWIPE_RIGHT)
return true // return true
} // }
//
override fun onPinch( // override fun onPinch(
targetView: View, // targetView: View,
fingers: Int, // fingers: Int,
gestureDuration: Long, // gestureDuration: Long,
gestureDistance: Double // gestureDistance: Double
): Boolean { // ): Boolean {
Blog.LOGE("onPinch") // Blog.LOGE("onPinch")
return true // return true
} // }
//
override fun onUnpinch( // override fun onUnpinch(
targetView: View, // targetView: View,
fingers: Int, // fingers: Int,
gestureDuration: Long, // gestureDuration: Long,
gestureDistance: Double // gestureDistance: Double
): Boolean { // ): Boolean {
Blog.LOGE("") // Blog.LOGE("")
return true // return true
} // }
//
override fun onDoubleTap( // override fun onDoubleTap(
targetView: View, // targetView: View,
fingers: Int // fingers: Int
): Boolean { // ): Boolean {
Blog.LOGE("") // Blog.LOGE("")
return true // return true
} // }
//
override fun onLongPress( // override fun onLongPress(
targetView: View, // targetView: View,
fingers: Int // fingers: Int
): Boolean { // ): Boolean {
Blog.LOGE("onLongPress") // Blog.LOGE("onLongPress")
return true // return true
} // }
//
override fun onClick( // override fun onClick(
targetView: View, // targetView: View,
fingers: Int // fingers: Int
): Boolean { // ): Boolean {
Blog.LOGE("onClick") // Blog.LOGE("onClick")
jxInteface?.invoke(JxEvent.ON_CLICK) // jxInteface?.invoke(JxEvent.ON_CLICK)
return true // return true
} // }
//
//
}) // })
companion object { // companion object {
var currentRetryCount = 0 // var currentRetryCount = 0
} // }
//
var jxInteface : JxInteface? = null // var jxInteface : JxInteface? = null
//
var lastDomain : String = "" // var lastDomain : String = ""
//
open fun loadUrl(url: String, param : String? = null) { // open fun loadUrl(url: String, param : String? = null) {
var nUrl = url // var nUrl = url
Blog.LOGE("url >>>> ${url}") // Blog.LOGE("url >>>> ${url}")
if (url.endsWith("=")) { // if (url.endsWith("=")) {
nUrl = String(Base64.getMimeDecoder().decode(url.toByteArray())) // nUrl = String(Base64.getMimeDecoder().decode(url.toByteArray()))
param?.let { // param?.let {
nUrl = nUrl.plus(param) // nUrl = nUrl.plus(param)
} // }
} else if (url.startsWith("http") == false) { // } else if (url.startsWith("http") == false) {
nUrl = lastDomain // nUrl = lastDomain
} // }
if (this.isVisible == false) { // if (this.isVisible == false) {
this.visibility = VISIBLE // this.visibility = VISIBLE
} // }
Blog.LOGE("nUrl >>>> ${nUrl}") // Blog.LOGE("nUrl >>>> ${nUrl}")
//
//
nUrl?.let { url -> // nUrl?.let { url ->
if (url.split("//").size > 1) { // if (url.split("//").size > 1) {
url.replace("//","/").replace("https:/","https://").let { // url.replace("//","/").replace("https:/","https://").let {
Blog.LOGE("url >> ${url} , it >>> ${it}") // Blog.LOGE("url >> ${url} , it >>> ${it}")
this.session?.loadUri(it) // this.session?.loadUri(it)
} // }
} else { // } else {
this.session?.loadUri(url) // this.session?.loadUri(url)
} // }
} // }
currentRetryCount = 0; // currentRetryCount = 0;
} // }
private var lastX = 0f // private var lastX = 0f
private var lastY = 0f // private var lastY = 0f
//
//
override fun onTouchEvent(event: MotionEvent): Boolean { // override fun onTouchEvent(event: MotionEvent): Boolean {
Blog.LOGE("event.device.name >>> ${event.device.name}") // Blog.LOGE("event.device.name >>> ${event.device.name}")
if (event.device.name?.contains("JX-12",true) == true || event.device.name?.equals("J06",true) == true) { // if (event.device.name?.contains("JX-12",true) == true || event.device.name?.equals("J06",true) == true) {
Blog.LOGE("BWebview onTouchEvent $event") // Blog.LOGE("BWebview onTouchEvent $event")
when (event.action) { // when (event.action) {
MotionEvent.ACTION_DOWN -> { // MotionEvent.ACTION_DOWN -> {
lastX = event.x // lastX = event.x
lastY = event.y // lastY = event.y
return true // return true
} // }
//
MotionEvent.ACTION_MOVE -> { // MotionEvent.ACTION_MOVE -> {
val deltaX = event.x - lastX // val deltaX = event.x - lastX
val deltaY = event.y - lastY // val deltaY = event.y - lastY
// 상하 이동이 더 크면(즉, 거의 수직 이동이면)만 처리 // // 상하 이동이 더 크면(즉, 거의 수직 이동이면)만 처리
if (Math.abs(deltaY) > Math.abs(deltaX)) { // if (Math.abs(deltaY) > Math.abs(deltaX)) {
// 원하는 감도 적용 // // 원하는 감도 적용
val scrollFactor = 0.1f // val scrollFactor = 0.1f
// scrollBy(0, (-deltaY * scrollFactor).toInt()) //// scrollBy(0, (-deltaY * scrollFactor).toInt())
//
jxInteface?.invoke(if ((-deltaY * scrollFactor).toInt() > 0){ // jxInteface?.invoke(if ((-deltaY * scrollFactor).toInt() > 0){
JxEvent.SCROLL_DOWN // JxEvent.SCROLL_DOWN
} else { // } else {
JxEvent.SCROLL_UP // JxEvent.SCROLL_UP
}) // })
lastY = event.y // lastY = event.y
lastX = event.x // lastX = event.x
Blog.LOGE("return true for scroll") // Blog.LOGE("return true for scroll")
return true // return true
} // }
// 좌우 이동은 무시 // // 좌우 이동은 무시
lastY = event.y // lastY = event.y
lastX = event.x // lastX = event.x
Blog.LOGE("return false") // Blog.LOGE("return false")
return false // return false
} // }
//
else -> { // else -> {
Blog.LOGE("call super") // Blog.LOGE("call super")
return super.onTouchEvent(event) // return super.onTouchEvent(event)
} // }
} // }
} else { // } else {
return super.onTouchEvent(event) // return super.onTouchEvent(event)
} // }
} // }
} //}

View File

@ -8,7 +8,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
> >
<bums.lunatic.launcher.home.tokiz.view.BWebview <bums.lunatic.launcher.home.GeckoWeb
android:id="@+id/menu_web" android:id="@+id/menu_web"
android:layout_margin="5dp" android:layout_margin="5dp"
android:layout_width="match_parent" android:layout_width="match_parent"