diff --git a/app/src/main/assets/extensions/my_extension/messaging.js b/app/src/main/assets/extensions/my_extension/messaging.js index 947ae0d4..a8e26c16 100644 --- a/app/src/main/assets/extensions/my_extension/messaging.js +++ b/app/src/main/assets/extensions/my_extension/messaging.js @@ -423,7 +423,8 @@ function gotoNext() { if(e.hasAttribute("href") && ( (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 @@ -432,9 +433,9 @@ function gotoNext() { if(targetElement !== null) { targetElement.click() } else { - location.href = "https://naver.com" +// location.href = "https://naver.com" } - }, 5000); + }, 15000); } } catch (e) { diff --git a/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt b/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt index 1e0a0a0b..1b9cbc09 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt @@ -582,6 +582,7 @@ internal class LauncherActivity : CommonActivity() { @SuppressLint("NewApi", "MissingPermission") override fun onCreate(savedInstanceState: Bundle?) { installSplashScreen() + getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); lActivity = this mWorkManager = WorkManager.getInstance(this) DynamicColors.applyToActivityIfAvailable(this) diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt index c6abc51e..8a2a77b4 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt @@ -2,6 +2,7 @@ package bums.lunatic.launcher.home import android.app.DownloadManager import android.content.Context +import android.content.DialogInterface import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP 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_DPAD_DOWN import android.view.KeyEvent.KEYCODE_DPAD_UP +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup +import android.widget.CheckBox +import android.widget.EditText import android.widget.ProgressBar import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible 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.model.History 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) { loadUrl(uri) } else { - 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 - }) + val builder: AlertDialog.Builder = AlertDialog.Builder(context) + builder.setTitle("Move To") + val viewInflated: View = LayoutInflater.from(context) + .inflate(R.layout.text_inpu_password, null, false) + val input = viewInflated.findViewById(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) @@ -469,16 +493,9 @@ class GeckoWeb : BWebview { "SHOWVIEWER" -> { } "PRIVATES"->{ - lPortMessage.privates?.forEach { - Blog.LOGE("Item screenshots >>> ${it.getScreen()}") - it.pubDate = afterDay(it.pubDate) -// WorkersDb.insertData(it) - getRealm().apply { - this.writeBlocking { - copyToRealm(it, UpdatePolicy.ALL) - } - } - context.toast("Received Msg privates form ${lPortMessage.currentPage} data => ${lPortMessage.privates?.size ?: 0}") + lPortMessage.privates?.let { + context.toast("Received Msg privates form ${lPortMessage.currentPage} data => ${it?.size ?: 0}") + WorkersDb.insertBulkData(it) } } "Cookies"->{ diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt index 95ba22dc..b9d1bfde 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt @@ -24,7 +24,6 @@ import android.content.DialogInterface import android.content.Intent import android.content.SharedPreferences import android.net.Uri -import android.os.Build import android.os.Bundle import android.os.Handler import android.os.Looper @@ -40,7 +39,6 @@ import android.widget.Toast import androidx.annotation.NonNull import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible -import androidx.databinding.BindingAdapter import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager 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.beforeOneDay import bums.lunatic.launcher.workers.WorkersDb -import bums.lunatic.launcher.workers.WorkersDb.prvClear -import com.bumptech.glide.Glide -import com.bumptech.glide.load.engine.DiskCacheStrategy +import bums.lunatic.launcher.workers.WorkersDb.getRealm import com.google.android.material.imageview.ShapeableImageView import com.google.gson.Gson import com.squareup.picasso.Picasso import io.realm.kotlin.UpdatePolicy import io.realm.kotlin.ext.query -import io.realm.kotlin.notifications.InitialResults import io.realm.kotlin.notifications.ResultsChange -import io.realm.kotlin.notifications.UpdatedResults import io.realm.kotlin.query.RealmQuery import io.realm.kotlin.query.RealmResults import io.realm.kotlin.query.Sort @@ -85,7 +79,6 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import java.text.SimpleDateFormat import java.util.Date -import kotlin.time.TimeSource internal class RssHome : Fragment() { @@ -233,7 +226,7 @@ internal class RssHome : Fragment() { when (rss.category()) { RssDataType.REDDIT_NSFW, RssDataType.PRIVATE -> { v.findViewById(R.id.circle_preview)?.let { - if (RssDataType.PRIVATE.equals(rss.category()) && imageView) { + if (RssDataType.PRIVATE.equals(rss.category())) { openGecko(rssData = rss) } else { if (it.visibility == View.GONE) { @@ -250,7 +243,7 @@ internal class RssHome : Fragment() { data = Uri.parse(rss.originPage) }) } else { - openGecko(rss.originPage()) + openGecko(rss) } } } @@ -262,7 +255,7 @@ internal class RssHome : Fragment() { } RssDataType.DOTAX -> { - openGecko(rss.originPage()) + openGecko(rss) } RssDataType.YOUTUBE -> { @@ -270,15 +263,43 @@ internal class RssHome : Fragment() { } RssDataType.CLIEN -> { - openGecko(rss.originPage()) + openGecko(rss) } 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(R.id.input) as EditText + val privateMode = viewInflated.findViewById(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() { @@ -317,26 +338,28 @@ internal class RssHome : Fragment() { @SuppressLint("SimpleDateFormat") - fun openGecko(originPage: String? = null, rssData: RssData? = null) { - if (!imageView) { - originPage?.let { + fun openGecko(rssData: RssData? = null) { + binding.layoutRssSummary.root.visibility = View.GONE + if (rssData?.category()?.equals(RssDataType.PRIVATE) == false && rssData?.originPage?.isNotEmpty() == true) { + rssData?.originPage?.let { binding.geckoWeb.privateMode = false - rssId = originPage + rssId = it targetList.clear() - var setString = hashSetOf() setString.addAll(rssList) setString.removeAll { it.equals(rssId) } targetList.addAll(setString) binding.geckoWeb.loadUrl(rssId) } - } else { + } else if (rssData?.category()?.equals(RssDataType.PRIVATE) == true){ rssData?.let { + binding.geckoWeb.privateMode = true lasted.removeAll { target -> target.originPage.equals(it.originPage) } appendReadCount(it, 1, false) Blog.LOGE("removeFirst >>> ${Gson().toJson(it)}") binding.layoutRssSummary.title.tag = it binding.layoutRssSummary.root.visibility = View.VISIBLE + binding.layoutRssSummary.scrollView.scrollTo(0,0) var vote = it.vote var read = it.read it.title?.let { @@ -345,7 +368,7 @@ internal class RssHome : Fragment() { "O" }else { "X" - }} , R:${read}]") + }} , R:${read + 1}]") } it.pubDate()?.let { @@ -376,6 +399,10 @@ internal class RssHome : Fragment() { loadImage(binding.layoutRssSummary.screen, 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() true } + binding.search.setOnClickListener { + if (binding.geckoWeb.isVisible) { + binding.geckoWeb.visibility = View.GONE + } + binding.geckoWeb.visibility = View.GONE + searchKeyword() + true + } binding.privateBtn.setOnClickListener { queryPrevate(true) } @@ -472,6 +507,10 @@ internal class RssHome : Fragment() { binding.layoutRssSummary.link.setOnClickListener { (it.tag as? RssData)?.let { appendReadCount(it, 1, true) + startActivity(Intent().apply { + action = Intent.ACTION_VIEW + data = Uri.parse(it.magnet_link) + }) } } binding.layoutRssSummary.title.setOnClickListener { @@ -584,6 +623,9 @@ internal class RssHome : Fragment() { } fun updateQuery(q: RealmQuery) { + infosJob?.cancel() + commandHandler.removeCallbacks(infoUpdate) + mRssDataResult = q.sort("pubDate ", Sort.DESCENDING).limit(300).distinct("originPage", "title").find() mRssDataResult?.asFlow()?.let { flow -> @@ -646,13 +688,42 @@ internal class RssHome : Fragment() { updateQuery(rQ) } + fun buildMultiFieldOrQuery( + fields: List, + keywords: List + ): Pair> { + val queryParts = mutableListOf() + val args = mutableListOf() + + 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( - keyword: String, - category: ArrayList = arrayListOf(), - noLimit: Boolean = false + keywords: List, ) { beforeQuery() - updateQuery(WorkersDb.getRssQuery(keyword, category, noLimit)) + var rQ = getRealm().query().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) { Picasso.get().cancelRequest(this) +// setOnTouchListener(null) setOnTouchListener(null) } + imageView.setImageResource(R.drawable.ic_info) + imageView.setAlpha(1f) url?.let { url -> if (url.length > 4) { try { @@ -794,7 +875,7 @@ internal class RssHome : Fragment() { override fun onSuccess() { imageView.visibility = View.VISIBLE imageView.setAlpha(0.05f) - imageView.setOnTouchListener(lOnTouchListener) + imageView.setOnClickListener(lOnClickListener) Blog.LOGE("Picasso load into onSuccess URL:$url") } @@ -802,9 +883,13 @@ internal class RssHome : Fragment() { e?.printStackTrace() if (retryCount > 0) { // 메인 스레드에서 재시도 - Handler(Looper.getMainLooper()).postDelayed({ - loadImage(imageView, url, retryCount - 1) - }, 1500L) + if (binding.layoutRssSummary.root.isVisible) { + mainHandler.postDelayed({ + if (binding.layoutRssSummary.root.isVisible && imageView.visibility == View.INVISIBLE) { + loadImage(imageView, url, retryCount - 1) + } + }, 3000L) + } } else { // 3회 모두 실패: 대체 이미지 표시 imageView.setImageResource(R.drawable.ic_info) @@ -823,7 +908,7 @@ internal class RssHome : Fragment() { 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 fun Context.toast(string: String) { diff --git a/app/src/main/kotlin/bums/lunatic/launcher/workers/WorkersDb.kt b/app/src/main/kotlin/bums/lunatic/launcher/workers/WorkersDb.kt index 23f1b05d..e9ed8eca 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/workers/WorkersDb.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/workers/WorkersDb.kt @@ -32,6 +32,7 @@ import bums.lunatic.launcher.model.TelegramMessage import bums.lunatic.launcher.model.WeatherForcast import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.JamoUtils +import bums.lunatic.launcher.utils.afterDay import bums.lunatic.launcher.utils.beforeDay import bums.lunatic.launcher.utils.beforeOneDay import com.google.gson.Gson @@ -108,15 +109,19 @@ object WorkersDb { getRealm().writeBlocking { try { rssDatas.forEach { t -> - if (query("originPage == $0", t.originPage).find().isEmpty()) { -// val catfillters = arrayListOf(RssDataType.THEQOO,RssDataType.RULIWEB,RssDataType.ARCA,RssDataType.CLIEN,RssDataType.FMKORAE,RssDataType.DOTAX,RssDataType.DCINSIDE) -// if(catfillters.contains(it.category()) && query("chosung == $0",it.chosung).find().size == 0) { + var results= query("originPage == $0", t.originPage).find() + if (results.isEmpty()) { + if(it.category().equals(RssDataType.PRIVATE)) { + it.pubDate = afterDay(it.pubDate) + } this.copyToRealm(t, UpdatePolicy.ERROR) -// } else if(!catfillters.contains(it.category())){ -// this.copyToRealm(it, UpdatePolicy.ERROR) -// } else { -// -// } + } else { + if(it.category().equals(RssDataType.PRIVATE)) { + it.pubDate = afterDay(it.pubDate) + it.vote = results.first().vote + it.read = results.first().read + this.copyToRealm(t, UpdatePolicy.ALL) + } } } diff --git a/app/src/main/res/layout/launcher_activity.xml b/app/src/main/res/layout/launcher_activity.xml index a7eed3ac..d1361b29 100644 --- a/app/src/main/res/layout/launcher_activity.xml +++ b/app/src/main/res/layout/launcher_activity.xml @@ -62,7 +62,9 @@