This commit is contained in:
2026-03-23 18:03:45 +09:00
parent 9aee32e42d
commit 112012ce0c
8 changed files with 383 additions and 104 deletions
@@ -20,7 +20,14 @@ package bums.lunatic.launcher
import android.app.Application
import android.content.ComponentCallbacks2
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.text.SpannableStringBuilder
import android.text.style.RelativeSizeSpan
import android.view.View
import android.view.View.inflate
import android.widget.TextView
import android.widget.Toast
import bums.lunatic.launcher.helpers.HourlyLogWriter
import bums.lunatic.launcher.helpers.PrefHelper
import bums.lunatic.launcher.home.Base64ImageCache
@@ -39,6 +46,7 @@ import java.io.File
import java.util.concurrent.TimeUnit
internal class LunaticLauncher : Application() {
companion object {
var appContext : LunaticLauncher? = null
@@ -49,6 +57,21 @@ internal class LunaticLauncher : Application() {
return sRuntime
}
var privateCompletedDir : File? = null
var toast : Toast? = null
fun Context.toast(msg: String) {
val biggerText = SpannableStringBuilder(msg)
biggerText.setSpan(RelativeSizeSpan(1.6f), 0, msg.length, 0)
val view: View = inflate(this, R.layout.simple_toast, null)
view.findViewById<TextView>(R.id.text).text = biggerText
if (toast==null) {
toast = Toast(this)
toast?.duration = Toast.LENGTH_SHORT
toast?.cancel()
}
toast?.view = view
toast?.show()
}
}
private fun initGeckoRuntime() {
@@ -170,7 +170,7 @@ class ForeGroundService : Service() {
set(value) {
field = value
if (value == null) {
startForeGround(max= 0, progress = 0, vibrator = true)
startForeGround(max= 0, progress = 0, vibrator = false)
}
}
@@ -190,7 +190,7 @@ class ForeGroundService : Service() {
currentProcessId = UUID.randomUUID().toString()
YoutubeDL.getInstance()
.execute(command, currentProcessId) { progress, est, str ->
startForeGround(100, progress.toInt(),str, true)
startForeGround(100, progress.toInt(),str, false)
if (progress >= 100) {
targetUrls.remove(url)
currentProcessId = null
@@ -210,7 +210,7 @@ class ForeGroundService : Service() {
}
}
fun startForeGround(max : Int = 0, progress : Int = 0, str : String? = "실행중입니다.", vibrator : Boolean? = false) {
fun startForeGround(max : Int = 0, progress : Int = 0, str : String? = "실행중입니다.", vibrator : Boolean = false) {
val currentChannelId = if (vibrator == true) "${CHANNEL_ID}_vibrate" else "${CHANNEL_ID}_silent"
@@ -7,6 +7,8 @@ import android.content.Context
import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.net.Uri
import android.os.Build
import android.text.SpannableStringBuilder
@@ -30,6 +32,7 @@ import androidx.core.net.toUri
import androidx.core.view.isVisible
import bums.lunatic.launcher.BookmarkUploader
import bums.lunatic.launcher.LunaticLauncher.Companion.getRuntime
import bums.lunatic.launcher.LunaticLauncher.Companion.toast
import bums.lunatic.launcher.R
import bums.lunatic.launcher.helpers.ForeGroundService
import bums.lunatic.launcher.helpers.ForeGroundService.Companion.ACTION_VIDEO_DOWNLOAD
@@ -306,6 +309,16 @@ open class GeckoWeb @JvmOverloads constructor(
}
}
}
fun nextShorts() {
sendJsonMsg("NEXT_SHORTS")
saveCurrentSessionState()
}
fun prevShorts() {
sendJsonMsg("PREV_SHORTS")
saveCurrentSessionState()
}
// [Navigation Delegate]
private val navigationDelegate = object : GeckoSession.NavigationDelegate {
@@ -605,25 +618,62 @@ open class GeckoWeb @JvmOverloads constructor(
var HH = 0.3
fun pageDown() {
val session = this.session ?: return
val pzc = session.panZoomController
// 💡 현재 눈에 보이는 GeckoView의 높이를 가져옵니다.
val viewHeight = this.height.toDouble().times(HH)
// 세로 방향(y)으로 뷰 높이만큼 아래로 스크롤 (픽셀 단위)
// 세 번째 인자는 애니메이션 여부입니다.
pzc.scrollBy(ScreenLength.fromPixels(0.0), ScreenLength.fromPixels(viewHeight),
PanZoomController.SCROLL_BEHAVIOR_SMOOTH)
sendJsonMsg("MARKER",Pair<String, Any?>("isDown",true))
// val pzc = session.panZoomController
//
// // 💡 현재 눈에 보이는 GeckoView의 높이를 가져옵니다.
// val viewHeight = this.height.toDouble().times(HH)
//
// // 세로 방향(y)으로 뷰 높이만큼 아래로 스크롤 (픽셀 단위)
// // 세 번째 인자는 애니메이션 여부입니다.
// pzc.scrollBy(ScreenLength.fromPixels(0.0), ScreenLength.fromPixels(viewHeight),
// PanZoomController.SCROLL_BEHAVIOR_SMOOTH)
//
// showGuideLine((this.height - viewHeight).toInt())
}
fun pageUp() {
val session = this.session ?: return
val pzc = session.panZoomController
val viewHeight = this.height.toDouble().times(HH)
sendJsonMsg("MARKER",Pair<String, Any?>("isDown",false))
// val pzc = session.panZoomController
// val viewHeight = this.height.toDouble().times(HH)
//
// // 위로 스크롤
// pzc.scrollBy(ScreenLength.fromPixels(0.0), ScreenLength.fromPixels(-viewHeight),
// PanZoomController.SCROLL_BEHAVIOR_SMOOTH)
//
// showGuideLine(viewHeight.toInt())
}
// 위로 스크롤
pzc.scrollBy(ScreenLength.fromPixels(0.0), ScreenLength.fromPixels(-viewHeight),
PanZoomController.SCROLL_BEHAVIOR_SMOOTH)
private val guideView: View by lazy {
View(context).apply {
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, 150.dpToPx()) // 150dp 정도의 넓은 영역
// 위는 투명하고 아래로 갈수록 강조색이 보이는 그라데이션
background = GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
intArrayOf(0x00FF0000, 0x40FF0000) // 투명 -> 반투명 빨강
)
visibility = GONE
}
}
private fun showGuideLine(yPosition: Int) {
sendJsonMsg("MARKER",Pair<String, Any?>("yPos",yPosition))
// if (guideView.parent == null) this.addView(guideView)
//
// guideView.apply {
// // PageDown 시에는 이전 바닥 지점(yPosition)에 뷰의 상단을 맞춤
// // PageUp 시에는 이전 천장 지점(yPosition)에 뷰의 하단을 맞춤
// translationY = if (isDown) (yPosition - 150.dpToPx()).toFloat() else yPosition.toFloat()
// visibility = VISIBLE
// alpha = 1f
//
// animate()
// .alpha(0f)
// .setDuration(800) // 너무 길면 거슬리니 0.8초 정도가 적당합니다.
// .withEndAction { visibility = GONE }
// .start()
// }
}
// File/Download Helpers
@@ -712,19 +762,7 @@ open class GeckoWeb @JvmOverloads constructor(
private fun getFilterF() = String(Base64.decode("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=", Base64.DEFAULT))
var toast : Toast? = null
private fun Context.toast(msg: String) {
val biggerText = SpannableStringBuilder(msg)
biggerText.setSpan(RelativeSizeSpan(1.6f), 0, msg.length, 0)
val view: View = inflate(this, R.layout.simple_toast, null)
view.findViewById<TextView>(R.id.text).text = biggerText
if (toast==null) {
toast = Toast(this)
toast?.duration = Toast.LENGTH_SHORT
}
toast?.view = view
toast?.show()
}
private fun View.post(action: () -> Unit) = this.post(Runnable(action))
fun onPause() {
@@ -738,4 +776,18 @@ open class GeckoWeb @JvmOverloads constructor(
restoreSessionState()
session?.setActive(true)
}
// dp 변환 확장 함수
private fun Int.dpToPx(): Int = (this * context.resources.displayMetrics.density).toInt()
fun prev10() {
sendJsonMsg("SEEK_PREV")
}
fun next10() {
sendJsonMsg("SEEK_NEXT")
}
fun play_pause() {
sendJsonMsg("PLAY_PAUSE")
}
}
@@ -116,7 +116,7 @@ internal class RssHome : RemoteGestureFragment() , KeyEventHandler {
override fun onRemoteLeft(isDouble : Boolean) {
if (binding.lunaticBrowser.isVisible) {
doNextPage()
binding.lunaticBrowser.geckoWeb.goBack()
} else {
}
@@ -124,7 +124,7 @@ internal class RssHome : RemoteGestureFragment() , KeyEventHandler {
override fun onRemoteRight(isDouble : Boolean) {
if (binding.lunaticBrowser.isVisible) {
binding.lunaticBrowser.geckoWeb.goBack()
doNextPage()
} else {
}
@@ -1076,12 +1076,4 @@ internal class RssHome : RemoteGestureFragment() , KeyEventHandler {
}
fun randomOrNull() : RssData? = lasted.randomOrNull()
}
var toast: Toast? = null
fun Context.toast(string: String) {
if (toast == null) {
toast = Toast.makeText(this,string,Toast.LENGTH_SHORT)
}
toast?.setText(string)
toast?.show()
}
@@ -41,6 +41,7 @@ import java.util.Calendar
import com.google.common.util.concurrent.ListenableFuture
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import bums.lunatic.launcher.LunaticLauncher.Companion.toast
class SystemStatusFragment : Fragment() {
@@ -1,8 +1,10 @@
package bums.lunatic.launcher.home.tokiz
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.res.Configuration
import android.media.AudioManager
import android.net.Uri
import android.os.Bundle
import android.os.Handler
@@ -31,6 +33,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import bums.lunatic.launcher.LunaticLauncher.Companion.toast
import bums.lunatic.launcher.R
import bums.lunatic.launcher.common.RemoteGestureFragment
import bums.lunatic.launcher.databinding.BooktokiBinding
@@ -38,7 +41,6 @@ import bums.lunatic.launcher.home.GeckoWeb
import bums.lunatic.launcher.home.GeckoWeb.JxEvent
import bums.lunatic.launcher.home.KeyEventHandler
import bums.lunatic.launcher.home.NeoRssActivity
import bums.lunatic.launcher.home.toast
import bums.lunatic.launcher.home.tokiz.view.PagedTextLayout
import bums.lunatic.launcher.home.tokiz.view.PagedTextViewInterface
import bums.lunatic.launcher.utils.Blog
@@ -238,7 +240,12 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
}
override fun onRemoteCenterClick() {
super.onRemoteCenterClick()
if (contentsType.contains("youtube")) {
binding.lunaticBrowser.geckoWeb.play_pause()
binding.lunaticBrowser.geckoWeb.saveCurrentSessionState()
} else {
super.onRemoteCenterClick()
}
}
override fun onRemoteCenterDoubleClick() {
@@ -253,6 +260,11 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
} else if (contentsType.contains("comics")) {
if (contentsType == "comics") sendViewerTouch("right") else actionNextEvent()
}
else if (contentsType.contains("youtube")) {
binding.lunaticBrowser.geckoWeb.next10()
}
}
override fun onRemoteLeft(isDouble : Boolean) {
@@ -260,6 +272,8 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
actionPrevEvent(isDouble)
} else if (contentsType.contains("comics")) {
if (contentsType == "comics") sendViewerTouch("left") else actionNextEvent()
}else if (contentsType.contains("youtube")) {
binding.lunaticBrowser.geckoWeb.prev10()
}
}
@@ -267,12 +281,15 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
if (binding.pagedLayer.isVisible) {
} else {
if (binding.lunaticBrowser.geckoWeb.scrollState > 0) {
if (contentsType.contains("youtube")) {
binding.lunaticBrowser.geckoWeb.nextShorts()
} else {
binding.lunaticBrowser.geckoWeb.pageDown()
}
if (binding.lunaticBrowser.geckoWeb.scrollState > 0) {
} else {
binding.lunaticBrowser.geckoWeb.pageDown()
}
}
}
}
@@ -280,10 +297,14 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
if (binding.pagedLayer.isVisible) {
} else {
if (binding.lunaticBrowser.geckoWeb.scrollState < 0) {
if (contentsType.contains("youtube")) {
binding.lunaticBrowser.geckoWeb.prevShorts()
} else {
binding.lunaticBrowser.geckoWeb.pageUp()
if (binding.lunaticBrowser.geckoWeb.scrollState < 0) {
} else {
binding.lunaticBrowser.geckoWeb.pageUp()
}
}
}
}
@@ -526,13 +547,17 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
}
}
private var originalVolume: Int = -1
private val audioManager by lazy {
requireContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager
}
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
saveContinuation = false
if (hidden) {
// 💡 화면에서 사라질 때: 타이머 중지 및 애니메이션 중지
binding.lunaticBrowser.geckoWeb?.onPause()
// 일반 WebView라면: webView.onPause() 및 webView.pauseTimers()
} else {
// 💡 다시 나타날 때: 다시 시작
@@ -541,6 +566,8 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -551,7 +578,10 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
// 💡 1. Toki용 레이아웃 설정
binding.lunaticBrowser.setupForToki()
originalVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
// 미디어 볼륨을 0으로 설정 (FLAG_SHOW_UI를 0으로 주면 볼륨 바가 뜨지 않음)
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0)
// 💡 2. GeckoWeb 접근 및 설정
val geckoWeb = binding.lunaticBrowser.geckoWeb
@@ -740,7 +770,21 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
override fun onResume() {
super.onResume()
originalVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
if (contentsType.contains("youtube")) {
// 미디어 볼륨을 0으로 설정 (FLAG_SHOW_UI를 0으로 주면 볼륨 바가 뜨지 않음)
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0)
}
Blog.LOGE("RssHome 활성화: 미디어 볼륨 0 설정 (이전 볼륨: $originalVolume)")
}
override fun onPause() {
super.onPause()
if (originalVolume != -1 && contentsType.contains("youtube")) {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, originalVolume, 0)
Blog.LOGE("RssHome 비활성화: 미디어 볼륨 복구 ($originalVolume)")
}
}
fun getLastinfo() : LastInfo? {
@@ -1013,21 +1057,7 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
fun showToast(origin: String) {
activity?.runOnUiThread {
val toast = Toast(requireContext())
toast.duration = Toast.LENGTH_SHORT
val biggerText = SpannableStringBuilder(origin)
biggerText.setSpan(RelativeSizeSpan(1.6f), 0, origin.length, 0)
val view: View = inflate(requireContext(), R.layout.simple_toast, null)
view.findViewById<TextView>(R.id.text).text = biggerText
toast.view = view
toast.show()
// Toast.makeText(
// baseContext,
// biggerText,
// Toast.LENGTH_SHORT
// ).show()
}
activity?.toast(origin)
}
var delayed = 3500L + Math.abs(Random.nextLong().rem(9999L))
@@ -27,7 +27,7 @@ import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.*
import androidx.annotation.RequiresApi
import bums.lunatic.launcher.home.toast
import bums.lunatic.launcher.LunaticLauncher.Companion.toast
import bums.lunatic.launcher.utils.Blog
import com.frostwire.jlibtorrent.swig.error_code
import com.frostwire.jlibtorrent.swig.libtorrent