diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 981c606..c0ae2b6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -34,6 +34,10 @@
tools:ignore="QueryAllPackagesPermission" />
+
+
+
@@ -64,7 +68,6 @@
android:name=".LauncherActivity"
android:theme="@style/Theme.LunarLauncher.Starting"
android:launchMode="singleInstance"
- android:screenOrientation="portrait"
android:excludeFromRecents="true"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|screenLayout|layoutDirection"
android:windowSoftInputMode="adjustResize"
@@ -151,5 +154,7 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/java/android/print/PDFPrint.java b/app/src/main/java/android/print/PDFPrint.java
new file mode 100644
index 0000000..68c84fe
--- /dev/null
+++ b/app/src/main/java/android/print/PDFPrint.java
@@ -0,0 +1,168 @@
+package android.print;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class PDFPrint {
+
+ public static void generatePDFFromHTML(final Context context, final File file, final String htmlString, final OnPDFPrintListener onPDFPrintListener) {
+ final WebView mWebView = new WebView(context);
+ mWebView.setWebViewClient(new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ PrintAttributes printAttributes = new PrintAttributes.Builder()
+ .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
+ .setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
+ .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
+ .build();
+
+ final PrintDocumentAdapter documentAdapter = mWebView.createPrintDocumentAdapter(file.getName());
+ documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
+
+ @Override
+ public void onWriteCancelled() {
+ super.onWriteCancelled();
+ onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
+ }
+
+ @Override
+ public void onWriteFailed(CharSequence error) {
+ super.onWriteFailed(error);
+ onPDFPrintListener.onError(new Exception(error.toString()));
+ }
+
+ @Override
+ public void onWriteFinished(PageRange[] pages) {
+ super.onWriteFinished(pages);
+ onPDFPrintListener.onSuccess(file);
+ }
+ });
+ }
+ }, null);
+ }
+ });
+ mWebView.loadData(htmlString.replaceAll("#", "%23"), "text/HTML", "UTF-8");
+ }
+
+ public static void generatePDFFromWebView(final File file, final WebView webView, final OnPDFPrintListener onPDFPrintListener) {
+ PrintAttributes printAttributes = new PrintAttributes.Builder()
+ .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
+ .setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
+ .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
+ .build();
+
+ final PrintDocumentAdapter documentAdapter = webView.createPrintDocumentAdapter(file.getName());
+ documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
+
+ @Override
+ public void onWriteCancelled() {
+ super.onWriteCancelled();
+ onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
+ }
+
+ @Override
+ public void onWriteFailed(CharSequence error) {
+ super.onWriteFailed(error);
+ try {
+ if (error != null && error.toString().length() > 0) {
+ onPDFPrintListener.onError(new Exception(error.toString()));
+ } else {
+ onPDFPrintListener.onError(new Exception("Empty Page"));
+ }
+ }catch (Exception e) {e.printStackTrace();}
+ }
+
+ @Override
+ public void onWriteFinished(PageRange[] pages) {
+ super.onWriteFinished(pages);
+ onPDFPrintListener.onSuccess(file);
+ }
+ });
+ }
+ }, null);
+ }
+
+ private static ParcelFileDescriptor getOutputFile(File file) {
+ try {
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static PrintJob printPDF(final Activity activity, final File pdfFileToPrint, final PrintAttributes printAttributes) {
+ PrintManager printManager = (PrintManager) activity.getSystemService(Context.PRINT_SERVICE);
+ String jobName = Long.valueOf(System.currentTimeMillis()).toString();
+ return printManager.print(jobName, new PrintDocumentAdapter() {
+ @Override
+ public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
+ InputStream input = null;
+ OutputStream output = null;
+
+ try {
+
+ input = new FileInputStream(pdfFileToPrint);
+ output = new FileOutputStream(destination.getFileDescriptor());
+
+ byte[] buf = new byte[1024];
+ int bytesRead;
+
+ while ((bytesRead = input.read(buf)) > 0) {
+ output.write(buf, 0, bytesRead);
+ }
+
+ callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ input.close();
+ output.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
+ if (cancellationSignal.isCanceled()) {
+ callback.onLayoutCancelled();
+ return;
+ }
+
+ PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(pdfFileToPrint.getName()).setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();
+ callback.onLayoutFinished(pdi, true);
+ }
+ }, printAttributes);
+ }
+
+ public interface OnPDFPrintListener {
+ void onSuccess(File file);
+
+ void onError(Exception exception);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/LauncherActivity.kt b/app/src/main/kotlin/rasel/lunar/launcher/LauncherActivity.kt
index 0623e78..98e0a54 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/LauncherActivity.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/LauncherActivity.kt
@@ -35,6 +35,9 @@ import android.net.Uri
import android.net.http.SslError
import android.os.Build
import android.os.Bundle
+import android.os.Environment
+import android.os.Environment.isExternalStorageManager
+import android.print.PDFPrint
import android.provider.Settings
import android.telephony.TelephonyManager
import android.view.View
@@ -53,12 +56,13 @@ import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
+import androidx.core.content.FileProvider
+import androidx.core.net.toUri
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
-import androidx.lifecycle.ReportFragment.Companion.reportFragment
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import androidx.work.ExistingPeriodicWorkPolicy
@@ -109,12 +113,15 @@ import rasel.lunar.launcher.workers.RuliWebGetter
import rasel.lunar.launcher.workers.TheQooGetter
import rasel.lunar.launcher.workers.WorkersDb
import rasel.lunar.launcher.workers.YoutubeGetter
+import java.io.File
+import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
+import kotlin.random.Random
internal class LauncherActivity : AppCompatActivity() {
@@ -150,7 +157,7 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(longTimePeriod, TimeUnit.MINUTES)
.addTag(SMS_WORK_TAG)
.build())
- }, 2, TimeUnit.SECONDS)
+ }, 1, TimeUnit.SECONDS)
}
fun refreshCalls() {
Executors.newSingleThreadScheduledExecutor().schedule({
@@ -161,9 +168,10 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(longTimePeriod, TimeUnit.MINUTES)
.addTag(CALL_WORK_TAG)
.build())
- }, 2, TimeUnit.SECONDS)
+ }, 1, TimeUnit.SECONDS)
}
fun refreshFeeds() {
+ var delay = 5L
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(FEDDS_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
@@ -171,10 +179,8 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(shortTimePeriod, TimeUnit.MINUTES)
.addTag(FEDDS_WORK_TAG)
.build())
- }, 2, TimeUnit.SECONDS)
- }
-
- fun refreshYoutube() {
+ }, delay, TimeUnit.SECONDS)
+ delay= delay + 5
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(YT_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
@@ -182,9 +188,8 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(longTimePeriod, TimeUnit.MINUTES)
.addTag(YT_WORK_TAG)
.build())
- }, 2, TimeUnit.SECONDS)
- }
- fun refreshReddit() {
+ }, delay, TimeUnit.SECONDS)
+ delay= delay + 5
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(REDDIT_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
@@ -192,10 +197,8 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(midTimePeriod, TimeUnit.MINUTES)
.addTag(REDDIT_WORK_TAG)
.build())
- }, 2, TimeUnit.SECONDS)
- }
- fun refreshComics() {
- refreshComics3()
+ }, delay, TimeUnit.SECONDS)
+ delay= delay + 5
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(COMIC_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
@@ -203,10 +206,8 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(midTimePeriod, TimeUnit.MINUTES)
.addTag(COMIC_WORK_TAG)
.build())
- refreshComics2()
- }, 2, TimeUnit.SECONDS)
- }
- fun refreshComics2() {
+ }, delay, TimeUnit.SECONDS)
+ delay= delay + 5
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(COMIC2_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
@@ -214,10 +215,8 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(midTimePeriod, TimeUnit.MINUTES)
.addTag(COMIC2_WORK_TAG)
.build())
- }, 2, TimeUnit.SECONDS)
- }
- fun refreshComics3() {
-
+ }, delay, TimeUnit.SECONDS)
+ delay= delay + 5
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(ClienGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
@@ -225,9 +224,8 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(midTimePeriod, TimeUnit.MINUTES)
.addTag(ClienGetter.TAG)
.build())
- refreshArca()
- }, 2, TimeUnit.SECONDS)
-
+ }, delay, TimeUnit.SECONDS)
+ delay= delay + 5
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(DCGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
@@ -235,10 +233,8 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(midTimePeriod, TimeUnit.MINUTES)
.addTag(DCGetter.TAG)
.build())
- refreshArca()
- }, 2, TimeUnit.SECONDS)
-
-
+ }, delay, TimeUnit.SECONDS)
+ delay= delay + 5
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(RuliWebGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
@@ -246,9 +242,8 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(midTimePeriod, TimeUnit.MINUTES)
.addTag(RuliWebGetter.TAG)
.build())
- refreshArca()
- }, 2, TimeUnit.SECONDS)
-
+ }, delay, TimeUnit.SECONDS)
+ delay= delay + 5
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(TheQooGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
@@ -256,12 +251,8 @@ internal class LauncherActivity : AppCompatActivity() {
PeriodicWorkRequestBuilder(midTimePeriod, TimeUnit.MINUTES)
.addTag(TheQooGetter.TAG)
.build())
- refreshArca()
- }, 2, TimeUnit.SECONDS)
-
- }
-
- fun refreshArca() {
+ }, delay, TimeUnit.SECONDS)
+ delay= delay + 5
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(ArcaGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
@@ -270,7 +261,7 @@ internal class LauncherActivity : AppCompatActivity() {
.addTag(ArcaGetter.TAG)
.build())
- }, 2, TimeUnit.SECONDS)
+ }, delay, TimeUnit.SECONDS)
}
fun workmanager() : WorkManager? {
@@ -337,14 +328,7 @@ internal class LauncherActivity : AppCompatActivity() {
refreshSms()
refreshCalls()
refreshFeeds()
- refreshYoutube()
- refreshReddit()
- refreshComics()
-// if (listItem.size < 2) {
-// lActivity?.doWebParseStart(jGuruRanks) {
-//
-// }
-// }
+
}
override fun onDestroy() {
@@ -370,7 +354,20 @@ internal class LauncherActivity : AppCompatActivity() {
val intent = Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)
startActivity(intent)
}
-
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ if (!isExternalStorageManager()) {
+ try {
+ startActivityForResult(Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {
+ addCategory("android.intent.category.DEFAULT")
+ data = Uri.parse(String.format("package:%s", applicationContext.packageName))
+ }, 300)
+ } catch (e: Exception) {
+ startActivityForResult(Intent().apply {
+ action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
+ }, 300)
+ }
+ }
+ }
}
private fun welcomeDialog() {
@@ -536,6 +533,146 @@ internal class LauncherActivity : AppCompatActivity() {
}
}
+ fun openDrive(gmmIntentUri : Uri, pakage : String? = null) {
+ val mapIntent = Intent(Intent.ACTION_MEDIA_SHARED, gmmIntentUri)
+ pakage?.let {
+ mapIntent.setPackage(pakage)
+ }
+ startActivity(mapIntent)
+ }
+
+ fun doWebSavor(url : String, callBack :CommadCallabck?) {
+ if (true)return
+ this.callBack = callBack
+
+ binding.searcher01.post { binding.searcher01.visibility = View.VISIBLE }
+ BLog.LOGE("binding.otherCheck before ThreadRun")
+ binding.searcher01.bringToFront()
+ binding.searcher01.alpha = 1f
+ binding.searcher01.webViewClient = object : WebViewClient() {
+ override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
+ if (url?.contains("missav") == true && isF) {
+ BLog.LOGE("binding.otherCheck before reload")
+ view?.loadUrl(url!!)
+ isF = true
+ return false
+ }
+ return false
+ }
+
+ override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
+ BLog.LOGE("binding.otherCheck searcher01 in onPageStarted ${url}")
+ super.onPageStarted(view, url, favicon)
+ }
+ override fun onReceivedError(
+ view: WebView?,
+ request: WebResourceRequest?,
+ error: WebResourceError?
+ ) {
+
+ }
+ override fun onReceivedSslError(
+ view: WebView?,
+ handler: SslErrorHandler?,
+ error: SslError?
+ ) {
+ handler?.proceed()
+ }
+
+ override fun onPageFinished(view: WebView?, url: String?) {
+ super.onPageFinished(view, url)
+ autoScrollDown(view,url)
+
+ }
+ }
+
+ WebView.setWebContentsDebuggingEnabled(false)
+ binding.searcher01.apply {
+ setBackgroundColor(Color.WHITE) // 백그라운드 색상 설정
+ setLayerType(View.LAYER_TYPE_SOFTWARE, null) // 랜더링 이슈 해결
+ try {
+ settings.apply {
+ userAgentString = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
+ javaScriptEnabled = true // 자바스크립트 사용 가능하도록 설정
+ loadWithOverviewMode = true // 전체 웹페이지를 화면에 맞게 로드
+ useWideViewPort = true // 화면에 맞게 페이지 확대/축소
+ domStorageEnabled = true // DOM 저장소 사용 가능하도록 설정
+ setSupportMultipleWindows(true)
+ javaScriptCanOpenWindowsAutomatically = true // 팝업창 차단 해제
+ cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
+ textZoom = 100 // system 에 의한 글꼴 변형 방지
+ defaultTextEncodingName = "UTF-8" // 인코딩 설정
+ allowContentAccess = true // 웹뷰를 통해 content url에 접근할지 여부
+ layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING // 웹페이지의 레이아웃을 화면에 맞게 자동으로 조정
+ }
+ } catch (ignore: NoSuchMethodError) {
+
+ }.apply {
+ loadUrl(url) // 웹페이지 연결
+ }
+ }
+ }
+
+ fun autoScrollDown(webView: WebView?, url: String?) {
+ webView?.let { webView ->
+ val ramdomTimeSec =
+ 800L.plus(Math.abs(Random(System.currentTimeMillis()).nextLong().rem(489L)))
+ BLog.LOGE("ramdomTime >>> ${ramdomTimeSec}")
+ if (((webView?.scrollY ?: 0) + (webView?.height
+ ?: 0)) < webView?.contentHeight ?: 0
+ ) {
+ webView?.postDelayed({
+ webView?.scrollY = (binding.searcher01.scrollY) + (binding.searcher01.height.toFloat() * 0.4).toInt()
+ autoScrollDown(webView, url)
+ }, ramdomTimeSec)
+ } else {
+ webView?.postDelayed({
+ binding.viewPager.bringToFront()
+ binding.searcher01.alpha = 0f
+ if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
+ val fileName = url?.toUri()?.path?.replace("/","_")?.replace(".","_")
+ val path = File(Environment.getExternalStorageDirectory(),"bums")
+ if (path.exists() == false) {
+ path.mkdirs()
+ }
+ val file = File(path, fileName.plus(".pdf"))
+
+ BLog.LOGE("file >>> ${file.absolutePath}")
+ try {
+ PDFPrint.generatePDFFromWebView(file,webView, object : PDFPrint.OnPDFPrintListener {
+ override fun onSuccess(file: File?) {
+ BLog.LOGE("file >>>> ${file!!.absolutePath}")
+ val shareIntent: Intent = Intent().apply {
+ action = Intent.ACTION_SEND
+ this.`package` = "com.synology.dsdrive"
+ val imageUri = FileProvider.getUriForFile(
+ this@LauncherActivity,
+ "rasel.lunar.launcher.debug.fileprovider", //(use your app signature + ".provider" )
+ file
+ )
+ putExtra(Intent.EXTRA_STREAM, imageUri)
+ type = "pdf"
+ }
+ this@LauncherActivity.startActivity(shareIntent)
+ }
+
+ override fun onError(exception: java.lang.Exception?) {
+ Toast.makeText(this@LauncherActivity,
+ "Pdf Save Failk ${exception?.localizedMessage}", Toast.LENGTH_LONG).show()
+ exception?.printStackTrace()
+ }
+ } )
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ } else {
+
+ }
+ }, ramdomTimeSec)
+ }
+ }
+ }
+
var callBack : CommadCallabck? = null
var isF = false
fun doWebParseStart(url : String, callBack :CommadCallabck?) {
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/feeds/Feeds.kt b/app/src/main/kotlin/rasel/lunar/launcher/feeds/Feeds.kt
index 0c69a23..1c20df6 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/feeds/Feeds.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/feeds/Feeds.kt
@@ -62,10 +62,7 @@ import rasel.lunar.launcher.CommadCallabck
import rasel.lunar.launcher.LauncherActivity.Companion.appWidgetHost
import rasel.lunar.launcher.LauncherActivity.Companion.appWidgetManager
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
-import rasel.lunar.launcher.LauncherActivity.Companion.refreshComics
import rasel.lunar.launcher.LauncherActivity.Companion.refreshFeeds
-import rasel.lunar.launcher.LauncherActivity.Companion.refreshReddit
-import rasel.lunar.launcher.LauncherActivity.Companion.refreshYoutube
import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.FeedsBinding
import rasel.lunar.launcher.feeds.rss.RssAdapter
@@ -228,6 +225,9 @@ internal class Feeds : Fragment() , CommadCallabck {
if (input.text.toString().trim().contains(" ")) {
val cmd = input.text.toString().trim().split(" ")
when(cmd[0]) {
+ "s" -> {
+ home?.queryInfos(keyword = cmd[1])
+ }
"jf" -> {
consoleLog("on Cmd JF")
GlobalScope.launch { excuteGetterMostByUrl("https://javmost.to/search/movie/${cmd[1]}") }
@@ -284,6 +284,9 @@ internal class Feeds : Fragment() , CommadCallabck {
addAll(RssDataType.values())
remove(RssDataType.GURU)
remove(RssDataType.Most)
+ })
+ "all" -> home?.queryInfos(arrayListOf().apply {
+
})
"onews" -> home?.queryInfos(arrayListOf().apply {
addAll(RssDataType.values())
@@ -307,26 +310,12 @@ internal class Feeds : Fragment() , CommadCallabck {
}
}.start()
}
- "ytb" -> {
- refreshYoutube()
- consoleLog("excute refreshYoutube()")
- }
- "reddit" -> {
- refreshReddit()
- consoleLog("excute refreshReddit()")
- }
-
- "fedd" -> {
+ "req" -> {
refreshFeeds()
consoleLog("excute refreshFeeds()")
}
- "comic" -> {
- refreshComics()
- consoleLog("excute refreshComics()")
- }
-
"taxi" -> {
consoleLog("before run State home?.binding?.alcholKatalkT?.isVisible >> ${home?.binding?.alcholKatalkT?.isVisible}")
home?.showAl()
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt b/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt
index 090079f..04c51c8 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt
@@ -22,6 +22,7 @@ import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
+import android.content.DialogInterface
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
@@ -34,10 +35,17 @@ import android.view.LayoutInflater
import android.view.View
import android.view.View.OnScrollChangeListener
import android.view.ViewGroup
+import android.widget.EditText
+import android.widget.RadioButton
+import android.widget.RadioGroup
+import android.widget.TableRow
import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat.RECEIVER_EXPORTED
import androidx.core.content.ContextCompat.registerReceiver
+import androidx.core.view.children
+import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.DividerItemDecoration
@@ -45,6 +53,7 @@ import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
+import com.google.gson.Gson
import io.realm.kotlin.ext.query
import io.realm.kotlin.notifications.InitialResults
import io.realm.kotlin.notifications.ResultsChange
@@ -53,17 +62,17 @@ import io.realm.kotlin.query.RealmResults
import io.realm.kotlin.query.Sort
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.json.JSONArray
import org.json.JSONObject
+import org.jsoup.Jsoup
+import rasel.lunar.launcher.CommadCallabck
import rasel.lunar.launcher.LauncherActivity.Companion.CALL_WORK_TAG
import rasel.lunar.launcher.LauncherActivity.Companion.SMS_WORK_TAG
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
-import rasel.lunar.launcher.LauncherActivity.Companion.refreshComics
import rasel.lunar.launcher.LauncherActivity.Companion.refreshFeeds
-import rasel.lunar.launcher.LauncherActivity.Companion.refreshReddit
-import rasel.lunar.launcher.LauncherActivity.Companion.refreshYoutube
import rasel.lunar.launcher.LauncherActivity.Companion.workmanager
import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.LauncherHomeBinding
@@ -76,6 +85,7 @@ import rasel.lunar.launcher.helpers.UniUtils.Companion.canAuthenticate
import rasel.lunar.launcher.helpers.UniUtils.Companion.expandNotificationPanel
import rasel.lunar.launcher.helpers.UniUtils.Companion.lockMethod
import rasel.lunar.launcher.home.weather.WeatherExecutor
+import rasel.lunar.launcher.model.CiliMagnet
import rasel.lunar.launcher.model.NotificationItem
import rasel.lunar.launcher.model.RssData
import rasel.lunar.launcher.qaccess.QuickAccess
@@ -87,12 +97,15 @@ import rasel.lunar.launcher.todos.NotificationItemAdapter
import rasel.lunar.launcher.todos.RssItemAdapter
import rasel.lunar.launcher.todos.SmsLogsAdapter
import rasel.lunar.launcher.utils.BLog
+import rasel.lunar.launcher.utils.RssList.jGuruMain
import rasel.lunar.launcher.utils.SimpleFingerGestures
import rasel.lunar.launcher.utils.beforeDay
+import rasel.lunar.launcher.view.TableRadioGroup
import rasel.lunar.launcher.workers.RecentCall
import rasel.lunar.launcher.workers.RecentSms
import rasel.lunar.launcher.workers.WorkersDb
import java.net.URLEncoder
+import java.nio.charset.Charset
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
@@ -143,16 +156,12 @@ internal class LauncherHome : Fragment() {
}
val notiUpdate = Runnable {
- if (lastedNoti?.size ?: 0 > 0) {
- binding.otherCheck.text = "최근 정보[${lasted!!.size}]"
- mRssAdapter.updateData(lasted!!)
-// binding.infoList.smoothScrollToPosition(0)
- }
+ chooseAdpater()
}
- var lasted : RealmResults? = null
- var lastedNoti : RealmResults? = null
+ var lasted : List? = null
+ var lastedNoti : List? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -188,6 +197,8 @@ internal class LauncherHome : Fragment() {
binding.infoList.adapter = mRssAdapter
binding.notiList.adapter = mNotiAdapter
+ binding.favAppsGroup.setOnClickListener { searchData() }
+
try{binding.mainList.removeOnScrollListener(onScrChanged)}catch (e : Exception){e.printStackTrace()}
binding.mainList.addOnScrollListener(onScrChanged)
try{binding.smsList.removeOnScrollListener(onScrChanged)}catch (e : Exception){e.printStackTrace()}
@@ -265,10 +276,11 @@ internal class LauncherHome : Fragment() {
when (changes) {
is UpdatedResults -> {
BLog.LOGE("ResultsChange onNotificationPosted")
- lastedNoti = changes.list
- commandHandler.removeCallbacks(infoUpdate)
- commandHandler.postDelayed(infoUpdate, UPDATE_DELAY)
-
+ WorkersDb.getRealm().apply {
+ lastedNoti = copyFromRealm(changes.list)
+ }
+ commandHandler.removeCallbacks(notiUpdate)
+ commandHandler.postDelayed(notiUpdate, UPDATE_DELAY)
}
else -> {
@@ -277,8 +289,6 @@ internal class LauncherHome : Fragment() {
}
}
}
- mNotificationResult?.let { mNotiAdapter?.updateData(it) }
-
noticeJob?.start()
}
@@ -298,7 +308,8 @@ internal class LauncherHome : Fragment() {
filter!!.forEach {
rQ = rQ.query("category != $0", it.name)
}
- mRssDataResult = rQ.sort("pubDate ", Sort.DESCENDING).limit(1000).find()
+ //limit(1000)
+ mRssDataResult = rQ.sort("pubDate ", Sort.DESCENDING).find()
BLog.LOGE("${this} ::::: queryInfos after query find >>>> ")
infosJob = CoroutineScope(Dispatchers.Default).launch {
mRssDataResult?.asFlow()?.collect { changes: ResultsChange ->
@@ -307,7 +318,10 @@ internal class LauncherHome : Fragment() {
when (changes) {
is InitialResults -> {
BLog.LOGE("${this} ::::: queryInfos after changes size >>>> ${changes.list.size}")
- lasted = changes.list
+ WorkersDb.getRealm().apply {
+ lasted = copyFromRealm(changes.list)
+ }
+
commandHandler.postDelayed(infoUpdate, UPDATE_DELAY * 3)
}
is UpdatedResults -> {
@@ -319,11 +333,54 @@ internal class LauncherHome : Fragment() {
}
}
}
- mRssDataResult?.let {
- BLog.LOGE("${this} ::::: queryInfos updateData >>>> ")
-// lasted = it
-// commandHandler.postDelayed(infoUpdate, UPDATE_DELAY * 3)
- mRssAdapter.updateData(it)
+ infosJob?.start()
+ }
+
+ fun queryInfos(keyword : String, category : String? = null) {
+ BLog.LOGE("${this} ::::: queryInfos >>>> ${keyword}")
+ try { infosJob?.cancel() } catch (e:Exception) {e.printStackTrace()}
+ mRssDataResult = null
+ try {
+ System.gc()
+ }catch (e : Exception){e.printStackTrace()}
+
+ WorkersDb.getRealm().apply { writeBlocking {
+ delete(query().query("pubDate < $0",beforeDay(Date(),3)).query("category != $0 || category != $1 ", RssDataType.GURU.name,RssDataType.Most.name).find())
+ }}
+ BLog.LOGE("${this} ::::: queryInfos after delete >>>> ")
+ var rQ = WorkersDb.getRealm().query().query("pubDate > $0", beforeDay(Date(),3))
+ if(keyword.length > 0)
+ keyword.split("").forEach {
+ rQ = rQ.query("title CONTAINS $0 OR title CONTAINS $1", it.toUpperCase(), it.toLowerCase())
+ }
+ category?.let {
+ rQ = rQ.query("category == $0", it)
+ }
+
+ //limit(1000)
+ mRssDataResult = rQ.sort("pubDate ", Sort.DESCENDING).find()
+ BLog.LOGE("${this} ::::: queryInfos after query find >>>> ")
+ infosJob = CoroutineScope(Dispatchers.Default).launch {
+ mRssDataResult?.asFlow()?.collect { changes: ResultsChange ->
+ commandHandler.removeCallbacks(infoUpdate)
+
+ when (changes) {
+ is InitialResults -> {
+ BLog.LOGE("${this} ::::: queryInfos after changes size >>>> ${changes.list.size}")
+ WorkersDb.getRealm().apply {
+ lasted = copyFromRealm(changes.list)
+ }
+
+ commandHandler.postDelayed(infoUpdate, UPDATE_DELAY * 3)
+ }
+ is UpdatedResults -> {
+// lasted = changes.list
+// commandHandler.postDelayed(infoUpdate, UPDATE_DELAY * 3)
+ }
+ else -> {
+ }
+ }
+ }
}
infosJob?.start()
}
@@ -397,6 +454,7 @@ internal class LauncherHome : Fragment() {
binding.otherCheck.isSelected = false
} else {
+ queryInfos()
binding.otherCheck.isSelected = true
views.remove(binding.infoList)
binding.infoList.scrollToPosition(0)
@@ -407,6 +465,7 @@ internal class LauncherHome : Fragment() {
if (binding.notice.isSelected ) {
binding.notice.isSelected = false
} else {
+ queryNotice()
binding.notice.isSelected = true
views.remove(binding.notiList)
binding.notiList.visibility = View.VISIBLE
@@ -426,16 +485,60 @@ internal class LauncherHome : Fragment() {
binding.otherCheck.setOnLongClickListener {
queryInfos()
- refreshYoutube()
- refreshComics()
refreshFeeds()
- refreshReddit()
true
}
}
// https://www.youtube.com/results?search_query=sds
+
+ fun searchData() {
+ val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
+ builder.setTitle("Command Line")
+ val viewInflated: View = LayoutInflater.from(context)
+ .inflate(R.layout.search_layout, view as ViewGroup?, false)
+ val input = viewInflated.findViewById(R.id.input) as EditText
+ val categoryz = viewInflated.findViewById(R.id.categoryz) as TableRadioGroup
+ categoryz.setMaxColumns(5)
+ categoryz.setMaxRows(5)
+ var idx = 0
+ RssDataType.values().reversed().toList().chunked(5).forEach {
+ var tb = TableRow(requireContext())
+ it.forEach { c ->
+ if(c.equals(RssDataType.NO_DATA) == false) {
+ tb.addView(RadioButton(requireContext()).apply {
+ this.tag = c.name
+ this.text = c.name
+ })
+ }
+ }
+ categoryz.addView(tb)
+ }
+
+ builder.setView(viewInflated)
+ builder.setPositiveButton(android.R.string.ok,
+ DialogInterface.OnClickListener { dialog, which ->
+ dialog.dismiss()
+ var category : String? = null
+ categoryz.children.forEach {
+ if(it is TableRow) {
+ it.children.forEach {
+ if (it is RadioButton && it.isChecked) {
+ (it.tag as? String)?.let { category = it }
+ }
+ }
+ }
+ }
+ queryInfos(keyword =input.text.toString(),category)
+ })
+ builder.setNegativeButton(android.R.string.cancel,
+ DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
+ builder.show()
+ }
+
+
+
fun showAl() {
binding.alcholKatalkT.visibility = View.VISIBLE
binding.alcholKatalkT.setOnClickListener {
@@ -465,61 +568,61 @@ internal class LauncherHome : Fragment() {
binding.infoList.visibility = View.INVISIBLE
binding.notiList.visibility = View.INVISIBLE
if (binding.missedCalls.isSelected) {
- if (recentCalls.size > 0 && isAdded && isResumed && isVisible) {
+ if (recentCalls.size > 0) {
try {
callList.clear()
recentCalls.forEach { t, u ->
callList.add(u)
}.apply {
callList.sortByDescending { it.date }
- Handler(Looper.getMainLooper()).post {
- binding.mainList.visibility = View.VISIBLE
- mMissedCallsAdapter.updateData(callList)
- binding.recentSms.isSelected = false
- binding.otherCheck.isSelected = false
- binding.notice.isSelected = false
- }
+// Handler(Looper.getMainLooper()).post {
+ binding.mainList.visibility = View.VISIBLE
+ mMissedCallsAdapter.updateData(callList)
+ binding.recentSms.isSelected = false
+ binding.otherCheck.isSelected = false
+ binding.notice.isSelected = false
+// }
}
} catch (e : Exception) {
}
}
} else if(binding.recentSms.isSelected){
- if (smsList.size > 0 && isAdded && isResumed && isVisible) {
+ if (smsList.size > 0) {
try {
smsList.sortByDescending { it.rcvDate }
binding.smsList.visibility = View.VISIBLE
- Handler(Looper.getMainLooper()).post {
- binding.smsList.visibility = View.VISIBLE
- mSmsLogsAdapter.updateData(smsList)
- binding.missedCalls.isSelected = false
- binding.otherCheck.isSelected = false
- binding.notice.isSelected = false
- }
+// Handler(Looper.getMainLooper()).post {
+ binding.smsList.visibility = View.VISIBLE
+ mSmsLogsAdapter.updateData(smsList)
+ binding.missedCalls.isSelected = false
+ binding.otherCheck.isSelected = false
+ binding.notice.isSelected = false
+// }
} catch (e : Exception) {
}
}
} else if(binding.otherCheck.isSelected) {
- Handler(Looper.getMainLooper()).post {
- binding.missedCalls.isSelected = false
- binding.recentSms.isSelected = false
- binding.notice.isSelected = false
- binding.infoList.visibility = View.VISIBLE
- binding.otherCheck.text = "최근 정보[${lasted?.size ?: "-"}]"
- lasted?.let { mRssAdapter.updateData(it) }
+// Handler(Looper.getMainLooper()).post {
+ binding.missedCalls.isSelected = false
+ binding.recentSms.isSelected = false
+ binding.notice.isSelected = false
+ binding.infoList.visibility = View.VISIBLE
+ binding.otherCheck.text = "최근 정보[${lasted?.size ?: "-"}]"
+ lasted?.let { mRssAdapter.updateData(it) }
- }
+// }
}
else if(binding.notice.isSelected) {
- Handler(Looper.getMainLooper()).post {
- binding.missedCalls.isSelected = false
- binding.recentSms.isSelected = false
- binding.otherCheck.isSelected = false
- binding.notiList.visibility = View.VISIBLE
- binding.notice.text = "알림 센터[${lastedNoti?.size ?: "-"}]"
- lastedNoti?.let { mNotiAdapter.updateData(it)}
- }
+// Handler(Looper.getMainLooper()).post {
+ binding.missedCalls.isSelected = false
+ binding.recentSms.isSelected = false
+ binding.otherCheck.isSelected = false
+ binding.notiList.visibility = View.VISIBLE
+ binding.notice.text = "알림 센터[${lastedNoti?.size ?: "-"}]"
+ lastedNoti?.let { mNotiAdapter.updateData(it)}
+// }
}
commandHandler.postDelayed(hideListView, UPDATE_DELAY * 5)
}
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/model/CommunityData.kt b/app/src/main/kotlin/rasel/lunar/launcher/model/CommunityData.kt
index 143809f..eaeb93f 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/model/CommunityData.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/model/CommunityData.kt
@@ -1,6 +1,7 @@
package rasel.lunar.launcher.model
import io.realm.kotlin.types.RealmObject
+import io.realm.kotlin.types.annotations.Ignore
import io.realm.kotlin.types.annotations.PrimaryKey
import org.jsoup.select.Elements
import rasel.lunar.launcher.utils.BLog
@@ -191,9 +192,15 @@ class RssData : RealmObject, RssDataInterface {
var thumbnail : String? = null
var pubDate : Long = 0L
var category : String? = null
-
+ @Ignore
+ var mRssDataType : RssDataType? = null
override fun title(): String {
- return title ?: ""
+ return when(category()){
+ RssDataType.NewsFeed -> {
+ if(title?.length ?: 0 > 30) title?.substring(0,30).plus("...") else title ?: ""
+ }
+ else -> title ?: ""
+ }
}
override fun thumbnailUrl(): String {
@@ -205,7 +212,16 @@ class RssData : RealmObject, RssDataInterface {
}
override fun description(): String {
- return description ?: ""
+
+ return when(category()){
+ RssDataType.YOUTUBE -> {
+ if(description?.contains("게시자") == true) description!!.split("게시자")[0] else description ?: ""
+ }
+ RssDataType.NewsFeed -> {
+ category().name
+ }
+ else -> description.plus(" / ").plus(category().name)
+ }
}
override fun pubDate(): Long {
@@ -213,7 +229,9 @@ class RssData : RealmObject, RssDataInterface {
}
override fun category(): RssDataType {
- return RssDataType.valueOf(category!!)
+ if (mRssDataType == null)
+ mRssDataType = RssDataType.valueOf(category!!)
+ return mRssDataType!!
}
}
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/todos/RssItemAdapter.kt b/app/src/main/kotlin/rasel/lunar/launcher/todos/RssItemAdapter.kt
index 08283b5..dee6064 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/todos/RssItemAdapter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/todos/RssItemAdapter.kt
@@ -41,9 +41,98 @@ import java.text.SimpleDateFormat
import java.util.Date
+fun openNews(schemeString : String) {
+ val gmmIntentUri = Uri.parse(schemeString)
+ val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
+ mapIntent.setPackage("com.android.chrome")
+ lActivity?.startActivity(mapIntent)
+}
+
+
+fun openYouTube(schemeString : String) {
+ val gmmIntentUri = Uri.parse(schemeString)
+ val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
+ mapIntent.setPackage("com.google.android.youtube")
+ lActivity?.startActivity(mapIntent)
+}
+
+fun openReddit(schemeString : String) {
+ val gmmIntentUri = Uri.parse(schemeString)
+ val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
+ mapIntent.setPackage("com.reddit.frontpage")
+ lActivity?.startActivity(mapIntent)
+}
+
+fun openDotax(schemeString : String) {
+ val gmmIntentUri = Uri.parse(schemeString)
+ val mapIntent = Intent(Intent.ACTION_VIEW)
+ mapIntent.setPackage("net.daum.android.cafe")
+ mapIntent.setData(gmmIntentUri)
+ lActivity?.startActivity(mapIntent)
+}
+
+
+fun openOpera(schemeString : String) {
+ BLog.LOGE("openOpera ${schemeString}")
+ val gmmIntentUri = Uri.parse(schemeString)
+ val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
+ mapIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ mapIntent.setPackage("com.opera.browser")
+ lActivity?.startActivity(mapIntent)
+}
+
+
+
internal class RssItemAdapter (
+
private val context: Context) : RecyclerView.Adapter() {
- private var rssDataItemLis: ArrayList = arrayListOf()
+ companion object {
+ @SuppressLint("SimpleDateFormat")
+ val dateFormat = SimpleDateFormat("a HH:mm / yy - MM - dd")
+ val emptyDate = " - "
+
+ val dateViewClick = View.OnClickListener { v ->
+ (v?.tag as? Int)?.let { idx ->
+ val rss = rssDataItemLis[idx]
+ when(rss.category()) {
+ RssDataType.GURU,RssDataType.Most,RssDataType.REDDIT_nsfw -> {
+ v.findViewById(R.id.circle_preview)?.let {
+ if (it.visibility == View.GONE) {
+ it.visibility = View.VISIBLE
+ it.postDelayed({
+ it.visibility = View.GONE
+ }, 2000L)
+ } else {
+ openOpera(rss.originPage())
+ }
+ }
+ }
+ RssDataType.REDDIT -> { openReddit(rss.originPage()) }
+ RssDataType.Dotax -> { openDotax(rss.originPage()) }
+ RssDataType.YOUTUBE -> { openYouTube(rss.originPage()) }
+ else -> { openNews(rss.originPage()) }
+ }
+ }
+ }
+ private var rssDataItemLis: ArrayList = arrayListOf()
+ val mLongClickListener = View.OnLongClickListener { v ->
+ (v?.tag as? Int)?.let { idx ->
+ val rss = rssDataItemLis[idx]
+ lActivity?.doWebSavor(rss.originPage(),null)
+// when (rss.category()) {
+// RssDataType.GURU ,RssDataType.Most , RssDataType.TAGS-> { openOpera(rss.originPage()) }
+// RssDataType.REDDIT -> { openReddit(rss.originPage()) }
+// RssDataType.Dotax -> { openDotax(rss.originPage()) }
+// RssDataType.YOUTUBE -> { openYouTube(rss.originPage()) }
+// else -> { openNews(rss.originPage()) }
+// }
+ }
+ true
+ }
+ }
+
+
+
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RssTag {
val binding = ListItemWithBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false)
return RssTag(binding)
@@ -53,7 +142,7 @@ internal class RssItemAdapter (
return rssDataItemLis.size
}
- val dateFormat = SimpleDateFormat("a HH:mm / yy - MM - dd")
+
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RssTag, position: Int) {
@@ -62,77 +151,35 @@ internal class RssItemAdapter (
if (rssData.pubDate() > 1000L) {
holder.view.date.text = dateFormat.format(Date(rssData.pubDate()))
} else {
- holder.view.date.text = ""
+ holder.view.date.text = emptyDate
}
holder.view.title.text = rssData.title()
- when(rssData.category()) {
- RssDataType.YOUTUBE -> {
- holder.view.desc.text = if(rssData.description().contains("게시자")) rssData.description().split("게시자")[0] else rssData.description()
- }
- RssDataType.NewsFeed -> {
- holder.view.desc.text = rssData.category().name
- holder.view.title.text = if(rssData.title().length > 30)rssData.title().substring(0,30).plus("...") else rssData.title()
- }
- RssDataType.NO_DATA -> {}
- else -> {
- holder.view.desc.text = rssData.description().plus(" ").plus(rssData.category().name)
- }
- }
+ holder.view.desc.text = rssData.description()
+
var param = holder.view.circlePreview.layoutParams
holder.view.circlePreview.layoutParams = ConstraintLayout.LayoutParams(rssData.category().defaultImgSize(), param.height)
holder.view.circlePreview.visibility = rssData.category().getDefaultVisibiliy()
+ Picasso.get().cancelRequest(holder.view.circlePreview)
+
if(rssData.thumbnailUrl()?.length ?: 0 > 6) {
Picasso.get().load(rssData.thumbnailUrl().replace("&","&").toUri()).into(holder.view.circlePreview)
} else if (rssData.category().getResId() > 0 ) {
holder.view.circlePreview.setImageResource(rssData.category().getResId())
} else {
holder.view.circlePreview.setImageDrawable(null)
- Picasso.get().cancelRequest(holder.view.circlePreview)
}
+
holder.view.root.tag = position
holder.view.root.setOnClickListener(dateViewClick)
holder.view.root.setOnLongClickListener(mLongClickListener)
}
- val dateViewClick = View.OnClickListener {
- it.findViewById(R.id.circle_preview)?.let {
- if (it.visibility == View.GONE) {
- it.visibility = View.VISIBLE
- it.postDelayed({
- it.visibility = View.GONE
- }, 1000L)
- }
- }
- }
-
- val mLongClickListener = View.OnLongClickListener { v ->
- (v?.tag as? Int)?.let { idx ->
- val rss = rssDataItemLis[idx]
- when (rss.category()) {
- RssDataType.GURU ,RssDataType.Most , RssDataType.TAGS-> { openOpera(rss.originPage()) }
- RssDataType.REDDIT -> { openReddit(rss.originPage()) }
- RssDataType.Dotax -> { openDotax(rss.originPage()) }
- RssDataType.YOUTUBE -> { openYouTube(rss.originPage()) }
- else -> { openNews(rss.originPage()) }
- }
- }
- true
- }
-
- fun openOpera(schemeString : String) {
- BLog.LOGE("openOpera ${schemeString}")
- val gmmIntentUri = Uri.parse(schemeString)
- val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
- mapIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
- mapIntent.setPackage("com.opera.browser")
- lActivity?.startActivity(mapIntent)
- }
fun updateData(newList: List) {
try {
- BLog.LOGE("newList >> ${newList}")
+// BLog.LOGE("newList >> ${newList}")
DiffUtil.calculateDiff(RssItemDiffUtil(rssDataItemLis, newList)).apply {
}.dispatchUpdatesTo(this).apply {
@@ -140,49 +187,13 @@ internal class RssItemAdapter (
}
rssDataItemLis.clear()
rssDataItemLis.addAll(newList)
- BLog.LOGE("rssDataItemLis >> ${rssDataItemLis}")
- }catch ( e : Exception) {
+// BLog.LOGE("rssDataItemLis >> ${rssDataItemLis}")
+ } catch (e: Exception) {
e.printStackTrace()
}
}
- fun openNews(schemeString : String) {
- val gmmIntentUri = Uri.parse(schemeString)
- val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
- mapIntent.setPackage("com.android.chrome")
- lActivity?.startActivity(mapIntent)
- }
-
-
- fun openYouTube(schemeString : String) {
- val gmmIntentUri = Uri.parse(schemeString)
- val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
- mapIntent.setPackage("com.google.android.youtube")
- lActivity?.startActivity(mapIntent)
- }
-
- fun openReddit(schemeString : String) {
- val gmmIntentUri = Uri.parse(schemeString)
- val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
- mapIntent.setPackage("com.reddit.frontpage")
- lActivity?.startActivity(mapIntent)
- }
-
- fun openDotax(schemeString : String) {
- val gmmIntentUri = Uri.parse(schemeString)
- val mapIntent = Intent(Intent.ACTION_VIEW)
- mapIntent.setPackage("net.daum.android.cafe")
- mapIntent.setData(gmmIntentUri)
- lActivity?.startActivity(mapIntent)
- }
}
-//fun dp2px(dp: Float): Float {
-// val resources: Resources = this.getResources()
-// val metrics = resources.displayMetrics
-// val px = dp * (metrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
-// return px
-//}
-
internal class RssTag(var view: ListItemWithBinding) : RecyclerView.ViewHolder(view.root) {}
internal class RssItemDiffUtil(
var oldList: List, var newList: List
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/view/TableRadioGroup.kt b/app/src/main/kotlin/rasel/lunar/launcher/view/TableRadioGroup.kt
new file mode 100644
index 0000000..96937ec
--- /dev/null
+++ b/app/src/main/kotlin/rasel/lunar/launcher/view/TableRadioGroup.kt
@@ -0,0 +1,128 @@
+package rasel.lunar.launcher.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.view.View.OnClickListener
+import android.view.ViewGroup
+import android.widget.RadioButton
+import android.widget.TableLayout
+import android.widget.TableRow
+
+
+class TableRadioGroup : TableLayout {
+ var checkedRadioButtonId: Int = -1
+ private set
+ private var onCheckedChangeListener: OnCheckedChangeListener? = null
+ private var maxColumns = -1 // Maximum number of columns (-1 for unlimited)
+ private var maxRows = -1 // Maximum number of rows (-1 for unlimited)
+
+ constructor(context: Context) : super(context)
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ fun setMaxColumns(maxColumns: Int) {
+ this.maxColumns = maxColumns
+ }
+
+ fun setMaxRows(maxRows: Int) {
+ this.maxRows = maxRows
+ }
+
+ override fun addView(child: View, index: Int, params: ViewGroup.LayoutParams) {
+ if (child is TableRow) {
+ val numChildren = child.childCount
+ for (i in 0 until numChildren) {
+ val view = child.getChildAt(i)
+ if (view is RadioButton) {
+ setupRadioButton(view)
+ }
+ }
+ }
+ super.addView(child, index, params)
+
+ // Adjust the number of rows and columns if necessary
+ adjustTableLayout()
+ }
+
+ private fun setupRadioButton(radioButton: RadioButton?) {
+ if (radioButton == null) {
+ return
+ }
+
+ radioButton.setOnClickListener(OnClickListener {
+ if (checkedRadioButtonId != -1) {
+ setCheckedStateForView(checkedRadioButtonId, false)
+ }
+ val id = radioButton.id
+ setCheckedStateForView(id, true)
+ checkedRadioButtonId = id
+ if (onCheckedChangeListener != null) {
+ onCheckedChangeListener!!.onCheckedChanged(
+ this@TableRadioGroup,
+ checkedRadioButtonId
+ )
+ }
+ })
+ }
+
+ private fun setCheckedStateForView(viewId: Int, checked: Boolean) {
+ val checkedView = findViewById(viewId)
+ if (checkedView != null && checkedView is RadioButton) {
+ checkedView.isChecked = checked
+ }
+ }
+
+ fun setOnCheckedChangeListener(listener: OnCheckedChangeListener?) {
+ onCheckedChangeListener = listener
+ }
+
+ fun clearCheck() {
+ setCheckedStateForView(checkedRadioButtonId, false)
+ checkedRadioButtonId = -1
+ }
+
+ private fun adjustTableLayout() {
+ if (maxColumns > 0 && maxRows > 0) {
+ val childCount = childCount
+ var rowCount = 0
+ var currentRow: TableRow? = null
+ for (i in 0 until childCount) {
+ val child = getChildAt(i)
+ if (child is TableRow) {
+ currentRow = child
+ rowCount++
+ } else if (currentRow != null) {
+ val columnCount = currentRow.childCount
+ if (columnCount >= maxColumns) {
+ // Create a new row if the maximum column count is reached
+ if (rowCount < maxRows) {
+ val newRow = TableRow(context)
+ super.addView(newRow, getChildIndex(currentRow) + 1)
+ currentRow = newRow
+ rowCount++
+ } else {
+ // Remove extra children that exceed the maximum row count
+ removeView(child)
+ continue
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun getChildIndex(child: View): Int {
+ val childCount = childCount
+ for (i in 0 until childCount) {
+ if (getChildAt(i) === child) {
+ return i
+ }
+ }
+ return -1
+ }
+
+ interface OnCheckedChangeListener {
+ fun onCheckedChanged(group: TableRadioGroup?, checkedId: Int)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/ArcaGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/ArcaGetter.kt
index 25a2282..30b2d00 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/ArcaGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/ArcaGetter.kt
@@ -19,7 +19,8 @@ class ArcaGetter : BaseGetter {
constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) {
}
- override fun doWork(): Result {
+
+ override fun realWork(): Result {
try {
val urls = arrayListOf(
"https://arca.live/b/singbung?mode=best",
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/BaseGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/BaseGetter.kt
index a2086ae..8f1ddaa 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/BaseGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/BaseGetter.kt
@@ -1,13 +1,26 @@
package rasel.lunar.launcher.workers
import android.content.Context
+import androidx.annotation.CallSuper
import androidx.work.Worker
import androidx.work.WorkerParameters
import rasel.lunar.launcher.model.RssData
+import rasel.lunar.launcher.utils.before30Min
import rasel.lunar.launcher.utils.beforeDay
+import java.util.Calendar
import java.util.Date
-open class BaseGetter : Worker {
+open abstract class BaseGetter : Worker {
+ protected companion object {
+ var lastedUpdateTime = 0L
+
+ fun before10Min(): Long {
+ val cal: Calendar = Calendar.getInstance()
+ cal.setTime(Date())
+ cal.add(Calendar.MINUTE, -10)
+ return cal.timeInMillis
+ }
+ }
val USAGT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15"
val now = Date()
val limitDateTime = beforeDay(now,3)
@@ -17,7 +30,15 @@ open class BaseGetter : Worker {
constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) {
}
+ @CallSuper
override fun doWork(): Result {
- TODO("Not yet implemented")
+ val currentTime = before10Min()
+ if (lastedUpdateTime > 0L && currentTime > lastedUpdateTime) {
+ return Result.success().apply {
+
+ }
+ }
+ return realWork()
}
+ abstract fun realWork() : Result
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/ClienGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/ClienGetter.kt
index df2bf18..3e62879 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/ClienGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/ClienGetter.kt
@@ -67,7 +67,7 @@ class ClienGetter : BaseGetter {
}
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
try {
val testUrl2 = arrayListOf("https://www.clien.net/service/group/community")
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/DCGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/DCGetter.kt
index 5016bb1..0583c6a 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/DCGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/DCGetter.kt
@@ -66,7 +66,7 @@ class DCGetter : BaseGetter {
}
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
var tempArray = arrayListOf()
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/DotaxGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/DotaxGetter.kt
index b1df42f..c85b81c 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/DotaxGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/DotaxGetter.kt
@@ -18,7 +18,7 @@ class DotaxGetter : BaseGetter {
}
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
try {
val dotaxUrls = arrayListOf("https://m.cafe.daum.net/dotax",
"https://m.cafe.daum.net/dotax/_rec?page=2",
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/FmKoreaGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/FmKoreaGetter.kt
index 3993237..7bba89c 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/FmKoreaGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/FmKoreaGetter.kt
@@ -17,7 +17,7 @@ class FmKoreaGetter : BaseGetter {
}
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
val now = Date()
try {
val fmkoreaUrls = arrayListOf("https://www.fmkorea.com",
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/NewsFeedsGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/NewsFeedsGetter.kt
index 011bb31..494ddec 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/NewsFeedsGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/NewsFeedsGetter.kt
@@ -17,7 +17,7 @@ class NewsFeedsGetter : BaseGetter {
}
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
feddsUrls.clear()
feddsUrls.addAll(RssList.newsFeeds)
feddsUrls.addAll(RssList.getFeedUrls())
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/RecentCallGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/RecentCallGetter.kt
index 7238fb6..263fa1f 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/RecentCallGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/RecentCallGetter.kt
@@ -42,7 +42,7 @@ class RecentCallGetter : BaseGetter {
}
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
var dateParam = beforeDay(Date(),3).toString()
var managedCursor = lActivity?.contentResolver?.query(
@@ -74,33 +74,13 @@ class RecentCallGetter : BaseGetter {
var dir: String = ""
val dircode = callType.toInt()
when (dircode) {
- CallLog.Calls.INCOMING_TYPE -> {
- dir = "INCOMING_TYPE"
- }
-
- CallLog.Calls.OUTGOING_TYPE -> {
- dir = "OUTGOING_TYPE"
- }
-
- CallLog.Calls.MISSED_TYPE -> {
- dir = "MISSED_TYPE"
- }
-
- CallLog.Calls.VOICEMAIL_TYPE -> {
- dir = "VOICEMAIL_TYPE"
- }
-
- CallLog.Calls.REJECTED_TYPE -> {
- dir = "REJECTED_TYPE"
- }
-
- CallLog.Calls.BLOCKED_TYPE -> {
- dir = "BLOCKED_TYPE"
- }
-
- CallLog.Calls.ANSWERED_EXTERNALLY_TYPE -> {
- dir = "ANSWERED_EXTERNALLY_TYPE"
- }
+ CallLog.Calls.INCOMING_TYPE -> { dir = "INCOMING_TYPE" }
+ CallLog.Calls.OUTGOING_TYPE -> { dir = "OUTGOING_TYPE" }
+ CallLog.Calls.MISSED_TYPE -> { dir = "MISSED_TYPE" }
+ CallLog.Calls.VOICEMAIL_TYPE -> { dir = "VOICEMAIL_TYPE" }
+ CallLog.Calls.REJECTED_TYPE -> { dir = "REJECTED_TYPE" }
+ CallLog.Calls.BLOCKED_TYPE -> { dir = "BLOCKED_TYPE" }
+ CallLog.Calls.ANSWERED_EXTERNALLY_TYPE -> { dir = "ANSWERED_EXTERNALLY_TYPE" }
}
var missed: RecentCall = if (recentCalls.containsKey(phNumber)) {
recentCalls.get(phNumber)!!.apply {
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/RecentSmsGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/RecentSmsGetter.kt
index d3921bd..f960500 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/RecentSmsGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/RecentSmsGetter.kt
@@ -29,7 +29,7 @@ class RecentSmsGetter : BaseGetter {
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
var dateParam = beforeDay(Date(),3).toString()
val managedCursor = lActivity?.contentResolver?.query(
Telephony.Sms.CONTENT_URI, arrayOf(
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/RedditGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/RedditGetter.kt
index 38df0cf..4997725 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/RedditGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/RedditGetter.kt
@@ -16,7 +16,7 @@ class RedditGetter : BaseGetter {
}
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
val temp = arrayListOf()
for (url in feedJsons) {
for (it in RssFeedsParser.getReddit(url)) {
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/RuliWebGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/RuliWebGetter.kt
index 4ad5f3d..d05fd88 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/RuliWebGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/RuliWebGetter.kt
@@ -2,6 +2,7 @@ package rasel.lunar.launcher.workers
import android.annotation.SuppressLint
import android.content.Context
+import androidx.core.net.toUri
import androidx.work.WorkerParameters
import org.jsoup.Jsoup
import rasel.lunar.launcher.model.DcInside
@@ -47,7 +48,7 @@ class RuliWebGetter : BaseGetter {
if (title.length > 0 && pageLink.length > 0) {
RuliWeb().let { ru ->
ru.title = title
- ru.link = pageLink
+ ru.link = pageLink.replace(pageLink.toUri().query ?: "","")
ru.desc = desc
ru.thumbnail = thumbnailUrl
ru.dateTiem = dateTimeTxt.replace("날짜","").trim()
@@ -59,7 +60,7 @@ class RuliWebGetter : BaseGetter {
}
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
try {
val testUrl2 = arrayListOf("https://bbs.ruliweb.com/best/humor_only","https://bbs.ruliweb.com/best/humor_only/now?m=humor_only&t=default&page=2")
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/TheQooGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/TheQooGetter.kt
index 93328ab..46e08dd 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/TheQooGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/TheQooGetter.kt
@@ -45,7 +45,7 @@ class TheQooGetter : BaseGetter {
}
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
try {
val testUrl2 = arrayListOf("https://theqoo.net/hot")
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/WorkersDb.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/WorkersDb.kt
index 21f78ea..a9855f8 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/WorkersDb.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/WorkersDb.kt
@@ -44,7 +44,7 @@ object WorkersDb {
try {
getRealm().writeBlocking {
try {
- this.copyToRealm(it, UpdatePolicy.ALL)
+ this.copyToRealm(it, UpdatePolicy.ERROR)
} catch (e : Exception) {
}
diff --git a/app/src/main/kotlin/rasel/lunar/launcher/workers/YoutubeGetter.kt b/app/src/main/kotlin/rasel/lunar/launcher/workers/YoutubeGetter.kt
index a8e8152..5e66608 100644
--- a/app/src/main/kotlin/rasel/lunar/launcher/workers/YoutubeGetter.kt
+++ b/app/src/main/kotlin/rasel/lunar/launcher/workers/YoutubeGetter.kt
@@ -23,7 +23,7 @@ class YoutubeGetter : BaseGetter {
}
@SuppressLint("RestrictedApi")
- override fun doWork(): Result {
+ override fun realWork(): Result {
rssUrls.clear()
rssUrls.addAll(RssList.youtubeUrls)
for (url in rssUrls) {
@@ -41,8 +41,6 @@ class YoutubeGetter : BaseGetter {
if(it.html().contains("var ytInitialData", false)) {/**/
var ytInitialData = it.html().split("var ytInitialData = ")[1].split("")[0].toString()
var tempJSONObject : JSONObject? = null
-
-
JSONObject(ytInitialData).apply{
tempJSONObject = this
val root = Gson().fromJson(tempJSONObject.toString(), Root::class.java)
diff --git a/app/src/main/res/layout/search_layout.xml b/app/src/main/res/layout/search_layout.xml
new file mode 100644
index 0000000..651bfdb
--- /dev/null
+++ b/app/src/main/res/layout/search_layout.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml
index a8df289..6ce9181 100644
--- a/app/src/main/res/xml/file_paths.xml
+++ b/app/src/main/res/xml/file_paths.xml
@@ -1,3 +1,4 @@
+
\ No newline at end of file