This commit is contained in:
lunaticbum 2025-07-27 19:15:12 +09:00
parent ee7cee7638
commit 867ee66499
7 changed files with 181 additions and 58 deletions

View File

@ -423,7 +423,8 @@ function gotoNext() {
if(e.hasAttribute("href") && if(e.hasAttribute("href") &&
( (
(e.getAttribute("href").search("page=2") > -1 && location.href.search("page") < 0) || (e.getAttribute("href").search("page=2") > -1 && location.href.search("page") < 0) ||
(e.getAttribute("href").search("page=3") > -1 && location.href.search("page=2") > 0) (e.getAttribute("href").search("page=3") > -1 && location.href.search("page=2") > 0) ||
(e.getAttribute("href").search("page=4") > -1 && location.href.search("page=3") > 0)
)) { )) {
targetElement = e targetElement = e
@ -432,9 +433,9 @@ function gotoNext() {
if(targetElement !== null) { if(targetElement !== null) {
targetElement.click() targetElement.click()
} else { } else {
location.href = "https://naver.com" // location.href = "https://naver.com"
} }
}, 5000); }, 15000);
} }
} catch (e) { } catch (e) {

View File

@ -582,6 +582,7 @@ internal class LauncherActivity : CommonActivity() {
@SuppressLint("NewApi", "MissingPermission") @SuppressLint("NewApi", "MissingPermission")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen() installSplashScreen()
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
lActivity = this lActivity = this
mWorkManager = WorkManager.getInstance(this) mWorkManager = WorkManager.getInstance(this)
DynamicColors.applyToActivityIfAvailable(this) DynamicColors.applyToActivityIfAvailable(this)

View File

@ -2,6 +2,7 @@ package bums.lunatic.launcher.home
import android.app.DownloadManager import android.app.DownloadManager
import android.content.Context import android.content.Context
import android.content.DialogInterface
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
@ -23,12 +24,17 @@ import android.view.KeyEvent.KEYCODE_BUTTON_X
import android.view.KeyEvent.KEYCODE_BUTTON_Y import android.view.KeyEvent.KEYCODE_BUTTON_Y
import android.view.KeyEvent.KEYCODE_DPAD_DOWN import android.view.KeyEvent.KEYCODE_DPAD_DOWN
import android.view.KeyEvent.KEYCODE_DPAD_UP import android.view.KeyEvent.KEYCODE_DPAD_UP
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.EditText
import android.widget.ProgressBar import android.widget.ProgressBar
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible import androidx.core.view.isVisible
import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime
import bums.lunatic.launcher.R
import bums.lunatic.launcher.tokiz.data.HistoryManager import bums.lunatic.launcher.tokiz.data.HistoryManager
import bums.lunatic.launcher.tokiz.data.model.History import bums.lunatic.launcher.tokiz.data.model.History
import bums.lunatic.launcher.tokiz.data.model.PortMessage import bums.lunatic.launcher.tokiz.data.model.PortMessage
@ -397,12 +403,30 @@ class GeckoWeb : BWebview {
if(it.host?.let { it1 -> lastedUrl?.contains(it1, true) } == true) { if(it.host?.let { it1 -> lastedUrl?.contains(it1, true) } == true) {
loadUrl(uri) loadUrl(uri)
} else { } else {
context.startActivity(Intent().apply { val builder: AlertDialog.Builder = AlertDialog.Builder(context)
action = Intent.ACTION_VIEW builder.setTitle("Move To")
flags = Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS.or(FLAG_ACTIVITY_CLEAR_TOP).or( val viewInflated: View = LayoutInflater.from(context)
FLAG_ACTIVITY_NEW_TASK) .inflate(R.layout.text_inpu_password, null, false)
data = it val input = viewInflated.findViewById<View>(R.id.input) as EditText
}) input.visibility = View.GONE
builder.setView(viewInflated)
builder.setPositiveButton(
android.R.string.ok,
DialogInterface.OnClickListener { dialog, which ->
dialog.dismiss()
context.startActivity(Intent().apply {
action = Intent.ACTION_VIEW
flags = Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS.or(FLAG_ACTIVITY_CLEAR_TOP).or(
FLAG_ACTIVITY_NEW_TASK)
data = it
})
})
builder.setNegativeButton(
android.R.string.cancel,
DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
builder.show()
} }
} }
return super.onNewSession(session, uri) return super.onNewSession(session, uri)
@ -469,16 +493,9 @@ class GeckoWeb : BWebview {
"SHOWVIEWER" -> { "SHOWVIEWER" -> {
} }
"PRIVATES"->{ "PRIVATES"->{
lPortMessage.privates?.forEach { lPortMessage.privates?.let {
Blog.LOGE("Item screenshots >>> ${it.getScreen()}") context.toast("Received Msg privates form ${lPortMessage.currentPage} data => ${it?.size ?: 0}")
it.pubDate = afterDay(it.pubDate) WorkersDb.insertBulkData(it)
// WorkersDb.insertData(it)
getRealm().apply {
this.writeBlocking {
copyToRealm(it, UpdatePolicy.ALL)
}
}
context.toast("Received Msg privates form ${lPortMessage.currentPage} data => ${lPortMessage.privates?.size ?: 0}")
} }
} }
"Cookies"->{ "Cookies"->{

View File

@ -24,7 +24,6 @@ import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@ -40,7 +39,6 @@ import android.widget.Toast
import androidx.annotation.NonNull import androidx.annotation.NonNull
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.databinding.BindingAdapter
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
@ -65,17 +63,13 @@ import bums.lunatic.launcher.utils.SimpleFingerGestures
import bums.lunatic.launcher.utils.beforeDay import bums.lunatic.launcher.utils.beforeDay
import bums.lunatic.launcher.utils.beforeOneDay import bums.lunatic.launcher.utils.beforeOneDay
import bums.lunatic.launcher.workers.WorkersDb import bums.lunatic.launcher.workers.WorkersDb
import bums.lunatic.launcher.workers.WorkersDb.prvClear import bums.lunatic.launcher.workers.WorkersDb.getRealm
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.google.android.material.imageview.ShapeableImageView import com.google.android.material.imageview.ShapeableImageView
import com.google.gson.Gson import com.google.gson.Gson
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import io.realm.kotlin.UpdatePolicy import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query import io.realm.kotlin.ext.query
import io.realm.kotlin.notifications.InitialResults
import io.realm.kotlin.notifications.ResultsChange import io.realm.kotlin.notifications.ResultsChange
import io.realm.kotlin.notifications.UpdatedResults
import io.realm.kotlin.query.RealmQuery import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.RealmResults import io.realm.kotlin.query.RealmResults
import io.realm.kotlin.query.Sort import io.realm.kotlin.query.Sort
@ -85,7 +79,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import kotlin.time.TimeSource
internal class RssHome : Fragment() { internal class RssHome : Fragment() {
@ -233,7 +226,7 @@ internal class RssHome : Fragment() {
when (rss.category()) { when (rss.category()) {
RssDataType.REDDIT_NSFW, RssDataType.PRIVATE -> { RssDataType.REDDIT_NSFW, RssDataType.PRIVATE -> {
v.findViewById<ShapeableImageView>(R.id.circle_preview)?.let { v.findViewById<ShapeableImageView>(R.id.circle_preview)?.let {
if (RssDataType.PRIVATE.equals(rss.category()) && imageView) { if (RssDataType.PRIVATE.equals(rss.category())) {
openGecko(rssData = rss) openGecko(rssData = rss)
} else { } else {
if (it.visibility == View.GONE) { if (it.visibility == View.GONE) {
@ -250,7 +243,7 @@ internal class RssHome : Fragment() {
data = Uri.parse(rss.originPage) data = Uri.parse(rss.originPage)
}) })
} else { } else {
openGecko(rss.originPage()) openGecko(rss)
} }
} }
} }
@ -262,7 +255,7 @@ internal class RssHome : Fragment() {
} }
RssDataType.DOTAX -> { RssDataType.DOTAX -> {
openGecko(rss.originPage()) openGecko(rss)
} }
RssDataType.YOUTUBE -> { RssDataType.YOUTUBE -> {
@ -270,15 +263,43 @@ internal class RssHome : Fragment() {
} }
RssDataType.CLIEN -> { RssDataType.CLIEN -> {
openGecko(rss.originPage()) openGecko(rss)
} }
else -> { else -> {
openGecko(rss.originPage()) openGecko(rss)
} }
} }
} }
} }
fun searchKeyword() {
val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
builder.setTitle("Keyword")
val viewInflated: View = LayoutInflater.from(requireContext())
.inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
val input = viewInflated.findViewById<View>(R.id.input) as EditText
val privateMode = viewInflated.findViewById<CheckBox>(R.id.parivate_mode) as CheckBox
privateMode.setOnCheckedChangeListener { v,c->
binding.geckoWeb.privateMode = c
}
privateMode.visibility = View.GONE
binding.geckoWeb.privateMode = true
builder.setView(viewInflated)
builder.setPositiveButton(
android.R.string.ok,
DialogInterface.OnClickListener { dialog, which ->
dialog.dismiss()
var command = input.editableText?.toString()
if (command?.length ?: 0 > 0) {
queryInfos(keywords = command!!.split(" ")!!)
}
})
builder.setNegativeButton(
android.R.string.cancel,
DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
builder.show()
}
fun ask() { fun ask() {
@ -317,26 +338,28 @@ internal class RssHome : Fragment() {
@SuppressLint("SimpleDateFormat") @SuppressLint("SimpleDateFormat")
fun openGecko(originPage: String? = null, rssData: RssData? = null) { fun openGecko(rssData: RssData? = null) {
if (!imageView) { binding.layoutRssSummary.root.visibility = View.GONE
originPage?.let { if (rssData?.category()?.equals(RssDataType.PRIVATE) == false && rssData?.originPage?.isNotEmpty() == true) {
rssData?.originPage?.let {
binding.geckoWeb.privateMode = false binding.geckoWeb.privateMode = false
rssId = originPage rssId = it
targetList.clear() targetList.clear()
var setString = hashSetOf<String>() var setString = hashSetOf<String>()
setString.addAll(rssList) setString.addAll(rssList)
setString.removeAll { it.equals(rssId) } setString.removeAll { it.equals(rssId) }
targetList.addAll(setString) targetList.addAll(setString)
binding.geckoWeb.loadUrl(rssId) binding.geckoWeb.loadUrl(rssId)
} }
} else { } else if (rssData?.category()?.equals(RssDataType.PRIVATE) == true){
rssData?.let { rssData?.let {
binding.geckoWeb.privateMode = true
lasted.removeAll { target -> target.originPage.equals(it.originPage) } lasted.removeAll { target -> target.originPage.equals(it.originPage) }
appendReadCount(it, 1, false) appendReadCount(it, 1, false)
Blog.LOGE("removeFirst >>> ${Gson().toJson(it)}") Blog.LOGE("removeFirst >>> ${Gson().toJson(it)}")
binding.layoutRssSummary.title.tag = it binding.layoutRssSummary.title.tag = it
binding.layoutRssSummary.root.visibility = View.VISIBLE binding.layoutRssSummary.root.visibility = View.VISIBLE
binding.layoutRssSummary.scrollView.scrollTo(0,0)
var vote = it.vote var vote = it.vote
var read = it.read var read = it.read
it.title?.let { it.title?.let {
@ -345,7 +368,7 @@ internal class RssHome : Fragment() {
"O" "O"
}else { }else {
"X" "X"
}} , R:${read}]") }} , R:${read + 1}]")
} }
it.pubDate()?.let { it.pubDate()?.let {
@ -376,6 +399,10 @@ internal class RssHome : Fragment() {
loadImage(binding.layoutRssSummary.screen, it) loadImage(binding.layoutRssSummary.screen, it)
binding.layoutRssSummary.screenLink.text = it binding.layoutRssSummary.screenLink.text = it
} }
// it.originPage().let {
// Blog.LOGE(it)
// binding.layoutRssSummary.smallg.loadUrl(it)
// }
} }
} }
} }
@ -423,6 +450,14 @@ internal class RssHome : Fragment() {
ask() ask()
true true
} }
binding.search.setOnClickListener {
if (binding.geckoWeb.isVisible) {
binding.geckoWeb.visibility = View.GONE
}
binding.geckoWeb.visibility = View.GONE
searchKeyword()
true
}
binding.privateBtn.setOnClickListener { binding.privateBtn.setOnClickListener {
queryPrevate(true) queryPrevate(true)
} }
@ -472,6 +507,10 @@ internal class RssHome : Fragment() {
binding.layoutRssSummary.link.setOnClickListener { binding.layoutRssSummary.link.setOnClickListener {
(it.tag as? RssData)?.let { (it.tag as? RssData)?.let {
appendReadCount(it, 1, true) appendReadCount(it, 1, true)
startActivity(Intent().apply {
action = Intent.ACTION_VIEW
data = Uri.parse(it.magnet_link)
})
} }
} }
binding.layoutRssSummary.title.setOnClickListener { binding.layoutRssSummary.title.setOnClickListener {
@ -584,6 +623,9 @@ internal class RssHome : Fragment() {
} }
fun updateQuery(q: RealmQuery<RssData>) { fun updateQuery(q: RealmQuery<RssData>) {
infosJob?.cancel()
commandHandler.removeCallbacks(infoUpdate)
mRssDataResult = mRssDataResult =
q.sort("pubDate ", Sort.DESCENDING).limit(300).distinct("originPage", "title").find() q.sort("pubDate ", Sort.DESCENDING).limit(300).distinct("originPage", "title").find()
mRssDataResult?.asFlow()?.let { flow -> mRssDataResult?.asFlow()?.let { flow ->
@ -646,13 +688,42 @@ internal class RssHome : Fragment() {
updateQuery(rQ) updateQuery(rQ)
} }
fun buildMultiFieldOrQuery(
fields: List<String>,
keywords: List<String>
): Pair<String, Array<String>> {
val queryParts = mutableListOf<String>()
val args = mutableListOf<String>()
keywords.forEach { keyword ->
val fieldConditions = fields.map { field ->
"$field CONTAINS[c] \$${args.size}"
}.joinToString(" AND ")
queryParts.add("($fieldConditions)")
// 각 필드마다 같은 keyword를 넣어줘야 함
fields.forEach { _ -> args.add(keyword) }
}
val queryString = queryParts.joinToString(" OR ")
return Pair(queryString, args.toTypedArray())
}
fun queryInfos( fun queryInfos(
keyword: String, keywords: List<String>,
category: ArrayList<String> = arrayListOf(),
noLimit: Boolean = false
) { ) {
beforeQuery() beforeQuery()
updateQuery(WorkersDb.getRssQuery(keyword, category, noLimit)) var rQ = getRealm().query<RssData>().sort("pubDate", Sort.DESCENDING)
// 사용 예시
val (queryStr, queryArgs) = buildMultiFieldOrQuery(
listOf("title", "description"),
keywords
)
updateQuery(rQ.query(queryStr, *queryArgs))
} }
@ -777,11 +848,21 @@ internal class RssHome : Fragment() {
} }
} }
fun loadImage(imageView: ImageView, url: String?, retryCount: Int = 3) { var lOnClickListener = object : View.OnClickListener{
override fun onClick(v: View) {
v.setAlpha(1f)
v.visibility = View.VISIBLE
}
}
val mainHandler = Handler(Looper.getMainLooper())
fun loadImage(imageView: ImageView, url: String?, retryCount: Int = 5) {
with(imageView) { with(imageView) {
Picasso.get().cancelRequest(this) Picasso.get().cancelRequest(this)
// setOnTouchListener(null)
setOnTouchListener(null) setOnTouchListener(null)
} }
imageView.setImageResource(R.drawable.ic_info)
imageView.setAlpha(1f)
url?.let { url -> url?.let { url ->
if (url.length > 4) { if (url.length > 4) {
try { try {
@ -794,7 +875,7 @@ internal class RssHome : Fragment() {
override fun onSuccess() { override fun onSuccess() {
imageView.visibility = View.VISIBLE imageView.visibility = View.VISIBLE
imageView.setAlpha(0.05f) imageView.setAlpha(0.05f)
imageView.setOnTouchListener(lOnTouchListener) imageView.setOnClickListener(lOnClickListener)
Blog.LOGE("Picasso load into onSuccess URL:$url") Blog.LOGE("Picasso load into onSuccess URL:$url")
} }
@ -802,9 +883,13 @@ internal class RssHome : Fragment() {
e?.printStackTrace() e?.printStackTrace()
if (retryCount > 0) { if (retryCount > 0) {
// 메인 스레드에서 재시도 // 메인 스레드에서 재시도
Handler(Looper.getMainLooper()).postDelayed({ if (binding.layoutRssSummary.root.isVisible) {
loadImage(imageView, url, retryCount - 1) mainHandler.postDelayed({
}, 1500L) if (binding.layoutRssSummary.root.isVisible && imageView.visibility == View.INVISIBLE) {
loadImage(imageView, url, retryCount - 1)
}
}, 3000L)
}
} else { } else {
// 3회 모두 실패: 대체 이미지 표시 // 3회 모두 실패: 대체 이미지 표시
imageView.setImageResource(R.drawable.ic_info) imageView.setImageResource(R.drawable.ic_info)
@ -823,7 +908,7 @@ internal class RssHome : Fragment() {
imageView.visibility = View.INVISIBLE imageView.visibility = View.INVISIBLE
} }
} }
fun randomOrNull() : RssData? = lasted.sortedByDescending { it.read }.filter { it.vote == false && it.read < nomoreShowCount }.randomOrNull() fun randomOrNull() : RssData? = lasted.filter { it.vote == false && it.read < 2 }.randomOrNull()
} }
var toast: Toast? = null var toast: Toast? = null
fun Context.toast(string: String) { fun Context.toast(string: String) {

View File

@ -32,6 +32,7 @@ import bums.lunatic.launcher.model.TelegramMessage
import bums.lunatic.launcher.model.WeatherForcast import bums.lunatic.launcher.model.WeatherForcast
import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.Blog
import bums.lunatic.launcher.utils.JamoUtils import bums.lunatic.launcher.utils.JamoUtils
import bums.lunatic.launcher.utils.afterDay
import bums.lunatic.launcher.utils.beforeDay import bums.lunatic.launcher.utils.beforeDay
import bums.lunatic.launcher.utils.beforeOneDay import bums.lunatic.launcher.utils.beforeOneDay
import com.google.gson.Gson import com.google.gson.Gson
@ -108,15 +109,19 @@ object WorkersDb {
getRealm().writeBlocking { getRealm().writeBlocking {
try { try {
rssDatas.forEach { t -> rssDatas.forEach { t ->
if (query<RssData>("originPage == $0", t.originPage).find().isEmpty()) { var results= query<RssData>("originPage == $0", t.originPage).find()
// val catfillters = arrayListOf<RssDataType>(RssDataType.THEQOO,RssDataType.RULIWEB,RssDataType.ARCA,RssDataType.CLIEN,RssDataType.FMKORAE,RssDataType.DOTAX,RssDataType.DCINSIDE) if (results.isEmpty()) {
// if(catfillters.contains(it.category()) && query<RssData>("chosung == $0",it.chosung).find().size == 0) { if(it.category().equals(RssDataType.PRIVATE)) {
it.pubDate = afterDay(it.pubDate)
}
this.copyToRealm(t, UpdatePolicy.ERROR) this.copyToRealm(t, UpdatePolicy.ERROR)
// } else if(!catfillters.contains(it.category())){ } else {
// this.copyToRealm(it, UpdatePolicy.ERROR) if(it.category().equals(RssDataType.PRIVATE)) {
// } else { it.pubDate = afterDay(it.pubDate)
// it.vote = results.first().vote
// } it.read = results.first().read
this.copyToRealm(t, UpdatePolicy.ALL)
}
} }
} }

View File

@ -62,7 +62,9 @@
<Button <Button
android:text="hidden" android:text="hidden"
android:id="@+id/hidden" android:id="@+id/hidden"
style="@style/tabItem"
android:gravity="center"
android:layout_width="60dp"
android:layout_height="match_parent"/> android:layout_height="match_parent"/>
</RadioGroup> </RadioGroup>
</HorizontalScrollView> </HorizontalScrollView>

View File

@ -13,6 +13,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<ScrollView <ScrollView
android:id="@+id/scrollView"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
@ -105,6 +106,17 @@
android:textColor="@color/white" android:textColor="@color/white"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<bums.lunatic.launcher.home.GeckoWeb
android:id="@+id/smallg"
android:visibility="gone"
android:layout_width="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/link"
android:layout_height="800dp"
/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView> </ScrollView>
<ImageButton <ImageButton