This commit is contained in:
lunaticbum 2025-07-24 16:09:35 +09:00
parent 193946cadf
commit dc69070823
11 changed files with 326 additions and 210 deletions

View File

@ -0,0 +1,9 @@
(function() {
var meta = document.querySelector('meta[name=viewport]');
if (!meta) {
meta = document.createElement('meta');
meta.name = 'viewport';
document.head.appendChild(meta);
}
meta.setAttribute('content', 'width=device-width, initial-scale=1.0');
})();

View File

@ -15,7 +15,7 @@
{ {
"run_at": "document_end", "run_at": "document_end",
"matches": ["<all_urls>"], "matches": ["<all_urls>"],
"js": ["messaging.js"] "js": ["messaging.js","inject-viewport.js"]
} }
], ],
"permissions": [ "permissions": [

View File

@ -414,20 +414,21 @@ var time2 = null
function gotoNext() { function gotoNext() {
clearTimeout(time1) clearTimeout(time1)
try{ try{
console.log("targetUrl :: " + targetUrl); console.log("targetUrl :: " + targetUrl);
time2 = setTimeout(function () { if (document.querySelector('[class="btn-group"]')) {
clearTimeout(time2) time2 = setTimeout(function () {
document.querySelector('[class="btn-group"]').querySelectorAll('a').forEach(function(e){ clearTimeout(time2)
if(e.hasAttribute("href") && document.querySelector('[class="btn-group"]').querySelectorAll('a').forEach(function(e){
( 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=2") > -1 && location.href.search("page") < 0) ||
)) { (e.getAttribute("href").search("page=3") > -1 && location.href.search("page=2") > 0)
e.click() )) {
} e.click()
}) }
}, 5000); })
}, 5000);
}
} catch (e) { } catch (e) {
} }

View File

@ -731,7 +731,7 @@ internal class LauncherActivity : CommonActivity() {
when(currentFragment) { when(currentFragment) {
is RssHome ->{ is RssHome ->{
if (currentFragment.binding.layoutRssSummary.root.isVisible) { if (currentFragment.binding.layoutRssSummary.root.isVisible) {
currentFragment.openGecko(rssData = currentFragment.lasted.randomOrNull()) currentFragment.openGecko(rssData = currentFragment.randomOrNull())
} else { } else {
currentFragment.doNextPage() currentFragment.doNextPage()
} }

View File

@ -27,6 +27,7 @@ import android.view.View
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 bums.lunatic.launcher.LauncherActivity.Companion.getRuntime import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime
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
@ -110,6 +111,7 @@ class GeckoWeb : BWebview {
var canGoBack: Boolean? = null var canGoBack: Boolean? = null
var mPort: WebExtension.Port? = null var mPort: WebExtension.Port? = null
var mCaache : WebExtension.Port? = null var mCaache : WebExtension.Port? = null
var privateMode = false
object WebExtensionInfo { object WebExtensionInfo {
val mPortNam = "browser" val mPortNam = "browser"
val extPath = "resource://android/assets/extensions/my_extension/" val extPath = "resource://android/assets/extensions/my_extension/"
@ -347,20 +349,9 @@ class GeckoWeb : BWebview {
} }
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
super.onPageStart(session, url) super.onPageStart(session, url)
if (url.contains(getFilterF()) && url.contains("jpg") == false) { if (url.contains(getFilterF()) && privateMode) {
this@GeckoWeb.visibility = View.INVISIBLE this@GeckoWeb.visibility = View.INVISIBLE
} }
// if (url?.contains("reddit.app.link") == true) {
// session.stop()
// Uri.parse(url)?.let { uri ->
// 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 = uri
// })
// }
// }
} }
override fun onPageStop(session: GeckoSession, success: Boolean) { override fun onPageStop(session: GeckoSession, success: Boolean) {
@ -368,12 +359,12 @@ class GeckoWeb : BWebview {
super.onPageStop(session, success) super.onPageStop(session, success)
if (success && mPort != null) { if (success && mPort != null) {
if (mPort == null) { if (mPort == null) {
// No extension registered yet, let's ignore this message
return return
} }
} }
} }
} }
@ -423,7 +414,7 @@ class GeckoWeb : BWebview {
Blog.LOGE("GeckoView", "현재 session: $session") Blog.LOGE("GeckoView", "현재 session: $session")
url?.let { url -> url?.let { url ->
if (url?.contains(getFilterF()) == true && url.contains("jpg") == false) { if (url?.contains(getFilterF()) == true && privateMode) {
this@GeckoWeb.visibility = View.INVISIBLE this@GeckoWeb.visibility = View.INVISIBLE
} }
if (url.split("//").size > 1) { if (url.split("//").size > 1) {
@ -482,7 +473,7 @@ class GeckoWeb : BWebview {
copyToRealm(it, UpdatePolicy.ALL) copyToRealm(it, UpdatePolicy.ALL)
} }
} }
Toast.makeText(context, "Received Msg privates form ${lPortMessage.currentPage} data => ${lPortMessage.privates?.size ?: 0}", Toast.LENGTH_SHORT).show() context.toast("Received Msg privates form ${lPortMessage.currentPage} data => ${lPortMessage.privates?.size ?: 0}")
} }
} }
"Cookies"->{ "Cookies"->{
@ -657,6 +648,35 @@ class GeckoWeb : BWebview {
return super.dispatchKeyEvent(ev) return super.dispatchKeyEvent(ev)
} }
override fun loadUrl(url: String, param : String?) {
var nUrl = url
Blog.LOGE("url >>>> ${url}")
if (url.endsWith("=")) {
nUrl = String(java.util.Base64.getMimeDecoder().decode(url.toByteArray()))
param?.let {
nUrl = nUrl.plus(param)
}
} else if (url.startsWith("http") == false) {
nUrl = lastDomain
}
if (!privateMode && this.isVisible == false) {
this.visibility = View.VISIBLE
}
Blog.LOGE("nUrl >>>> ${nUrl}")
nUrl?.let { url ->
if (url.split("//").size > 1) {
url.replace("//","/").replace("https:/","https://").let {
Blog.LOGE("url >> ${url} , it >>> ${it}")
this.session?.loadUri(it)
}
} else {
this.session?.loadUri(url)
}
}
BWebview.Companion.currentRetryCount = 0;
}
companion object { companion object {
private const val TAG = "DualScreenStatus" private const val TAG = "DualScreenStatus"

View File

@ -19,6 +19,7 @@
package bums.lunatic.launcher.home package bums.lunatic.launcher.home
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
@ -109,121 +110,123 @@ internal class RssHome : Fragment() {
var mRssDataResult: RealmResults<RssData>? = null var mRssDataResult: RealmResults<RssData>? = null
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("")
if (imageView){ if (imageView) {
openGecko(rssData = lasted.randomOrNull()) openGecko(rssData = randomOrNull())
}
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 {
if (imageView){ if (imageView) {
openGecko(rssData = lasted.randomOrNull()) openGecko(rssData = randomOrNull())
}
Blog.LOGE("")
return true
} }
Blog.LOGE("")
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("")
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("")
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 false return false
} }
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 false return false
} }
override fun onClick( override fun onClick(
targetView: View, targetView: View,
fingers: Int fingers: Int
): Boolean { ): Boolean {
Blog.LOGE("onClick") Blog.LOGE("onClick")
return false return false
} }
}) })
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
home = this home = this
} }
var targetList = arrayListOf<String>() var targetList = arrayListOf<String>()
val dateViewClick = View.OnClickListener { v -> val dateViewClick = View.OnClickListener { v ->
Blog.LOGE("click view >> ${v}") Blog.LOGE("click view >> ${v}")
(v?.tag as? RssData)?.let { rss -> (v?.tag as? RssData)?.let { rss ->
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
writeBlocking { writeBlocking {
rss.read = rss.read + 1 rss.read = rss.read + 1
if(rss.getCho()?.length ?: 0 < 1) { if (rss.getCho()?.length ?: 0 < 1) {
rss.chosung = rss.title rss.chosung = rss.title
} }
copyToRealm(rss,UpdatePolicy.ALL) copyToRealm(rss, UpdatePolicy.ALL)
} }
} }
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()) && imageView) {
openGecko(rssData = lasted.randomOrNull()) openGecko(rssData = rss)
} else { } else {
if (it.visibility == View.GONE) { if (it.visibility == View.GONE) {
it.visibility = View.VISIBLE it.visibility = View.VISIBLE
@ -245,17 +248,23 @@ internal class RssHome : Fragment() {
} }
} }
} }
RssDataType.REDDIT -> { RssDataType.REDDIT -> {
openReddit(rss.originPage()) openReddit(rss.originPage())
} }
RssDataType.DOTAX -> { RssDataType.DOTAX -> {
openGecko(rss.originPage()) openGecko(rss.originPage())
} }
RssDataType.YOUTUBE -> { openYouTube(rss.originPage())
RssDataType.YOUTUBE -> {
openYouTube(rss.originPage())
} }
RssDataType.CLIEN -> { RssDataType.CLIEN -> {
openGecko(rss.originPage()) openGecko(rss.originPage())
} }
else -> { else -> {
openGecko(rss.originPage()) openGecko(rss.originPage())
} }
@ -271,17 +280,22 @@ internal class RssHome : Fragment() {
.inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false) .inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
val input = viewInflated.findViewById<View>(R.id.input) as EditText val input = viewInflated.findViewById<View>(R.id.input) as EditText
builder.setView(viewInflated) builder.setView(viewInflated)
builder.setPositiveButton(android.R.string.ok, builder.setPositiveButton(
android.R.string.ok,
DialogInterface.OnClickListener { dialog, which -> DialogInterface.OnClickListener { dialog, which ->
dialog.dismiss() dialog.dismiss()
var command = input.editableText?.toString() var command = input.editableText?.toString()
if (command?.length ?: 0 > 0) { if (command?.length ?: 0 > 0) {
binding.geckoWeb.loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=", "/?searchTerm=${command}") binding.geckoWeb.loadUrl(
"aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=",
"/?searchTerm=${command}"
)
} else { } else {
binding.geckoWeb.loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=") binding.geckoWeb.loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=")
} }
}) })
builder.setNegativeButton(android.R.string.cancel, builder.setNegativeButton(
android.R.string.cancel,
DialogInterface.OnClickListener { dialog, which -> dialog.cancel() }) DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
builder.show() builder.show()
@ -304,12 +318,20 @@ internal class RssHome : Fragment() {
} }
} else { } else {
rssData?.let { rssData?.let {
lasted.removeAll { target -> target.originPage.equals(it.originPage) }
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
it.title()?.let { var vote = it.vote
var read = it.read
it.title?.let {
Blog.LOGE(it) Blog.LOGE(it)
binding.layoutRssSummary.title.text = it binding.layoutRssSummary.title.text = it.replace(Regex("[\\r\\n]+"), " ").plus( "\n[V:${if (vote) {
"O"
}else {
"X"
}} , R:${read}]")
} }
it.pubDate()?.let { it.pubDate()?.let {
@ -320,7 +342,7 @@ internal class RssHome : Fragment() {
binding.layoutRssSummary.desc.tag = it binding.layoutRssSummary.desc.tag = it
it.description()?.let { it.description()?.let {
Blog.LOGE(it) Blog.LOGE(it)
binding.layoutRssSummary.desc.text = it binding.layoutRssSummary.desc.text = it.replace(Regex("[\\r\\n]+"), " ")
} }
binding.layoutRssSummary.link.tag = it binding.layoutRssSummary.link.tag = it
it.getMagnet().let { it.getMagnet().let {
@ -354,15 +376,19 @@ internal class RssHome : Fragment() {
binding = LauncherHomeBinding.inflate(inflater, container, false) binding = LauncherHomeBinding.inflate(inflater, container, false)
fragManager = lActivity!!.supportFragmentManager fragManager = lActivity!!.supportFragmentManager
settingsPrefs = requireContext().getSharedPreferences(PREFS_SETTINGS, 0) settingsPrefs = requireContext().getSharedPreferences(PREFS_SETTINGS, 0)
mRssAdapter = RssItemAdapter(requireContext(),dateViewClick) mRssAdapter = RssItemAdapter(requireContext(), dateViewClick)
val decoration = DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL) val decoration = DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL)
binding.infoList.addItemDecoration(decoration) binding.infoList.addItemDecoration(decoration)
binding.infoList.visibility = View.VISIBLE binding.infoList.visibility = View.VISIBLE
binding.infoList.adapter = mRssAdapter binding.infoList.adapter = mRssAdapter
binding.infoList.setOnTouchListener { v,e -> binding.infoList.setOnTouchListener { v, e ->
if (e.device.name?.contains("JX-12",true) == true|| e.device.name?.equals("J06",true) == true) { if (e.device.name?.contains("JX-12", true) == true || e.device.name?.equals(
"J06",
true
) == true
) {
Blog.LOGE("touchEvent -> ${e}") Blog.LOGE("touchEvent -> ${e}")
return@setOnTouchListener mSimpleFingerGestures.onTouch(v,e) return@setOnTouchListener mSimpleFingerGestures.onTouch(v, e)
} else { } else {
return@setOnTouchListener false return@setOnTouchListener false
@ -374,7 +400,7 @@ internal class RssHome : Fragment() {
} }
} }
binding.test.setOnClickListener { binding.test.setOnClickListener {
if(binding.geckoWeb.isVisible) { if (binding.geckoWeb.isVisible) {
binding.geckoWeb.visibility = View.GONE binding.geckoWeb.visibility = View.GONE
} }
@ -389,7 +415,7 @@ internal class RssHome : Fragment() {
val result = query<RssData>().query("originPage == $0", rssId).find() val result = query<RssData>().query("originPage == $0", rssId).find()
if (result.size > 0) { if (result.size > 0) {
result.forEach { result.forEach {
if(it.vote) { if (it.vote) {
it.vote = false it.vote = false
} }
} }
@ -404,13 +430,13 @@ internal class RssHome : Fragment() {
if (binding.geckoWeb.isVisible) { if (binding.geckoWeb.isVisible) {
binding.geckoWeb.visibility = View.GONE binding.geckoWeb.visibility = View.GONE
} }
binding.layoutRssSummary.root.visibility = View.GONE binding.layoutRssSummary.root.visibility = View.GONE
queryInfos() queryInfos()
} }
binding.bookmark.setOnClickListener { binding.bookmark.setOnClickListener {
binding.layoutRssSummary.root.visibility = View.GONE binding.layoutRssSummary.root.visibility = View.GONE
queryVotes() queryVotes()
} }
binding.prv.setOnClickListener { binding.prv.setOnClickListener {
@ -424,25 +450,27 @@ internal class RssHome : Fragment() {
binding.layoutRssSummary.title.setOnClickListener { binding.layoutRssSummary.title.setOnClickListener {
(it.tag as? RssData)?.let { (it.tag as? RssData)?.let {
appendReadCount(it, nomoreShowCount, false) appendReadCount(it, nomoreShowCount, false)
openGecko(rssData = lasted.randomOrNull()) openGecko(rssData = randomOrNull())
} }
} }
binding.layoutRssSummary.close.setOnClickListener { binding.layoutRssSummary.close.setOnClickListener {
binding.layoutRssSummary.root.visibility = View.GONE binding.layoutRssSummary.root.visibility = View.GONE
} }
queryInfos() queryInfos()
binding.geckoWeb.progress = binding.progressBar binding.geckoWeb.progress = binding.progressBar
binding.geckoWeb.jxInteface = { jxEvent -> binding.geckoWeb.jxInteface = { jxEvent ->
when(jxEvent) { when (jxEvent) {
JxEvent.SCROLL_UP -> binding.geckoWeb.sendScrollDown(false) JxEvent.SCROLL_UP -> binding.geckoWeb.sendScrollDown(false)
JxEvent.SCROLL_DOWN -> binding.geckoWeb.sendScrollDown(true) JxEvent.SCROLL_DOWN -> binding.geckoWeb.sendScrollDown(true)
JxEvent.ON_CLICK -> { JxEvent.ON_CLICK -> {
binding.geckoWeb.visibility = View.GONE binding.geckoWeb.visibility = View.GONE
} }
JxEvent.SWIPE_LEFT -> { JxEvent.SWIPE_LEFT -> {
doNextPage() doNextPage()
} }
JxEvent.SWIPE_RIGHT -> { JxEvent.SWIPE_RIGHT -> {
vote() vote()
} }
@ -456,11 +484,14 @@ internal class RssHome : Fragment() {
return binding.root return binding.root
} }
fun vote(){ fun vote() {
Blog.LOGE("Arrow Center Click") Blog.LOGE("Arrow Center Click")
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
writeBlocking { writeBlocking {
val result = query<RssData>().query(if(imageView)"thumbnail == $0" else "originPage == $0", rssId).find() val result = query<RssData>().query(
if (imageView) "thumbnail == $0" else "originPage == $0",
rssId
).find()
if (result.size > 0) { if (result.size > 0) {
result.forEach { it.vote = true } result.forEach { it.vote = true }
} }
@ -474,7 +505,10 @@ internal class RssHome : Fragment() {
fun doNextPage() { fun doNextPage() {
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
writeBlocking { writeBlocking {
val result = query<RssData>().query(if(imageView)"thumbnail == $0" else "originPage == $0", rssId).find() val result = query<RssData>().query(
if (imageView) "thumbnail == $0" else "originPage == $0",
rssId
).find()
if (result.size > 0) { if (result.size > 0) {
result.forEach { result.forEach {
it.read = it.read + nomoreShowCount it.read = it.read + nomoreShowCount
@ -492,9 +526,17 @@ internal class RssHome : Fragment() {
} }
} }
fun clearJob(job : Job?) { fun clearJob(job: Job?) {
try { job?.cancel() } catch (e: Exception) { e.printStackTrace() } try {
try { System.gc() } catch (e: Exception) { e.printStackTrace() } job?.cancel()
} catch (e: Exception) {
e.printStackTrace()
}
try {
System.gc()
} catch (e: Exception) {
e.printStackTrace()
}
} }
fun beforeQuery() { fun beforeQuery() {
@ -504,59 +546,76 @@ internal class RssHome : Fragment() {
delete( delete(
query<RssData>() query<RssData>()
.query("pubDate < $0", beforeDay(30)) .query("pubDate < $0", beforeDay(30))
.query("category != $0 AND category != $1 ", RssDataType.PRIVATE.name, RssDataType.REDDIT_NSFW.name) .query(
"category != $0 AND category != $1 ",
RssDataType.PRIVATE.name,
RssDataType.REDDIT_NSFW.name
)
.query("vote != $0", true).find() .query("vote != $0", true).find()
) )
} }
} }
fun updateQuery(q: RealmQuery<RssData>) { fun updateQuery(q: RealmQuery<RssData>) {
mRssDataResult = q.sort("pubDate ", Sort.DESCENDING).limit(300).distinct("originPage", "title").find() mRssDataResult =
q.sort("pubDate ", Sort.DESCENDING).limit(300).distinct("originPage", "title").find()
mRssDataResult?.asFlow()?.let { flow -> mRssDataResult?.asFlow()?.let { flow ->
infosJob = CoroutineScope(Dispatchers.IO).launch { infosJob = CoroutineScope(Dispatchers.IO).launch {
flow.collect { changes: ResultsChange<RssData> -> flow.collect { changes: ResultsChange<RssData> ->
when(changes) { // when (changes) {
is InitialResults -> { // is InitialResults -> {
commandHandler.removeCallbacks(infoUpdate) commandHandler.removeCallbacks(infoUpdate)
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
lasted.clear() lasted.clear()
lasted.addAll(copyFromRealm(changes.list)) lasted.addAll(copyFromRealm(changes.list))
} }
commandHandler.post(infoUpdate) commandHandler.post(infoUpdate)
} // }
is UpdatedResults -> { //
CoroutineScope(Dispatchers.Main).launch { // is UpdatedResults -> {
changes.changeRanges.forEach { // CoroutineScope(Dispatchers.Main).launch {
mRssAdapter.notifyItemRangeChanged(it.startIndex, it.length) // changes.changeRanges.forEach {
} // mRssAdapter.notifyItemRangeChanged(it.startIndex, it.length)
} // }
} // }
// }
} //
// }
} }
} }
infosJob?.start() infosJob?.start()
} }
} }
fun queryPrevate() { fun queryPrevate() {
imageView = true imageView = true
beforeQuery() beforeQuery()
updateQuery(WorkersDb.getPrivate()) updateQuery(WorkersDb.getPrivate())
} }
fun queryVotes() { fun queryVotes() {
imageView = false imageView = false
beforeQuery() beforeQuery()
updateQuery(WorkersDb.getVotedRss()) updateQuery(WorkersDb.getVotedRss())
} }
var imageView = false var imageView = false
fun queryInfos( fun queryInfos(
filter: Collection<RssDataType>? = arrayListOf(RssDataType.REDDIT_NSFW,RssDataType.PRIVATE), noLimit: Boolean = false filter: Collection<RssDataType>? = arrayListOf(
RssDataType.REDDIT_NSFW,
RssDataType.PRIVATE
), noLimit: Boolean = false
) { ) {
imageView = false imageView = false
beforeQuery() beforeQuery()
var rQ = WorkersDb.getRealm().query<RssData>().query("read < $0", nomoreShowCount).distinct("originPage", "title") var rQ = WorkersDb.getRealm().query<RssData>().query("read < $0", nomoreShowCount)
.distinct("originPage", "title")
if (!noLimit) rQ.query("pubDate > $0", beforeOneDay()) if (!noLimit) rQ.query("pubDate > $0", beforeOneDay())
((filter?.size ?: 0) > 0).letTrue {filter!!.forEach {rQ = rQ.query("category != $0", it.name)}} ((filter?.size ?: 0) > 0).letTrue {
filter!!.forEach {
rQ = rQ.query("category != $0", it.name)
}
}
updateQuery(rQ) updateQuery(rQ)
} }
@ -566,11 +625,10 @@ internal class RssHome : Fragment() {
noLimit: Boolean = false noLimit: Boolean = false
) { ) {
beforeQuery() beforeQuery()
updateQuery(WorkersDb.getRssQuery(keyword,category,noLimit)) updateQuery(WorkersDb.getRssQuery(keyword, category, noLimit))
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -591,13 +649,12 @@ internal class RssHome : Fragment() {
} }
fun chooseAdpater() { fun chooseAdpater() {
binding.infoList.visibility = View.VISIBLE binding.infoList.visibility = View.VISIBLE
lasted?.let { mRssAdapter.updateData(it) } lasted?.let { mRssAdapter.updateData(it) }
} }
fun appendReadCount(rss: RssData, appendCount : Int, vote : Boolean = false) { fun appendReadCount(rss: RssData, appendCount: Int, vote: Boolean = false) {
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
writeBlocking { writeBlocking {
var results = query<RssData>("originPage == $0", rss.originPage).find() var results = query<RssData>("originPage == $0", rss.originPage).find()
@ -615,7 +672,10 @@ internal class RssHome : Fragment() {
val swipeToDeleteCallback: SwipeToDeleteCallback = val swipeToDeleteCallback: SwipeToDeleteCallback =
object : SwipeToDeleteCallback(requireContext()) { object : SwipeToDeleteCallback(requireContext()) {
override fun onSwiped(@NonNull viewHolder: RecyclerView.ViewHolder, direction: Int) { override fun onSwiped(
@NonNull viewHolder: RecyclerView.ViewHolder,
direction: Int
) {
Blog.LOGE("onSwiped direction >>>> $direction") Blog.LOGE("onSwiped direction >>>> $direction")
(viewHolder.itemView.tag as? RssData)?.let { rss -> (viewHolder.itemView.tag as? RssData)?.let { rss ->
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
@ -673,48 +733,56 @@ internal class RssHome : Fragment() {
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
} }
}
fun loadImage(imageView: ImageView, url: String?, retryCount: Int = 3) {
fun loadImage(imageView: ImageView, url: String?, retryCount: Int = 3) { Picasso.get().cancelRequest(imageView)
Picasso.get().cancelRequest(imageView) url?.let { url ->
url?.let { url -> if (url.length > 4) {
if (url.length > 4) { try {
try { imageView.visibility = View.INVISIBLE
imageView.visibility = View.VISIBLE imageView.setAlpha(0.05f)
imageView.setAlpha(0.05f) Blog.LOGE("loadImage >>> $url")
Blog.LOGE("loadImage >>> $url") Picasso.get()
Picasso.get() .load(url)
.load(url) .into(imageView, object : com.squareup.picasso.Callback {
.into(imageView, object : com.squareup.picasso.Callback { override fun onSuccess() {
override fun onSuccess() { imageView.setAlpha(0.05f)
imageView.setAlpha(0.05f) Blog.LOGE("Picasso load into onSuccess URL:$url")
}
override fun onError(e: Exception?) {
e?.printStackTrace()
if (retryCount > 0) {
// 메인 스레드에서 재시도
Handler(Looper.getMainLooper()).post {
loadImage(imageView, url, retryCount - 1)
}
} else {
// 3회 모두 실패: 대체 이미지 표시
imageView.setImageResource(R.drawable.ic_info)
imageView.setAlpha(1f)
} }
}
})
imageView.contentDescription = url
}catch (e: Exception){
override fun onError(e: Exception?) {
e?.printStackTrace()
if (retryCount > 0) {
// 메인 스레드에서 재시도
Handler(Looper.getMainLooper()).postDelayed({
loadImage(imageView, url, retryCount - 1)
}, 1500L)
} else {
// 3회 모두 실패: 대체 이미지 표시
imageView.setImageResource(R.drawable.ic_info)
imageView.setAlpha(1f)
}
}
})
imageView.contentDescription = url
} catch (e: Exception) {
}
} else {
imageView.visibility = View.INVISIBLE
} }
} else { } ?: {
imageView.visibility = View.INVISIBLE imageView.visibility = View.INVISIBLE
} }
} ?: {
imageView.visibility = View.INVISIBLE
} }
fun randomOrNull() : RssData? = lasted.sortedByDescending { it.read }.filter { it.vote == false && it.read < nomoreShowCount }.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()
}

View File

@ -254,7 +254,7 @@ class RssData : RealmObject, RssDataInterface {
var mRssDataType : RssDataType? = null var mRssDataType : RssDataType? = null
override fun title(): String { override fun title(): String {
return when(category()){ return when(category()){
RssDataType.NEWSFEED -> { RssDataType.NEWSFEED,RssDataType.PRIVATE -> {
if(title?.length ?: 0 > 30) title?.substring(0,30).plus("...") else title ?: "" if(title?.length ?: 0 > 30) title?.substring(0,30).plus("...") else title ?: ""
} }
else -> title ?: "" else -> title ?: ""

View File

@ -160,7 +160,7 @@ open class BWebview : GeckoView {
var lastDomain : String = "" var lastDomain : String = ""
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("=")) {

View File

@ -26,21 +26,25 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<TextView <TextView
android:layout_margin="@dimen/_9sp"
android:padding="@dimen/_26sp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
android:id="@+id/title" android:id="@+id/title"
android:gravity="center"
android:singleLine="false" android:singleLine="false"
android:background="#000" android:background="#000"
android:textSize="@dimen/_20sp" android:textSize="@dimen/_26sp"
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"/>
<TextView <TextView
android:padding="@dimen/_20sp"
app:layout_constraintTop_toBottomOf="@id/title" app:layout_constraintTop_toBottomOf="@id/title"
android:id="@+id/date" android:id="@+id/date"
android:gravity="center_vertical|right" android:gravity="center_vertical|right"
android:singleLine="false" android:singleLine="false"
android:background="#000" android:background="#000"
android:textSize="@dimen/_20sp" android:textSize="@dimen/_14sp"
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"/>
@ -63,11 +67,13 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<TextView <TextView
android:padding="@dimen/_20sp"
app:layout_constraintTop_toBottomOf="@id/cover" app:layout_constraintTop_toBottomOf="@id/cover"
android:id="@+id/desc" android:id="@+id/desc"
android:gravity="center_vertical|right"
android:singleLine="false" android:singleLine="false"
android:background="#000" android:background="#000"
android:textSize="@dimen/_20sp" android:textSize="@dimen/_14sp"
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"/>
@ -90,11 +96,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<TextView <TextView
android:padding="@dimen/_20sp"
app:layout_constraintTop_toBottomOf="@id/screen" app:layout_constraintTop_toBottomOf="@id/screen"
android:id="@+id/link" android:id="@+id/link"
android:singleLine="false" android:singleLine="false"
android:background="#000" android:background="#000"
android:textSize="@dimen/_20sp" android:textSize="@dimen/_9sp"
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"/>

View File

@ -3,16 +3,18 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:id="@+id/colorInputLayout" android:id="@+id/colorInputLayout"
android:layout_width="@dimen/oneNinetySix" android:layout_width="@dimen/oneNinetySix"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="inpout text" android:hint="inpout text"
android:orientation="horizontal"
app:boxBackgroundColor="?attr/colorSurface" app:boxBackgroundColor="?attr/colorSurface"
app:endIconMode="clear_text" app:endIconMode="clear_text"
android:gravity="right"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent">
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/input" android:id="@+id/input"
@ -20,6 +22,15 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:imeOptions="actionDone" android:imeOptions="actionDone"
android:inputType="text" /> android:inputType="text" />
<CheckBox
android:padding="0dp"
android:text="PRIVATE MODE"
android:textColor="@color/white"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:id="@+id/parivate_mode"
android:checked="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -27,7 +27,7 @@
<dimen name="_20sp">23sp</dimen> <dimen name="_20sp">23sp</dimen>
<dimen name="_14sp">17sp</dimen> <dimen name="_14sp">17sp</dimen>
<dimen name="_12sp">14sp</dimen> <dimen name="_12sp">14sp</dimen>
<dimen name="_9sp">8sp</dimen>
<!-- toolbar height --> <!-- toolbar height -->
<dimen name="toolbar_height">100dp</dimen> <dimen name="toolbar_height">100dp</dimen>