...
This commit is contained in:
parent
9aee32e42d
commit
112012ce0c
@ -55,22 +55,203 @@ port.onMessage.addListener(response => {
|
|||||||
var type= response["type"];
|
var type= response["type"];
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "CLICK_PREV_CHAPTER" : {
|
case "SEEK_NEXT": // 5초 앞으로
|
||||||
const links = document.querySelectorAll("a");
|
{
|
||||||
let found = false;
|
let btn =
|
||||||
for (let link of links) {
|
document.querySelector('button[aria-label="10초 빨리 감기"]') ||
|
||||||
if (link.textContent.includes("이전화 보기")) {
|
document.querySelector('button[aria-label="뒤로 10초"]') ||
|
||||||
link.click();
|
document.querySelector('.ytp-right-controls .ytp-button[aria-label*="뒤로"]');
|
||||||
found = true;
|
|
||||||
break;
|
if (btn) {
|
||||||
}
|
btn.click();
|
||||||
}
|
return;
|
||||||
if (!found) {
|
|
||||||
port.postMessage({ type: "MSG", msg: "이전화 버튼을 찾을 수 없습니다." });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case "CLICK_NEXT_CHAPTER" : {
|
}
|
||||||
|
break;
|
||||||
|
case "PLAY_PAUSE": // 5초 뒤로
|
||||||
|
{
|
||||||
|
if (document.location.href.search("youtube") > -1) {
|
||||||
|
let btn =
|
||||||
|
document.querySelector('button[aria-label="동영상 재생"]') ||
|
||||||
|
document.querySelector('button[aria-label="동영상 일시중지"]') ;
|
||||||
|
|
||||||
|
if (btn) {
|
||||||
|
btn.click();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case "SEEK_PREV": // 5초 뒤로
|
||||||
|
{
|
||||||
|
if (document.location.href.search("youtube") > -1) {
|
||||||
|
let btn =
|
||||||
|
document.querySelector('button[aria-label="10초 되감기"]') ||
|
||||||
|
document.querySelector('button[aria-label="앞으로 10초"]') ||
|
||||||
|
document.querySelector('.ytp-right-controls .ytp-button[aria-label*="앞으로"]');
|
||||||
|
|
||||||
|
if (btn) {
|
||||||
|
btn.click();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case "PREV_SHORTS": {
|
||||||
|
if (document.location.href.search("shorts") > -1) {
|
||||||
|
// 1. 유튜브 쇼츠의 스크롤 컨테이너들 후보 (버전에 따라 다름)
|
||||||
|
const container = document.getElementById('shorts-container') ||
|
||||||
|
document.querySelector('ytd-shorts') ||
|
||||||
|
document.querySelector('#items.ytd-vertical-list-renderer');
|
||||||
|
|
||||||
|
if (container) {
|
||||||
|
// 컨테이너 내부에서 현재 뷰포트 높이만큼 스크롤
|
||||||
|
container.scrollBy({
|
||||||
|
top: window.innerHeight * -1,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 컨테이너를 못 찾을 경우, 키보드 'J'나 'ArrowDown'을 시뮬레이션하는 게 가장 정확합니다.
|
||||||
|
const event = new KeyboardEvent('keydown', {
|
||||||
|
key: 'ArrowUp',
|
||||||
|
keyCode: 40,
|
||||||
|
code: 'ArrowUp',
|
||||||
|
which: 40,
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
let btn = document.querySelector('.ytp-prev-button');
|
||||||
|
|
||||||
|
if (!btn) {
|
||||||
|
btn = document.querySelector('button[aria-label="이전 동영상"], button[aria-label="이전"]');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!btn) {
|
||||||
|
btn = Array.from(document.querySelectorAll('[aria-label]'))
|
||||||
|
.find(el => /이전/.test(el.getAttribute('aria-label')));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btn) {
|
||||||
|
btn.click();
|
||||||
|
} else {
|
||||||
|
console.log('이전 영상 버튼을 찾지 못했습니다.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "NEXT_SHORTS": {
|
||||||
|
if (document.location.href.search("shorts") > -1) {
|
||||||
|
// 1. 유튜브 쇼츠의 스크롤 컨테이너들 후보 (버전에 따라 다름)
|
||||||
|
const container = document.getElementById('shorts-container') ||
|
||||||
|
document.querySelector('ytd-shorts') ||
|
||||||
|
document.querySelector('#items.ytd-vertical-list-renderer');
|
||||||
|
|
||||||
|
if (container) {
|
||||||
|
// 컨테이너 내부에서 현재 뷰포트 높이만큼 스크롤
|
||||||
|
container.scrollBy({
|
||||||
|
top: window.innerHeight,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 컨테이너를 못 찾을 경우, 키보드 'J'나 'ArrowDown'을 시뮬레이션하는 게 가장 정확합니다.
|
||||||
|
const event = new KeyboardEvent('keydown', {
|
||||||
|
key: 'ArrowDown',
|
||||||
|
keyCode: 40,
|
||||||
|
code: 'ArrowDown',
|
||||||
|
which: 40,
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 1) 예전/기본 플레이어용 클래스
|
||||||
|
let btn = document.querySelector('.ytp-next-button');
|
||||||
|
|
||||||
|
// 2) aria-label 기반 (언어별로 텍스트 다를 수 있음)
|
||||||
|
if (!btn) {
|
||||||
|
btn = document.querySelector('button[aria-label="다음 동영상"], button[aria-label="다음"]');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) 혹시 아이콘 버튼이 다른 태그일 수도 있으니 좀 더 느슨하게
|
||||||
|
if (!btn) {
|
||||||
|
btn = Array.from(document.querySelectorAll('[aria-label]'))
|
||||||
|
.find(el => /다음/.test(el.getAttribute('aria-label')));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btn) {
|
||||||
|
btn.click();
|
||||||
|
} else {
|
||||||
|
console.log('다음 영상 버튼을 찾지 못했습니다.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "CLICK_PREV_CHAPTER" : {
|
||||||
|
const links = document.querySelectorAll("a");
|
||||||
|
let found = false;
|
||||||
|
for (let link of links) {
|
||||||
|
if (link.textContent.includes("이전화 보기")) {
|
||||||
|
link.click();
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
port.postMessage({ type: "MSG", msg: "이전화 버튼을 찾을 수 없습니다." });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "MARKER": {
|
||||||
|
const isDown = response["isDown"];
|
||||||
|
const scrollRatio = 0.6; // 이동 비율 (30%)
|
||||||
|
const viewportHeight = window.innerHeight;
|
||||||
|
const distance = viewportHeight * scrollRatio;
|
||||||
|
const startY = window.scrollY;
|
||||||
|
|
||||||
|
const id = 'scroll-ghost-layer';
|
||||||
|
let ghost = document.getElementById(id);
|
||||||
|
if (ghost) ghost.remove();
|
||||||
|
|
||||||
|
ghost = document.createElement('div');
|
||||||
|
ghost.id = id;
|
||||||
|
|
||||||
|
// 💡 isDown에 따라 그라데이션 방향과 보더 위치를 반전
|
||||||
|
const gradDir = isDown ? 'to top' : 'to bottom';
|
||||||
|
const borderStyle = isDown ? 'border-top: 3px solid rgba(0,122,255,0.4);' : 'border-bottom: 3px solid rgba(0,122,255,0.3);';
|
||||||
|
|
||||||
|
ghost.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
top: ${startY}px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: ${viewportHeight}px;
|
||||||
|
background: linear-gradient(${gradDir}, rgba(0,122,255,0.5), transparent);
|
||||||
|
${borderStyle}
|
||||||
|
z-index: 2147483647;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.8s ease-out;
|
||||||
|
opacity: 1;
|
||||||
|
`;
|
||||||
|
document.body.appendChild(ghost);
|
||||||
|
|
||||||
|
// 실제 스크롤 수행
|
||||||
|
const targetY = isDown ? startY + distance : startY - distance;
|
||||||
|
window.scrollTo({
|
||||||
|
top: targetY,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 레이어 제거
|
||||||
|
setTimeout(() => {
|
||||||
|
ghost.style.opacity = '0';
|
||||||
|
setTimeout(() => ghost.remove(), 800);
|
||||||
|
}, 1000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "CLICK_NEXT_CHAPTER" : {
|
||||||
const links = document.querySelectorAll("a");
|
const links = document.querySelectorAll("a");
|
||||||
let found = false;
|
let found = false;
|
||||||
for (let link of links) {
|
for (let link of links) {
|
||||||
@ -83,17 +264,17 @@ port.onMessage.addListener(response => {
|
|||||||
if (!found) {
|
if (!found) {
|
||||||
port.postMessage({ type: "MSG", msg: "다음화 버튼을 찾을 수 없습니다." });
|
port.postMessage({ type: "MSG", msg: "다음화 버튼을 찾을 수 없습니다." });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "fetchAllImages": {
|
case "fetchAllImages": {
|
||||||
const targetSrc = response["targetSrc"];
|
const targetSrc = response["targetSrc"];
|
||||||
const imageUrls = findAllRelatedImages(targetSrc);
|
const imageUrls = findAllRelatedImages(targetSrc);
|
||||||
// 찾은 이미지 URL 목록을 'allImagesFound' 타입으로 네이티브 앱에 다시 전송
|
// 찾은 이미지 URL 목록을 'allImagesFound' 타입으로 네이티브 앱에 다시 전송
|
||||||
sendMessage({
|
sendMessage({
|
||||||
type: "allImagesFound",
|
type: "allImagesFound",
|
||||||
urls: imageUrls
|
urls: imageUrls
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "search" : {
|
case "search" : {
|
||||||
var keyword = response["keyword"];
|
var keyword = response["keyword"];
|
||||||
@ -131,7 +312,7 @@ port.onMessage.addListener(response => {
|
|||||||
const elements = document.querySelectorAll(".main-content"); // 또는 getElementsByClassName("item")
|
const elements = document.querySelectorAll(".main-content"); // 또는 getElementsByClassName("item")
|
||||||
|
|
||||||
const matched = Array.from(elements).filter(el =>
|
const matched = Array.from(elements).filter(el =>
|
||||||
el.textContent.includes(keyword) // 대소문자 구분
|
el.textContent.includes(keyword) // 대소문자 구분
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -284,15 +465,15 @@ if(document.querySelector("#html_encoder_div")) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
function removeSpecificGifs() {
|
function removeSpecificGifs() {
|
||||||
const images = document.getElementsByTagName('img');
|
const images = document.getElementsByTagName('img');
|
||||||
for (let i = images.length - 1; i >= 0; i--) {
|
for (let i = images.length - 1; i >= 0; i--) {
|
||||||
const src = images[i].src;
|
const src = images[i].src;
|
||||||
// 요청하신 특정 도메인과 gif 패턴, 쿼리 파라미터를 체크
|
// 요청하신 특정 도메인과 gif 패턴, 쿼리 파라미터를 체크
|
||||||
if (src.includes('tokinbtoki') && src.includes('.gif') && src.includes('_=')) {
|
if (src.includes('tokinbtoki') && src.includes('.gif') && src.includes('_=')) {
|
||||||
images[i].parentNode.removeChild(images[i]);
|
images[i].parentNode.removeChild(images[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getList(children) {
|
function getList(children) {
|
||||||
// port.postMessage("Start of getList!" + children);
|
// port.postMessage("Start of getList!" + children);
|
||||||
@ -395,7 +576,7 @@ 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() {
|
function hideBook() {
|
||||||
@ -492,7 +673,7 @@ function scrollToLazyImg(fastMode) {
|
|||||||
// 한 번에 이동할 픽셀
|
// 한 번에 이동할 픽셀
|
||||||
const step = fastMode ? 600 : 200;
|
const step = fastMode ? 600 : 200;
|
||||||
// 반복 간격(ms) (느릴수록 로딩에 더 여유 생김)
|
// 반복 간격(ms) (느릴수록 로딩에 더 여유 생김)
|
||||||
const delay = fastMode ? 200 : 600;
|
const delay = fastMode ? 300 : 500;
|
||||||
// 스크롤 현재 위치 추적
|
// 스크롤 현재 위치 추적
|
||||||
let currentY = window.scrollY;
|
let currentY = window.scrollY;
|
||||||
let maxY = Math.max(
|
let maxY = Math.max(
|
||||||
@ -521,7 +702,7 @@ function scrollToLazyImg(fastMode) {
|
|||||||
// 직접 메시지 보내거나, 원하는 최종 동작 실행
|
// 직접 메시지 보내거나, 원하는 최종 동작 실행
|
||||||
// 예: window.postMessage('saveToObsidian', '*');
|
// 예: window.postMessage('saveToObsidian', '*');
|
||||||
}
|
}
|
||||||
}, 800);
|
}, delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,7 +736,7 @@ function gotoNext() {
|
|||||||
var targetElement = null;
|
var targetElement = null;
|
||||||
|
|
||||||
document.querySelectorAll('.btn-group')?.forEach((el) => {
|
document.querySelectorAll('.btn-group')?.forEach((el) => {
|
||||||
var pageLinks =el?.querySelectorAll('a');
|
var pageLinks =el?.querySelectorAll('a');
|
||||||
|
|
||||||
if (pageLinks) {
|
if (pageLinks) {
|
||||||
pageLinks.forEach(function(link) {
|
pageLinks.forEach(function(link) {
|
||||||
|
|||||||
@ -20,7 +20,14 @@ package bums.lunatic.launcher
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.ComponentCallbacks2
|
import android.content.ComponentCallbacks2
|
||||||
|
import android.content.Context
|
||||||
import android.database.sqlite.SQLiteDatabase
|
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.HourlyLogWriter
|
||||||
import bums.lunatic.launcher.helpers.PrefHelper
|
import bums.lunatic.launcher.helpers.PrefHelper
|
||||||
import bums.lunatic.launcher.home.Base64ImageCache
|
import bums.lunatic.launcher.home.Base64ImageCache
|
||||||
@ -39,6 +46,7 @@ import java.io.File
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal class LunaticLauncher : Application() {
|
internal class LunaticLauncher : Application() {
|
||||||
companion object {
|
companion object {
|
||||||
var appContext : LunaticLauncher? = null
|
var appContext : LunaticLauncher? = null
|
||||||
@ -49,6 +57,21 @@ internal class LunaticLauncher : Application() {
|
|||||||
return sRuntime
|
return sRuntime
|
||||||
}
|
}
|
||||||
var privateCompletedDir : File? = null
|
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() {
|
private fun initGeckoRuntime() {
|
||||||
|
|||||||
@ -170,7 +170,7 @@ class ForeGroundService : Service() {
|
|||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
if (value == null) {
|
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()
|
currentProcessId = UUID.randomUUID().toString()
|
||||||
YoutubeDL.getInstance()
|
YoutubeDL.getInstance()
|
||||||
.execute(command, currentProcessId) { progress, est, str ->
|
.execute(command, currentProcessId) { progress, est, str ->
|
||||||
startForeGround(100, progress.toInt(),str, true)
|
startForeGround(100, progress.toInt(),str, false)
|
||||||
if (progress >= 100) {
|
if (progress >= 100) {
|
||||||
targetUrls.remove(url)
|
targetUrls.remove(url)
|
||||||
currentProcessId = null
|
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"
|
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
|
||||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
|
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.GradientDrawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.text.SpannableStringBuilder
|
import android.text.SpannableStringBuilder
|
||||||
@ -30,6 +32,7 @@ import androidx.core.net.toUri
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import bums.lunatic.launcher.BookmarkUploader
|
import bums.lunatic.launcher.BookmarkUploader
|
||||||
import bums.lunatic.launcher.LunaticLauncher.Companion.getRuntime
|
import bums.lunatic.launcher.LunaticLauncher.Companion.getRuntime
|
||||||
|
import bums.lunatic.launcher.LunaticLauncher.Companion.toast
|
||||||
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
|
||||||
@ -306,6 +309,16 @@ open class GeckoWeb @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun nextShorts() {
|
||||||
|
|
||||||
|
sendJsonMsg("NEXT_SHORTS")
|
||||||
|
saveCurrentSessionState()
|
||||||
|
}
|
||||||
|
fun prevShorts() {
|
||||||
|
|
||||||
|
sendJsonMsg("PREV_SHORTS")
|
||||||
|
saveCurrentSessionState()
|
||||||
|
}
|
||||||
|
|
||||||
// [Navigation Delegate]
|
// [Navigation Delegate]
|
||||||
private val navigationDelegate = object : GeckoSession.NavigationDelegate {
|
private val navigationDelegate = object : GeckoSession.NavigationDelegate {
|
||||||
@ -605,25 +618,62 @@ open class GeckoWeb @JvmOverloads constructor(
|
|||||||
var HH = 0.3
|
var HH = 0.3
|
||||||
fun pageDown() {
|
fun pageDown() {
|
||||||
val session = this.session ?: return
|
val session = this.session ?: return
|
||||||
val pzc = session.panZoomController
|
sendJsonMsg("MARKER",Pair<String, Any?>("isDown",true))
|
||||||
|
// val pzc = session.panZoomController
|
||||||
// 💡 현재 눈에 보이는 GeckoView의 높이를 가져옵니다.
|
//
|
||||||
val viewHeight = this.height.toDouble().times(HH)
|
// // 💡 현재 눈에 보이는 GeckoView의 높이를 가져옵니다.
|
||||||
|
// val viewHeight = this.height.toDouble().times(HH)
|
||||||
// 세로 방향(y)으로 뷰 높이만큼 아래로 스크롤 (픽셀 단위)
|
//
|
||||||
// 세 번째 인자는 애니메이션 여부입니다.
|
// // 세로 방향(y)으로 뷰 높이만큼 아래로 스크롤 (픽셀 단위)
|
||||||
pzc.scrollBy(ScreenLength.fromPixels(0.0), ScreenLength.fromPixels(viewHeight),
|
// // 세 번째 인자는 애니메이션 여부입니다.
|
||||||
PanZoomController.SCROLL_BEHAVIOR_SMOOTH)
|
// pzc.scrollBy(ScreenLength.fromPixels(0.0), ScreenLength.fromPixels(viewHeight),
|
||||||
|
// PanZoomController.SCROLL_BEHAVIOR_SMOOTH)
|
||||||
|
//
|
||||||
|
// showGuideLine((this.height - viewHeight).toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pageUp() {
|
fun pageUp() {
|
||||||
val session = this.session ?: return
|
val session = this.session ?: return
|
||||||
val pzc = session.panZoomController
|
sendJsonMsg("MARKER",Pair<String, Any?>("isDown",false))
|
||||||
val viewHeight = this.height.toDouble().times(HH)
|
// 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())
|
||||||
|
}
|
||||||
|
|
||||||
// 위로 스크롤
|
private val guideView: View by lazy {
|
||||||
pzc.scrollBy(ScreenLength.fromPixels(0.0), ScreenLength.fromPixels(-viewHeight),
|
View(context).apply {
|
||||||
PanZoomController.SCROLL_BEHAVIOR_SMOOTH)
|
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
|
// File/Download Helpers
|
||||||
@ -712,19 +762,7 @@ open class GeckoWeb @JvmOverloads constructor(
|
|||||||
|
|
||||||
private fun getFilterF() = String(Base64.decode("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=", Base64.DEFAULT))
|
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))
|
private fun View.post(action: () -> Unit) = this.post(Runnable(action))
|
||||||
fun onPause() {
|
fun onPause() {
|
||||||
@ -738,4 +776,18 @@ open class GeckoWeb @JvmOverloads constructor(
|
|||||||
restoreSessionState()
|
restoreSessionState()
|
||||||
session?.setActive(true)
|
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) {
|
override fun onRemoteLeft(isDouble : Boolean) {
|
||||||
if (binding.lunaticBrowser.isVisible) {
|
if (binding.lunaticBrowser.isVisible) {
|
||||||
doNextPage()
|
binding.lunaticBrowser.geckoWeb.goBack()
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -124,7 +124,7 @@ internal class RssHome : RemoteGestureFragment() , KeyEventHandler {
|
|||||||
|
|
||||||
override fun onRemoteRight(isDouble : Boolean) {
|
override fun onRemoteRight(isDouble : Boolean) {
|
||||||
if (binding.lunaticBrowser.isVisible) {
|
if (binding.lunaticBrowser.isVisible) {
|
||||||
binding.lunaticBrowser.geckoWeb.goBack()
|
doNextPage()
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1077,11 +1077,3 @@ internal class RssHome : RemoteGestureFragment() , KeyEventHandler {
|
|||||||
fun randomOrNull() : RssData? = lasted.randomOrNull()
|
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 com.google.common.util.concurrent.ListenableFuture
|
||||||
import androidx.camera.lifecycle.ProcessCameraProvider
|
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import bums.lunatic.launcher.LunaticLauncher.Companion.toast
|
||||||
|
|
||||||
class SystemStatusFragment : Fragment() {
|
class SystemStatusFragment : Fragment() {
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
package bums.lunatic.launcher.home.tokiz
|
package bums.lunatic.launcher.home.tokiz
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
import android.media.AudioManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
@ -31,6 +33,7 @@ import androidx.appcompat.app.AlertDialog
|
|||||||
import androidx.core.net.toUri
|
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.LunaticLauncher.Companion.toast
|
||||||
import bums.lunatic.launcher.R
|
import bums.lunatic.launcher.R
|
||||||
import bums.lunatic.launcher.common.RemoteGestureFragment
|
import bums.lunatic.launcher.common.RemoteGestureFragment
|
||||||
import bums.lunatic.launcher.databinding.BooktokiBinding
|
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.GeckoWeb.JxEvent
|
||||||
import bums.lunatic.launcher.home.KeyEventHandler
|
import bums.lunatic.launcher.home.KeyEventHandler
|
||||||
import bums.lunatic.launcher.home.NeoRssActivity
|
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.PagedTextLayout
|
||||||
import bums.lunatic.launcher.home.tokiz.view.PagedTextViewInterface
|
import bums.lunatic.launcher.home.tokiz.view.PagedTextViewInterface
|
||||||
import bums.lunatic.launcher.utils.Blog
|
import bums.lunatic.launcher.utils.Blog
|
||||||
@ -238,7 +240,12 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onRemoteCenterClick() {
|
override fun onRemoteCenterClick() {
|
||||||
super.onRemoteCenterClick()
|
if (contentsType.contains("youtube")) {
|
||||||
|
binding.lunaticBrowser.geckoWeb.play_pause()
|
||||||
|
binding.lunaticBrowser.geckoWeb.saveCurrentSessionState()
|
||||||
|
} else {
|
||||||
|
super.onRemoteCenterClick()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRemoteCenterDoubleClick() {
|
override fun onRemoteCenterDoubleClick() {
|
||||||
@ -253,6 +260,11 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
|
|||||||
} else if (contentsType.contains("comics")) {
|
} else if (contentsType.contains("comics")) {
|
||||||
if (contentsType == "comics") sendViewerTouch("right") else actionNextEvent()
|
if (contentsType == "comics") sendViewerTouch("right") else actionNextEvent()
|
||||||
}
|
}
|
||||||
|
else if (contentsType.contains("youtube")) {
|
||||||
|
binding.lunaticBrowser.geckoWeb.next10()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRemoteLeft(isDouble : Boolean) {
|
override fun onRemoteLeft(isDouble : Boolean) {
|
||||||
@ -260,6 +272,8 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
|
|||||||
actionPrevEvent(isDouble)
|
actionPrevEvent(isDouble)
|
||||||
} else if (contentsType.contains("comics")) {
|
} else if (contentsType.contains("comics")) {
|
||||||
if (contentsType == "comics") sendViewerTouch("left") else actionNextEvent()
|
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) {
|
if (binding.pagedLayer.isVisible) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (binding.lunaticBrowser.geckoWeb.scrollState > 0) {
|
if (contentsType.contains("youtube")) {
|
||||||
|
binding.lunaticBrowser.geckoWeb.nextShorts()
|
||||||
} else {
|
} 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) {
|
if (binding.pagedLayer.isVisible) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (binding.lunaticBrowser.geckoWeb.scrollState < 0) {
|
if (contentsType.contains("youtube")) {
|
||||||
|
binding.lunaticBrowser.geckoWeb.prevShorts()
|
||||||
} else {
|
} 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) {
|
override fun onHiddenChanged(hidden: Boolean) {
|
||||||
super.onHiddenChanged(hidden)
|
super.onHiddenChanged(hidden)
|
||||||
saveContinuation = false
|
saveContinuation = false
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
// 💡 화면에서 사라질 때: 타이머 중지 및 애니메이션 중지
|
// 💡 화면에서 사라질 때: 타이머 중지 및 애니메이션 중지
|
||||||
binding.lunaticBrowser.geckoWeb?.onPause()
|
binding.lunaticBrowser.geckoWeb?.onPause()
|
||||||
|
|
||||||
// 일반 WebView라면: webView.onPause() 및 webView.pauseTimers()
|
// 일반 WebView라면: webView.onPause() 및 webView.pauseTimers()
|
||||||
} else {
|
} else {
|
||||||
// 💡 다시 나타날 때: 다시 시작
|
// 💡 다시 나타날 때: 다시 시작
|
||||||
@ -541,6 +566,8 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
@ -551,7 +578,10 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
|
|||||||
|
|
||||||
// 💡 1. Toki용 레이아웃 설정
|
// 💡 1. Toki용 레이아웃 설정
|
||||||
binding.lunaticBrowser.setupForToki()
|
binding.lunaticBrowser.setupForToki()
|
||||||
|
originalVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||||
|
|
||||||
|
// 미디어 볼륨을 0으로 설정 (FLAG_SHOW_UI를 0으로 주면 볼륨 바가 뜨지 않음)
|
||||||
|
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0)
|
||||||
// 💡 2. GeckoWeb 접근 및 설정
|
// 💡 2. GeckoWeb 접근 및 설정
|
||||||
val geckoWeb = binding.lunaticBrowser.geckoWeb
|
val geckoWeb = binding.lunaticBrowser.geckoWeb
|
||||||
|
|
||||||
@ -740,7 +770,21 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.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? {
|
fun getLastinfo() : LastInfo? {
|
||||||
@ -1013,21 +1057,7 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
|
|||||||
|
|
||||||
|
|
||||||
fun showToast(origin: String) {
|
fun showToast(origin: String) {
|
||||||
activity?.runOnUiThread {
|
activity?.toast(origin)
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var delayed = 3500L + Math.abs(Random.nextLong().rem(9999L))
|
var delayed = 3500L + Math.abs(Random.nextLong().rem(9999L))
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import android.net.NetworkCapabilities
|
|||||||
import android.net.NetworkRequest
|
import android.net.NetworkRequest
|
||||||
import android.os.*
|
import android.os.*
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import bums.lunatic.launcher.home.toast
|
import bums.lunatic.launcher.LunaticLauncher.Companion.toast
|
||||||
import bums.lunatic.launcher.utils.Blog
|
import bums.lunatic.launcher.utils.Blog
|
||||||
import com.frostwire.jlibtorrent.swig.error_code
|
import com.frostwire.jlibtorrent.swig.error_code
|
||||||
import com.frostwire.jlibtorrent.swig.libtorrent
|
import com.frostwire.jlibtorrent.swig.libtorrent
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user