diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7806479c..c1f91334 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,6 +5,7 @@ plugins { id ("com.android.application") id ("kotlin-android") id ("io.realm.kotlin") + id ("kotlin-kapt") } android { @@ -110,6 +111,7 @@ dependencies { implementation("com.github.delight-im:Android-AdvancedWebView:v3.2.1") implementation(project(":library")) implementation(project(":utils")) + implementation( "com.github.bumptech.glide:glide:4.11.0") // implementation("org.mozilla.geckoview:geckoview:139.0.20250523173407") // https://mvnrepository.com/artifact/org.mozilla.geckoview/geckoview implementation("org.mozilla.geckoview:geckoview:139.0.20250523173407") diff --git a/app/src/main/assets/extensions/my_extension/background.js b/app/src/main/assets/extensions/my_extension/background.js index 44fd417f..c5144f01 100644 --- a/app/src/main/assets/extensions/my_extension/background.js +++ b/app/src/main/assets/extensions/my_extension/background.js @@ -1,40 +1,65 @@ - -browser.webRequest.onHeadersReceived.addListener( - function(details) { - let headers = details.responseHeaders || []; - // Cache-Control 헤더가 없거나 no-store, no-cache 등일 때 수정 - let found = false; - for (let header of headers) { - if (header.name.toLowerCase() === "cache-control") { - header.value = "public, max-age=31536000"; // 1년 캐시 - found = true; - } - } - if (!found) { - headers.push({name: "Cache-Control", value: "public, max-age=31536000"}); - } - return {responseHeaders: headers}; - }, - {urls: ["*://*/*.gif"], types: ["image"]}, - ["blocking", "responseHeaders"] -); -//const originalLog = console.log; -//console.log = function(...args) { -// // 메시지 가공 또는 네이티브로 전달 -// originalLog.apply(console, args); -// browser.runtime.sendNativeMessage("browser", args); -//}; - -browser.webRequest.onBeforeRequest.addListener( - function(details) { - return { cancel: true }; - }, - { urls: ["*://*/*.gif"], types: ["image"] }, - ["blocking"] -); -//window.addEventListener('error', function(event) { -// if (event.message && event.message.includes('No impl for message: MozAfterPaint')) { -// // 앱으로 오류 신호 전달 -// browser.runtime.sendMessage({ type: 'RELOAD_REQUEST' }); +//const port = browser.runtime.connectNative("browser"); +//// 모든 요청을 가로챔 +//browser.webRequest.onCompleted.addListener(async (details) => { +// // 원래 요청 URL +// const url = details.url; +// try { +// // 실제 데이터 fetch (credentials, 쿠키 등 필요시 옵션 맞춤) +// const res = await fetch(url, {credentials: "include"}); +// const blob = await res.blob(); +// // 데이터 -> ArrayBuffer +// const arrayBuffer = await blob.arrayBuffer(); +// // base64로 변환 +// const base64 = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer))); +// // 네이티브 앱에게 전달 +// port.postMessage(JSON.stringify({type:"CACAHE",msg:msg , url: url, data: base64})); +//// browser.runtime.sendNativeMessage( +//// "browser", // 등록한 네이티브 앱 id +//// { url: url, data: base64 } +//// ); +// } catch(e) { +// // 에러 처리 +// console.error(e); // } -//}); \ No newline at end of file +//}, {urls: [""]}); +// +//// +////browser.webRequest.onHeadersReceived.addListener( +//// function(details) { +//// let headers = details.responseHeaders || []; +//// // Cache-Control 헤더가 없거나 no-store, no-cache 등일 때 수정 +//// let found = false; +//// for (let header of headers) { +//// if (header.name.toLowerCase() === "cache-control") { +//// header.value = "public, max-age=31536000"; // 1년 캐시 +//// found = true; +//// } +//// } +//// if (!found) { +//// headers.push({name: "Cache-Control", value: "public, max-age=31536000"}); +//// } +//// return {responseHeaders: headers}; +//// }, +//// {urls: ["*://*/*.gif"], types: ["image"]}, +//// ["blocking", "responseHeaders"] +////); +//////const originalLog = console.log; +//////console.log = function(...args) { +////// // 메시지 가공 또는 네이티브로 전달 +////// originalLog.apply(console, args); +////// browser.runtime.sendNativeMessage("browser", args); +//////}; +//// +////browser.webRequest.onBeforeRequest.addListener( +//// function(details) { +//// return { cancel: true }; +//// }, +//// { urls: ["*://*/*.gif"], types: ["image"] }, +//// ["blocking"] +////); +////window.addEventListener('error', function(event) { +//// if (event.message && event.message.includes('No impl for message: MozAfterPaint')) { +//// // 앱으로 오류 신호 전달 +//// browser.runtime.sendMessage({ type: 'RELOAD_REQUEST' }); +//// } +////}); \ No newline at end of file diff --git a/app/src/main/assets/extensions/my_extension/fdfdfdf.html b/app/src/main/assets/extensions/my_extension/fdfdfdf.html index 0a769e4a..7c2a90fc 100644 --- a/app/src/main/assets/extensions/my_extension/fdfdfdf.html +++ b/app/src/main/assets/extensions/my_extension/fdfdfdf.html @@ -1,3029 +1,93 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NH멤버스 팟 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -본문 바로가기 - - - - - -
- - - -
-
-
-
-
보유 포인트
-
- - - - - - 48,004 - - - P - -
-
-
-
-
- 8월 소멸 예정 포인트 -
- -
-
소멸 포인트 복구불가 안내
-

소멸된 포인트는 복구되지 않으며, 포인트 내역에서 조회하실 수 있습니다.

- -
-
-
- - -
-
-
- 당월 적립 포인트 -
- -
-
적립포인트 유효기간 안내
-

제휴사를 통해 적립된 포인트 및 이벤트 참여로 적립된 포인트는 유효기간이 있으니, 참고하시기 바랍니다.

- -
-
-
-
- - - 0 - - - P -
-
-
-
- -
-
-
-
-

이용내역

- -
-
- - - - - - - - - -
-
- -
- -
- -
- -
- -
- -
- - -
- -
-
-
- - -
-
- -
- -
- -
- -
- - - - -
- -
- - -
- -
-
-
- - - - -
-
- - -
- -
- -
-
-
+video-item ::>
+ + + + + + +
IPZZ-574 I Didn't Know About My Wife's Twisted Sexual Habits... My Beloved Wife, Who Is Usually Kind, Was A Masochistic Slave Trained By A Sadistic Neighbor. Kana Momonogi
+
+ +
+ 08/07/2025 | 4260 | 2602 +
+ - - - -
-
-
-
-

조회기간 선택

-
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
- -
- - 날짜 선택 -
-
- - - - -
- -
- - 날짜 선택 -
-
-
-

최대 조회 기간은 1년이에요.

-
-
- - -
-
+
+
+ 6
-
-
- - - - - - - - - - - - - -
-
-
-
- -
+ -
-
- - -
-
-
- -
- -
+ -
-
- - - -
-
-
-
-

다른 방법으로 본인인증하기

-
- -
-
- - - - - - -
-
- NH농협카드 / NHOnePASS 인증이란? -
- - -
- NH농협카드 인증이란? -

- 본인 명의의 NH농협 신용카드 또는 체크카드를 통해 본인임을 확인하는 서비스
(법인카드, 가족카드, - 선불카드 이용불가)
인증방식 : 간편인증(올원페이 인증), 일반인증(ARS 인증), 홈페이지 인증 - 총3가지 방식 제공 -

- NHOnePASS 인증이란? -

- NH 스마트뱅킹에 등록한 간편비밀번호, 지문(FaceID), 인증서를 통해 편리하게 본인확인 및 로그인할 수 있는 - 서비스
※ NH스마트뱅킹 앱이 설치된 디바이스에서만 이용가능 -

- -
- -
-
-
- -
+ - -
-
- - -
- -
-
-
-
-
- -
- -
+
+ SM
-
-
- - - - - -
-
-
-
- 회원가입을 중단하고 로그인 페이지로
이동하시겠어요? -
- - -
+ -
-
- - - -
-
-
- -
- 본인확인을 중단 하시겠어요? -
- -
+ -
- - - - - - - - \ No newline at end of file +
+ +
+ +
+
+ + + + 2025-07-23 11:22:20.062 26023-26023 Lunatic bums.lunatic.launcher E + + + + + + + + + + + + + + + 2025-07-23 11:22:20.062 26023-26023 Lunatic bums.lunatic.launcher E + + + + + + + + + +
Download Magnet 3.4gbS: 41L: 667 23/07/25Decen
Download Magnet 1.3gbS: 30L: 6 22/07/25
Download Magnet 5.3gbS: 60L: 23 22/07/25
+
+
+
\ No newline at end of file diff --git a/app/src/main/assets/extensions/my_extension/manifest.json b/app/src/main/assets/extensions/my_extension/manifest.json index bce7f3a4..dfb5b5c1 100644 --- a/app/src/main/assets/extensions/my_extension/manifest.json +++ b/app/src/main/assets/extensions/my_extension/manifest.json @@ -22,7 +22,6 @@ "nativeMessagingFromContent", "geckoViewAddons", "webRequest", - "webRequestBlocking", - "*://*/*.gif" + "webRequestBlocking" ] } diff --git a/app/src/main/assets/extensions/my_extension/messaging.js b/app/src/main/assets/extensions/my_extension/messaging.js index 38b0ebc4..f9c3b99a 100644 --- a/app/src/main/assets/extensions/my_extension/messaging.js +++ b/app/src/main/assets/extensions/my_extension/messaging.js @@ -1,4 +1,4 @@ - +const list = ["?page=2","?page=3","?page=4","?page=5","?page=6"]; const port = browser.runtime.connectNative("browser"); port.onMessage.addListener(response => { var type= response["type"]; @@ -285,5 +285,126 @@ if (port) { ) } + if (document.querySelectorAll('[class^="col-md-4 mb-4 video-item"]').length > 1) { + var datas = [] + document.querySelectorAll('[class^="col-md-4 mb-4 video-item"]').forEach(function (e) { + var date = 0 + try { + const dateString = e.querySelector('[class^="mb-2"]').querySelector("a").textContent.trim(); + + const [day, month, year] = dateString.split("/").map(Number); + date = new Date(year, month - 1, day).getTime(); + }catch (e) { + + } + var actor = "" + try { + actor = e.querySelector('[class^="mb-1"]').getAttribute("alt").trim() + }catch (e) { + + } + var desc = "" + try { + e.querySelectorAll('[class^="badge badge-"]').forEach(function (e) { + try { + if (Number(e.textContent) > 0) { + + }else { + if (desc.length > 0) { + desc += "," + } + desc += e.textContent.trim() + } + }catch (e) {} + } + ) + }catch (e) { + + } + var thumb = "" + try { + thumb = e.querySelector("td").querySelector("a").getAttribute('data-link') + }catch (e) { + + } + var magnet = "" + try { + e.querySelectorAll("td").forEach(function (e) { + e.querySelectorAll("a").forEach(function (e) { + if(e.getAttribute("href").startsWith("magnet")) { + magnet = e.getAttribute("href").replaceAll("&", "&"); + } + }) + }) + }catch (e) { + + } + + var title = ""; + try { + title = e.querySelector(".name").querySelector("a").querySelector("span").textContent.trim(); + }catch (e) { + + } + var originPage = "" + try { + + originPage = location.protocol + "//" + location.hostname + e.querySelector(".name").querySelector("a").getAttribute("href"); + }catch (e) { + + } + var screenshots = "" + try { + e.querySelectorAll("a").forEach(function (e) { + if(e.getAttribute("href").search("screenshots") > -1) { + screenshots = e.getAttribute("href"); + } + }) + }catch (e) { + + } + datas.push({ + "title" : title, + "description" : desc, + "originPage" : originPage, + "magnet" : magnet, + "thumbnail" : thumb, + "pubDate" : date, + "screenshots" : screenshots, + "chosung" : "", + "category" : "PRIVATE" + }); + }) + sendMessage( + { + type: "PRIVATES", + privates: datas + } + ); + + gotoNext() + } + },1500) +} + +function gotoNext() { + if (location.href.search("page") < 0) { + targetUrl = location.protocol + "//" + location.hostname + "/" + list[0] + }else { + var targetUrl = "" + for (i = 0; i < list.length - 1; i++) { + try { + if (location.href.search(list[i]) > -1) { + targetUrl = location.protocol + "//" + location.hostname + list[i + 1] + } + }catch (e) { + console.error(e) + } + + } + } + if (targetUrl.length > 5) { + setTimeout(function () {location.href = targetUrl},3000) + } } \ No newline at end of file diff --git a/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt b/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt index 416de6ae..acd92998 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/LauncherActivity.kt @@ -50,6 +50,7 @@ import androidx.core.net.toUri import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.isVisible import androidx.core.view.updatePadding import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.OneTimeWorkRequest @@ -66,7 +67,7 @@ import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS import bums.lunatic.launcher.helpers.Constants.Companion.widgetHostId import bums.lunatic.launcher.helpers.HeadsetActionButtonReceiver import bums.lunatic.launcher.helpers.PrefLong -import bums.lunatic.launcher.home.LauncherHome +import bums.lunatic.launcher.home.RssHome import bums.lunatic.launcher.home.RssViewBuilder import bums.lunatic.launcher.model.RssData import bums.lunatic.launcher.model.RssDataType @@ -612,7 +613,7 @@ internal class LauncherActivity : CommonActivity() { when(id) { R.id.feeds -> { supportFragmentManager.beginTransaction() - .replace(R.id.fragment_container, LauncherHome()) + .replace(R.id.fragment_container, RssHome()) .commit() } R.id.books ->{ @@ -728,8 +729,12 @@ internal class LauncherActivity : CommonActivity() { override fun handleOnBackPressed() { val currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) when(currentFragment) { - is LauncherHome ->{ - currentFragment.doNextPage() + is RssHome ->{ + if (currentFragment.binding.layoutRssSummary.root.isVisible) { + currentFragment.openGecko("") + } else { + currentFragment.doNextPage() + } } } } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/ExtHahMap.java b/app/src/main/kotlin/bums/lunatic/launcher/home/ExtHahMap.java index 9bc0e898..b0ed8b1f 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/ExtHahMap.java +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/ExtHahMap.java @@ -1,31 +1,31 @@ -//import androidx.annotation.Nullable; -// -//import java.util.HashMap; -// - -import androidx.annotation.Nullable; - -import java.util.HashMap; - -////package bums.lunatic.launcher.home; -//// ////import androidx.annotation.Nullable; //// ////import java.util.HashMap; //// -public class ExtHahMap extends HashMap { - @Nullable - @Override - public Object put(String key, Object value) { - if (value instanceof String) { - if (((String) value).length() > 0) { - - } else { - - } - }else { - return super.put(key, value); - } - } -} - +// +//import androidx.annotation.Nullable; +// +//import java.util.HashMap; +// +//////package bums.lunatic.launcher.home; +////// +//////import androidx.annotation.Nullable; +////// +//////import java.util.HashMap; +////// +//public class ExtHahMap extends HashMap { +// @Nullable +// @Override +// public Object put(String key, Object value) { +// if (value instanceof String) { +// if (((String) value).length() > 0) { +// +// } else { +// +// } +// }else { +// return super.put(key, value); +// } +// } +//} +// 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 11173440..15b61fe8 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/GeckoWeb.kt @@ -1,12 +1,17 @@ package bums.lunatic.launcher.home +import android.app.DownloadManager import android.content.Context import android.content.Intent +import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.net.Uri +import android.os.Environment import android.os.Handler import android.os.Looper import android.os.Message import android.util.AttributeSet +import android.util.Base64 import android.util.Log import android.view.KeyEvent import android.view.KeyEvent.ACTION_UP @@ -18,14 +23,23 @@ 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.View import android.widget.ProgressBar +import android.widget.Toast +import androidx.appcompat.app.AlertDialog import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime +import bums.lunatic.launcher.tokiz.data.HistoryManager +import bums.lunatic.launcher.tokiz.data.model.History +import bums.lunatic.launcher.tokiz.data.model.PortMessage import bums.lunatic.launcher.tokiz.view.BWebview import bums.lunatic.launcher.tokiz.view.JxEvent import bums.lunatic.launcher.utils.Blog +import bums.lunatic.launcher.utils.afterDay +import bums.lunatic.launcher.workers.WorkersDb import com.google.gson.Gson import org.json.JSONException import org.json.JSONObject +import org.jsoup.Jsoup import org.mozilla.gecko.util.ThreadUtils import org.mozilla.geckoview.ExperimentDelegate import org.mozilla.geckoview.GeckoResult @@ -39,13 +53,18 @@ import org.mozilla.geckoview.WebExtension.MessageDelegate import org.mozilla.geckoview.WebExtension.PortDelegate import org.mozilla.geckoview.WebExtensionController.AddonManagerDelegate import org.mozilla.geckoview.WebRequestError +import java.io.File +import java.text.SimpleDateFormat class GeckoWeb : BWebview { constructor(context: Context?) : super(context) { buildWeb() } - - + var decoViews = arrayListOf() + override fun setVisibility(visibility: Int) { + super.setVisibility(visibility) + decoViews.forEach { it.visibility = visibility } + } constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { buildWeb() @@ -54,6 +73,7 @@ class GeckoWeb : BWebview { val mPortNam = "browser" val extPath = "resource://android/assets/extensions/my_extension/" val extId = "messaging@booktoki468.com" + private fun buildWeb() { getRuntime()?.let { val session: GeckoSession = GeckoSession() @@ -87,7 +107,7 @@ class GeckoWeb : BWebview { var lastedUrl: String? = null var canGoBack: Boolean? = null var mPort: WebExtension.Port? = null - + var mCaache : WebExtension.Port? = null object WebExtensionInfo { val mPortNam = "browser" val extPath = "resource://android/assets/extensions/my_extension/" @@ -238,6 +258,32 @@ class GeckoWeb : BWebview { return super.onRecordMalformedConfigurationEvent(feature, part) } } + + fun showImageDownloadDialog(context: Context, imageUrl: Uri) { + AlertDialog.Builder(context) + .setTitle("이미지 다운로드") + .setMessage("이미지를 저장하시겠습니까?") + .setPositiveButton("저장") { _, _ -> + downloadImage(context, imageUrl) + } + .setNegativeButton("취소", null) + .show() + } + + fun downloadImage(context: Context, url: Uri) { + val fileName = url.lastPathSegment ?: "${SimpleDateFormat("yyyyMMddHHmmsss")}.jpg" + val request = DownloadManager.Request(url) + request.setTitle(fileName) + request.setDescription("이미지 다운로드 중...") + request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName) + // 네트워크타입, 알림설정 등 옵션 추가 가능 + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) + + val dm = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + dm.enqueue(request) + Toast.makeText(context, "다운로드 시작: $fileName", Toast.LENGTH_SHORT).show() + } + fun getFilterF() = String(java.util.Base64.getMimeDecoder().decode("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=".toByteArray())) val contentDelegate = object : GeckoSession.ContentDelegate { override fun onTitleChange( session: GeckoSession, @@ -260,6 +306,21 @@ class GeckoWeb : BWebview { super.onFirstContentfulPaint(session) } + + override fun onContextMenu( + session: GeckoSession, + screenX: Int, + screenY: Int, + element: GeckoSession.ContentDelegate.ContextElement + ) { + if (element.type == GeckoSession.ContentDelegate.ContextElement.TYPE_IMAGE) { + Uri.parse(element.srcUri)?.let { + showImageDownloadDialog(context,it) + } + } + + super.onContextMenu(session, screenX, screenY, element) + } } val progressDelegate = object : GeckoSession.ProgressDelegate { override fun onSecurityChange( @@ -284,15 +345,20 @@ class GeckoWeb : BWebview { } override fun onPageStart(session: GeckoSession, url: String) { super.onPageStart(session, url) - if (url?.contains("reddit.app.link") == true) { - session.stop() - Uri.parse(url)?.let { uri -> - context.startActivity(Intent().apply { - action = Intent.ACTION_VIEW - data = uri - }) - } + if (url.contains(getFilterF()) && url.contains("jpg") == false) { + 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) { @@ -305,6 +371,7 @@ class GeckoWeb : BWebview { } } + } } @@ -328,7 +395,18 @@ class GeckoWeb : BWebview { ): GeckoResult? { Blog.LOGE("GeckoView", "onNewSession: $session from WebExtension") - + Uri.parse(uri)?.let { + 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 + }) + } + } return super.onNewSession(session, uri) } @@ -343,6 +421,9 @@ class GeckoWeb : BWebview { Blog.LOGE("GeckoView", "현재 session: $session") url?.let { url -> + if (url?.contains(getFilterF()) == true && url.contains("jpg") == false) { + this@GeckoWeb.visibility = View.INVISIBLE + } if (url.split("//").size > 1) { url.replace("//", "/").replace("https:/", "https://").let { Blog.LOGE("url >> ${url} , it >>> ${it}") @@ -371,23 +452,129 @@ class GeckoWeb : BWebview { message: Any, port: WebExtension.Port ) { Blog.LOGE("PortDelegate", "Received message from extension: $message") + if (message is String && message.contains("type")) { + try { + var lPortMessage = + Gson().fromJson(message, PortMessage::class.java) + when(lPortMessage.type) { + "getListResult" -> { + } + "BookContents"->{ + + } + "NotRegistered" -> { + } + "WebtoonContents"-> { + } + "MSG" -> { + } + "SHOWVIEWER" -> { + } + "PRIVATES"->{ + lPortMessage.privates?.forEach { + Blog.LOGE("Item screenshots >>> ${it.screenshots}") + it.pubDate = afterDay(it.pubDate) + WorkersDb.insertData(it) + } + } + "PagerContents" -> { + if (lPortMessage.contents?.isNotEmpty() == true) { + + } + } + else -> { + + } + } + } catch (e: Exception) { + e.printStackTrace() + } + + } + } + + + override fun onDisconnect(port: WebExtension.Port) { + // This port is not usable anymore. + + + mPort = null + + + } + } + + val cacheDelegate: PortDelegate = + object : PortDelegate { + override fun onPortMessage( + message: Any, port: WebExtension.Port + ) { + Blog.LOGE("cacheDelegate", "cacheDelegate message : $message") } override fun onDisconnect(port: WebExtension.Port) { // This port is not usable anymore. - if (port === mPort) { - mPort = null + if (port === mCaache) { + mCaache = null } } } + fun onReceiveFromExtension(message: JSONObject) { + val url = message.getString("url") + val dataBase64 = message.getString("data") + val host = Uri.parse(url).host!! + val cacheDir = File(context.filesDir, "webcache/$host") + if (!cacheDir.exists()) cacheDir.mkdirs() + + // 파일명 생성 (중복처리 필요) + val fileName = filenameFromUrl(url) + val resourceFile = File(cacheDir, fileName) + val rawData = Base64.decode(dataBase64, Base64.DEFAULT) + resourceFile.writeBytes(rawData) + } + + + + fun filenameFromUrl(url: String): String { + // URL을 파싱 + val uri = Uri.parse(url) + // 경로 마지막 세그먼트 (예시: /images/logo.png → logo.png) + var filename = uri.lastPathSegment ?: "index.html" + + // 쿼리 파라미터 등 URL이 붙은 경우 처리 (예: index.html?version=2) + if (filename.contains("?")) { + filename = filename.substringBefore("?") + } + if (filename.isEmpty() || filename.endsWith("/")) { + filename = "index.html" + } + + // 파일명에 사용할 수 없는 문자 제거(윈도우, 리눅스, 맥 등 호환) + filename = filename.replace(Regex("[\\\\/:*?\"<>|]"), "_") + + // 너무 긴 파일명은 자르기 + val maxLength = 100 + if (filename.length > maxLength) { + val ext = filename.substringAfterLast('.', "") + filename = filename.take(maxLength - ext.length - 1) + + if (ext.isNotBlank()) ".$ext" else "" + } + + return filename + } + + val messageDelegate: MessageDelegate = object : MessageDelegate { override fun onConnect(port: WebExtension.Port) { - mPort = port - mPort!!.setDelegate(portDelegate) + Blog.LOGE("onConnect port >>> ${port.name}") + if (port != null) { + mPort = port + mPort!!.setDelegate(portDelegate) + } } override fun onMessage( @@ -401,11 +588,8 @@ class GeckoWeb : BWebview { ) return super.onMessage(nativeApp, message, sender) } - - } - fun onStart() { } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/LauncherHome.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt similarity index 67% rename from app/src/main/kotlin/bums/lunatic/launcher/home/LauncherHome.kt rename to app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt index cea16954..5735ca7c 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/LauncherHome.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/RssHome.kt @@ -19,8 +19,9 @@ package bums.lunatic.launcher.home import android.annotation.SuppressLint -import android.content.Context +import android.content.Intent import android.content.SharedPreferences +import android.net.Uri import android.os.Build import android.os.Bundle import android.os.Handler @@ -29,9 +30,11 @@ import android.view.LayoutInflater import android.view.PointerIcon import android.view.View import android.view.ViewGroup +import android.widget.ImageView import android.widget.Toast import androidx.annotation.NonNull -import androidx.annotation.RequiresApi +import androidx.core.view.isVisible +import androidx.databinding.BindingAdapter import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.DividerItemDecoration @@ -48,7 +51,6 @@ import bums.lunatic.launcher.home.adapters.SwipeToDeleteCallback import bums.lunatic.launcher.model.RssData import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.model.WeatherForcast -import bums.lunatic.launcher.openClient import bums.lunatic.launcher.openReddit import bums.lunatic.launcher.openYouTube import bums.lunatic.launcher.tokiz.view.JxEvent @@ -57,10 +59,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 com.bumptech.glide.Glide import com.google.android.material.imageview.ShapeableImageView 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 @@ -70,7 +75,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch -internal class LauncherHome : Fragment() { +internal class RssHome : Fragment() { lateinit var binding: LauncherHomeBinding private lateinit var fragManager: FragmentManager @@ -78,18 +83,17 @@ internal class LauncherHome : Fragment() { private var shouldResume = true companion object { - var home: LauncherHome? = null + var home: RssHome? = null var lastedFinishedPageUrl: String = "" } - val UPDATE_DELAY = 5L val commandHandler = Handler(Looper.getMainLooper()) val infoUpdate = Runnable { chooseAdpater() } var result: RealmResults? = null val nomoreShowCount = 5 fun rssStateVote() = (lasted?.filter { it.vote == true }?.size ?: -1) == (lasted?.size ?: 0) - var lasted: List? = null + var lasted: ArrayList = arrayListOf() var infosJob: Job? = null var rssId = "" lateinit var mRssAdapter: RssItemAdapter @@ -105,7 +109,9 @@ internal class LauncherHome : Fragment() { gestureDistance: Double ): Boolean { Blog.LOGE("") - + if (imageView){ + openGecko("") + } return true } @@ -115,6 +121,9 @@ internal class LauncherHome : Fragment() { gestureDuration: Long, gestureDistance: Double ): Boolean { + if (imageView){ + openGecko("") + } Blog.LOGE("") return true } @@ -202,19 +211,27 @@ internal class LauncherHome : Fragment() { } } when(rss.category()) { - //RssDataType.GURU,RssDataType.MOST, - RssDataType.REDDIT_NSFW -> { + RssDataType.REDDIT_NSFW,RssDataType.PRIVATE -> { v.findViewById(R.id.circle_preview)?.let { - if (it.visibility == View.GONE) { - it.visibility = View.VISIBLE - it.postDelayed({ - it.visibility = View.GONE - }, 2000L) + if (RssDataType.PRIVATE.equals(rss.category()) && imageView) { + openGecko("") } else { - if (RssDataType.REDDIT_NSFW.equals(rss.category())) { - openReddit(rss.originPage()) + if (it.visibility == View.GONE) { + it.visibility = View.VISIBLE + it.postDelayed({ + it.visibility = View.GONE + }, 2000L) } else { - openGecko(rss.originPage()) + if (RssDataType.REDDIT_NSFW.equals(rss.category())) { + openReddit(rss.originPage()) + } else if (RssDataType.PRIVATE.equals(rss.category())) { + startActivity(Intent().apply { + action = Intent.ACTION_VIEW + data = Uri.parse(rss.originPage) + }) + } else { + openGecko(rss.originPage()) + } } } } @@ -238,15 +255,38 @@ internal class LauncherHome : Fragment() { } fun openGecko(originPage: String) { - rssId = originPage - targetList.clear() + if (!imageView) { + rssId = originPage + targetList.clear() - var setString = hashSetOf() - setString.addAll(rssList) - setString.removeAll { it.equals(rssId) } + var setString = hashSetOf() + setString.addAll(rssList) + setString.removeAll { it.equals(rssId) } - targetList.addAll(setString) - binding.geckoWeb.loadUrl(rssId) + targetList.addAll(setString) + binding.geckoWeb.loadUrl(rssId) + } else { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { + lasted?.removeFirst()?.let { + binding.layoutRssSummary.root.visibility = View.VISIBLE + binding.layoutRssSummary.title.text = it.title() + binding.layoutRssSummary.desc.text = it.description() + binding.layoutRssSummary.link.text = it.originPage() + loadImage(binding.layoutRssSummary.cover,it.thumbnailUrl()) + loadImage(binding.layoutRssSummary.screen,it.getScreen()) + } + } + +// targetList.clear() +// lasted?.forEach { +// it.thumbnail?.let { +// targetList.add(it) +// } +// } +// rssId = targetList.removeAt(0) +// binding.geckoWeb.loadUrl(rssId) + } } @SuppressLint("ClickableViewAccessibility") @@ -272,6 +312,54 @@ internal class LauncherHome : Fragment() { return@setOnTouchListener false } } + binding.vote.setOnClickListener { + if (binding.geckoWeb.isVisible) { + vote() + } + } + binding.test.setOnClickListener { + if(binding.geckoWeb.isVisible) { + binding.geckoWeb.visibility = View.GONE + + } + binding.geckoWeb.visibility = View.GONE + binding.geckoWeb.loadUrl("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=") + } + + binding.hide.setOnClickListener { + if (binding.geckoWeb.isVisible) { + WorkersDb.getRealm().apply { + writeBlocking { + val result = query().query("originPage == $0", rssId).find() + if (result.size > 0) { + result.forEach { + if(it.vote) { + it.vote = false + } + } + } + } + } + doNextPage() + } + } + + binding.home.setOnClickListener { + if (binding.geckoWeb.isVisible) { + binding.geckoWeb.visibility = View.GONE + } + binding.layoutRssSummary.root.visibility = View.GONE + queryInfos() + } + + + binding.bookmark.setOnClickListener { + binding.layoutRssSummary.root.visibility = View.GONE + queryVotes() + } + binding.prv.setOnClickListener { + queryPrevate() + } queryInfos() binding.geckoWeb.progress = binding.progressBar binding.geckoWeb.jxInteface = { jxEvent -> @@ -289,20 +377,19 @@ internal class LauncherHome : Fragment() { } } } - - val nullCursor = PointerIcon.getSystemIcon(context!!, PointerIcon.TYPE_NULL) + val nullCursor = PointerIcon.getSystemIcon(requireContext(), PointerIcon.TYPE_NULL) binding.root.setPointerIcon(nullCursor) - + binding.geckoWeb.decoViews.add(binding.hide) + binding.geckoWeb.decoViews.add(binding.vote) + binding.geckoWeb.decoViews.add(binding.progressBar) return binding.root } - - fun vote(){ Blog.LOGE("Arrow Center Click") WorkersDb.getRealm().apply { writeBlocking { - val result = query().query("originPage == $0", rssId).find() + val result = query().query(if(imageView)"thumbnail == $0" else "originPage == $0", rssId).find() if (result.size > 0) { result.forEach { it.vote = true } } @@ -316,10 +403,10 @@ internal class LauncherHome : Fragment() { fun doNextPage() { WorkersDb.getRealm().apply { writeBlocking { - val result = query().query("originPage == $0", rssId).find() + val result = query().query(if(imageView)"thumbnail == $0" else "originPage == $0", rssId).find() if (result.size > 0) { result.forEach { - it.read = it.read + nomoreShowCount + it.read = it.read + nomoreShowCount } } } @@ -357,30 +444,48 @@ internal class LauncherHome : Fragment() { mRssDataResult?.asFlow()?.let { flow -> infosJob = CoroutineScope(Dispatchers.IO).launch { flow.collect { changes: ResultsChange -> - commandHandler.removeCallbacks(infoUpdate) - WorkersDb.getRealm().apply { - lasted = copyFromRealm(changes.list) + when(changes) { + is InitialResults -> { + commandHandler.removeCallbacks(infoUpdate) + WorkersDb.getRealm().apply { + lasted.clear() + lasted.addAll(copyFromRealm(changes.list)) + } + commandHandler.post(infoUpdate) + } + is UpdatedResults -> { + CoroutineScope(Dispatchers.Main).launch { + changes.changeRanges.forEach { + mRssAdapter.notifyItemRangeChanged(it.startIndex, it.length) + } + } + } + } - commandHandler.postDelayed(infoUpdate, UPDATE_DELAY) } } infosJob?.start() } } - + fun queryPrevate() { + imageView = true + beforeQuery() + updateQuery(WorkersDb.getPrivate()) + } fun queryVotes() { + imageView = false beforeQuery() updateQuery(WorkersDb.getVotedRss()) } - + var imageView = false fun queryInfos( - //RssDataType.GURU, RssDataType.MOST, - filter: Collection? = arrayListOf(RssDataType.REDDIT_NSFW), noLimit: Boolean = false + filter: Collection? = arrayListOf(RssDataType.REDDIT_NSFW,RssDataType.PRIVATE), noLimit: Boolean = false ) { + imageView = false beforeQuery() var rQ = WorkersDb.getRealm().query().query("read < $0", nomoreShowCount).distinct("originPage", "title") 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) } @@ -401,16 +506,16 @@ internal class LauncherHome : Fragment() { Blog.LOGE("onViewCreated()") - fragManager.addOnBackStackChangedListener { - Blog.LOGE("addOnBackStackChangedListener()") - shouldResume = if (fragManager.backStackEntryCount == 0) { - binding.root.visibility = View.VISIBLE - true - } else { - binding.root.visibility = View.GONE - false - } - } +// fragManager.addOnBackStackChangedListener { +// Blog.LOGE("addOnBackStackChangedListener()") +// shouldResume = if (fragManager.backStackEntryCount == 0) { +// binding.root.visibility = View.VISIBLE +// true +// } else { +// binding.root.visibility = View.GONE +// false +// } +// } enableSwipeToDeleteAndUndo() } @@ -475,8 +580,6 @@ internal class LauncherHome : Fragment() { override fun onResume() { super.onResume() - val nullCursor = PointerIcon.getSystemIcon(context!!, PointerIcon.TYPE_NULL) - binding.root.setPointerIcon(nullCursor) if (shouldResume) { } @@ -488,7 +591,21 @@ internal class LauncherHome : Fragment() { } - - - +@BindingAdapter("imageUrl") +fun loadImage(imageView: ImageView, url: String?) { + url?.let { + if (it.length > 4) { + Blog.LOGE("loadImage >>> $it") + Glide.with(imageView.context) + .load(url) + .fitCenter() + .into(imageView) + imageView.visibility = View.VISIBLE + } else { + imageView.visibility = View.GONE + } + } ?: { + imageView.visibility = View.GONE + } +} diff --git a/app/src/main/kotlin/bums/lunatic/launcher/home/adapters/RssItemAdapter.kt b/app/src/main/kotlin/bums/lunatic/launcher/home/adapters/RssItemAdapter.kt index acde5756..84dbb7bc 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/home/adapters/RssItemAdapter.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/home/adapters/RssItemAdapter.kt @@ -219,8 +219,8 @@ internal class RssItemAdapter ( v: View, event: MotionEvent ): Boolean { - Blog.LOGE("event.device.name >>> ${event.device.name}") - if (event.device.name?.contains("JX-12",true) == true|| event.device.name?.equals("J06",true) == true) { + if (event.device != null && event.device.name != null && (event.device.name?.contains("JX-12",true) == true|| event.device.name?.equals("J06",true) == true)) { + Blog.LOGE("event.device.name >>> ${event.device.name}") return true//mSimpleFingerGestures.onTouch(v,event) } else { return false diff --git a/app/src/main/kotlin/bums/lunatic/launcher/model/CommunityData.kt b/app/src/main/kotlin/bums/lunatic/launcher/model/CommunityData.kt index 42e22bb4..481cf866 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/model/CommunityData.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/model/CommunityData.kt @@ -1,5 +1,6 @@ package bums.lunatic.launcher.model +import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.JamoUtils import bums.lunatic.launcher.utils.afterDay import bums.lunatic.launcher.utils.beforeDayBy @@ -218,6 +219,12 @@ class RssData : RealmObject, RssDataInterface { var thumbnail : String? = null var pubDate : Long = 0L var category : String? = null + var magnet : String? = null + var screenshots : String? = null + fun getScreen() : String { + Blog.LOGE("getScreen $screenshots") + return screenshots ?: "" + } var chosung : String? = null var vote : Boolean = false @@ -232,15 +239,18 @@ class RssData : RealmObject, RssDataInterface { } else -> title ?: "" }.apply { + Blog.LOGE("title $this") chosung = JamoUtils.split(title).joinToString("") } } override fun thumbnailUrl(): String { + Blog.LOGE("thumbnail $thumbnail") return thumbnail ?: "" } override fun originPage(): String { + Blog.LOGE("originPage $originPage") return originPage ?: "" } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/model/RssDataInterface.kt b/app/src/main/kotlin/bums/lunatic/launcher/model/RssDataInterface.kt index 6c8a391e..3883f056 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/model/RssDataInterface.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/model/RssDataInterface.kt @@ -6,6 +6,7 @@ import bums.lunatic.launcher.helpers.PrefHelper enum class RssDataType { NO_DATA, + PRIVATE, YOUTUBE, NEWSFEED, // GURU, @@ -35,14 +36,14 @@ enum class RssDataType { fun defaultImgSize() = when (this) { YOUTUBE -> 200 - REDDIT_NSFW -> 360 + REDDIT_NSFW,PRIVATE -> 360 //,GURU,MOST else -> { 120 } } fun getDefaultVisibiliy() = when (this) { //,GURU,MOST - REDDIT_NSFW,NEWSFEED -> View.GONE + REDDIT_NSFW,PRIVATE -> View.GONE else -> { View.VISIBLE } } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/tokiz/BaseToki.kt b/app/src/main/kotlin/bums/lunatic/launcher/tokiz/BaseToki.kt index 73c855a0..9fc9626a 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/tokiz/BaseToki.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/tokiz/BaseToki.kt @@ -1174,7 +1174,6 @@ abstract class BaseToki : Fragment(), PagedTextViewInterface { } } } - } fun onLoadedContents(aContents: String) { diff --git a/app/src/main/kotlin/bums/lunatic/launcher/tokiz/data/model/ContentsPageInfo.kt b/app/src/main/kotlin/bums/lunatic/launcher/tokiz/data/model/ContentsPageInfo.kt index bfea2b39..9c11268e 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/tokiz/data/model/ContentsPageInfo.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/tokiz/data/model/ContentsPageInfo.kt @@ -1,5 +1,6 @@ package bums.lunatic.launcher.tokiz.data.model +import bums.lunatic.launcher.model.RssData import io.realm.kotlin.ext.realmListOf import io.realm.kotlin.types.RealmList import io.realm.kotlin.types.RealmObject @@ -10,6 +11,8 @@ class PortMessage { var bookInfos : PageInfosJ? = null var book : BookContents? = null var msg : String? = null + var contents : String? = null + var privates : ArrayList? = null } class BookContents { var chapterTitle : String? = null diff --git a/app/src/main/kotlin/bums/lunatic/launcher/tokiz/view/BWebview.kt b/app/src/main/kotlin/bums/lunatic/launcher/tokiz/view/BWebview.kt index 1ed83611..5c47e6f0 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/tokiz/view/BWebview.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/tokiz/view/BWebview.kt @@ -12,6 +12,7 @@ import bums.lunatic.launcher.tokiz.common.TouchArea import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.SimpleFingerGestures import org.mozilla.geckoview.GeckoView +import java.util.Base64 enum class JxEvent { SCROLL_UP, @@ -160,14 +161,19 @@ open class BWebview : GeckoView { var lastDomain : String = "" fun loadUrl(url: String) { + var nUrl = url + Blog.LOGE("url >>>> ${url}") + if (url.endsWith("=")) { + nUrl = String(Base64.getMimeDecoder().decode(url.toByteArray())) + } else if (url.startsWith("http") == false) { + nUrl = lastDomain + } if (this.isVisible == false) { this.visibility = View.VISIBLE } - Blog.LOGE("url >>>> ${url}") - var nUrl = url - if (url.startsWith("http") == false) { - nUrl = lastDomain - } + Blog.LOGE("nUrl >>>> ${nUrl}") + + nUrl?.let { url -> if (url.split("//").size > 1) { url.replace("//","/").replace("https:/","https://").let { diff --git a/app/src/main/kotlin/bums/lunatic/launcher/utils/DataUtils.kt b/app/src/main/kotlin/bums/lunatic/launcher/utils/DataUtils.kt index baaa113a..26002fed 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/utils/DataUtils.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/utils/DataUtils.kt @@ -8,6 +8,14 @@ import android.provider.ContactsContract.PhoneLookup import java.util.Calendar import java.util.Date +fun afterDay(date: Long): Long { + val cal: Calendar = Calendar.getInstance() + cal.setTime(Date(date)) + cal.add(Calendar.HOUR_OF_DAY, 23) + cal.add(Calendar.MINUTE, 53) + return cal.timeInMillis +} + fun before30Min(date: Date): Long { val cal: Calendar = Calendar.getInstance() cal.setTime(date) diff --git a/app/src/main/kotlin/bums/lunatic/launcher/utils/JsoupUtils.kt b/app/src/main/kotlin/bums/lunatic/launcher/utils/JsoupUtils.kt index 8e867163..728b8dc0 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/utils/JsoupUtils.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/utils/JsoupUtils.kt @@ -1,6 +1,6 @@ package bums.lunatic.launcher.utils -import bums.lunatic.launcher.home.LauncherHome.Companion.lastedFinishedPageUrl +import bums.lunatic.launcher.home.RssHome.Companion.lastedFinishedPageUrl import bums.lunatic.launcher.model.RssData import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.model.dateFormat 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 60349d6a..57920718 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/workers/WorkersDb.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/workers/WorkersDb.kt @@ -23,6 +23,7 @@ import bums.lunatic.launcher.model.LocationLog import bums.lunatic.launcher.model.NotificationItem import bums.lunatic.launcher.model.RssData import bums.lunatic.launcher.model.RssDataInterface +import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.model.TelegramBotUpdate import bums.lunatic.launcher.model.TelegramChat import bums.lunatic.launcher.model.TelegramData @@ -33,6 +34,7 @@ import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.JamoUtils import bums.lunatic.launcher.utils.beforeDay import bums.lunatic.launcher.utils.beforeOneDay +import com.google.gson.Gson import io.realm.kotlin.Realm import io.realm.kotlin.RealmConfiguration import io.realm.kotlin.UpdatePolicy @@ -86,9 +88,21 @@ object WorkersDb { getRealm().apply { this.writeBlocking { try { - if (query("originPage == $0", rssData.originPage).find().isEmpty()) { - this.copyToRealm(rssData, UpdatePolicy.ERROR) + if (rssData.category().equals(RssDataType.PRIVATE)) { + this.copyToRealm(rssData, UpdatePolicy.ALL) + Blog.LOGE("rssData >> $rssData ${rssData.getScreen()}") + } else { + if (query("originPage == $0", rssData.originPage).find() + .isEmpty() + ) { + this.copyToRealm(rssData, UpdatePolicy.ERROR) + } } + try { + query("originPage == $0",rssData.originPage).find()?.first()?.let { + Blog.LOGE("SAVED CHECK ${Gson().toJson(this.copyFromRealm(it))}") + } + }catch (e: Exception) {e.printStackTrace()} } catch (e : Exception) { } @@ -212,6 +226,9 @@ object WorkersDb { } } + fun getPrivate() = getRealm().query().query("category == $0 ", + RssDataType.PRIVATE.name).distinct("originPage", "title").sort("pubDate", Sort.DESCENDING) + fun getVotedRss() = getRealm().query().query("vote == $0", true).distinct("originPage", "title") fun getDeleteQuery( ) : RealmQuery{ diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml index 8b5f27e8..e4c2456a 100644 --- a/app/src/main/res/drawable/ic_delete.xml +++ b/app/src/main/res/drawable/ic_delete.xml @@ -1,8 +1,8 @@ + android:tint="@color/white"> diff --git a/app/src/main/res/layout/launcher_home.xml b/app/src/main/res/layout/launcher_home.xml index c8f1aec0..d21122b9 100644 --- a/app/src/main/res/layout/launcher_home.xml +++ b/app/src/main/res/layout/launcher_home.xml @@ -1,45 +1,146 @@ - - - + + android:layout_height="match_parent"> + + + + + + + + + + + + + - - - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_rss_summary.xml b/app/src/main/res/layout/layout_rss_summary.xml new file mode 100644 index 00000000..61a1687c --- /dev/null +++ b/app/src/main/res/layout/layout_rss_summary.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file