This commit is contained in:
lunaticbum 2024-08-30 18:09:49 +09:00
parent 2e9900201e
commit 9131931df9
16 changed files with 782 additions and 173 deletions

View File

@ -25,6 +25,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.net.Uri import android.net.Uri
@ -110,6 +111,8 @@ internal class LauncherActivity : AppCompatActivity() {
val CALL_WORK_TAG = "MissedCallGetter" val CALL_WORK_TAG = "MissedCallGetter"
val FEDDS_WORK_TAG = "NewsFeedsGetter" val FEDDS_WORK_TAG = "NewsFeedsGetter"
var isOpendFold = false
@JvmStatic var lActivity: LauncherActivity? = null @JvmStatic var lActivity: LauncherActivity? = null
@JvmStatic var appWidgetManager: AppWidgetManager? = null @JvmStatic var appWidgetManager: AppWidgetManager? = null
@JvmStatic var appWidgetHost: WidgetHost? = null @JvmStatic var appWidgetHost: WidgetHost? = null
@ -155,12 +158,31 @@ internal class LauncherActivity : AppCompatActivity() {
} }
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
BLog.LOGE("onConfigurationChanged Configuration >> ${newConfig}")
BLog.LOGE("onConfigurationChanged newConfig?.screenWidthDp >> ${newConfig?.screenWidthDp}")
isOpendFold = (newConfig?.screenWidthDp?.toInt() ?: 0 > 700) == true
binding.viewPager.invalidate()
binding.viewPager.currentItem = 1
}
override fun onNewIntent(intent: Intent?) { override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent) super.onNewIntent(intent)
binding.viewPager.invalidate()
binding.viewPager.post { BLog.LOGE("onNewIntent intent >> ${intent}")
binding.viewPager?.adapter?.notifyDataSetChanged()
intent?.extras?.keySet()?.forEach {
BLog.LOGE("onNewIntent intent >> ${it}")
} }
// binding.viewPager.invalidate()
// binding.viewPager.post {
// binding.viewPager?.adapter?.notifyDataSetChanged()
// }
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -200,15 +222,14 @@ internal class LauncherActivity : AppCompatActivity() {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
BLog.LOGE("onStart()") BLog.LOGE("LauncherActivity onStart()")
// if (settingsPrefs.getBoolean(KEY_BACK_HOME, false)) viewPager.currentItem = 1
statusBarView() statusBarView()
setBgColor() setBgColor()
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
BLog.LOGE("onResume") BLog.LOGE("LauncherActivity onResume")
// askPermissions()
} }
private fun welcomeDialog() { private fun welcomeDialog() {
@ -376,7 +397,9 @@ internal class LauncherActivity : AppCompatActivity() {
} }
} }
var callBack : (()->Unit)? = null
fun doWebPare(url : String, callBack : (()->Unit)?) { fun doWebPare(url : String, callBack : (()->Unit)?) {
this.callBack = callBack
BLog.LOGE("binding.otherCheck before ThreadRun") BLog.LOGE("binding.otherCheck before ThreadRun")
binding.searcher01.webViewClient = object : WebViewClient() { binding.searcher01.webViewClient = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
@ -448,12 +471,13 @@ internal class LauncherActivity : AppCompatActivity() {
var maxDate : Long = Long.MIN_VALUE var maxDate : Long = Long.MIN_VALUE
var minDate : Long = Long.MAX_VALUE var minDate : Long = Long.MAX_VALUE
val triple = 1000L * 60L * 60L * 24L * 3L
val simpldateFormat = SimpleDateFormat("d MMM, yy", Locale.US) val simpldateFormat = SimpleDateFormat("d MMM, yy", Locale.US)
fun jGuruMain(doc: Document) { fun jGuruMain(doc: Document) {
BLog.LOGE("do default parsing") // BLog.LOGE("do default parsing")
BLog.LOGE("SimpleDateFormat D MM yy => ${SimpleDateFormat("d MMM yy", Locale.US).format(Date())}") // BLog.LOGE("SimpleDateFormat D MM yy => ${SimpleDateFormat("d MMM yy", Locale.US).format(Date())}")
val prevUrl = doc.getElementsByClass("prev").get(0).getElementsByAttribute("href").get(0).attr("href") val prevUrl = doc.getElementsByClass("prev").get(0).getElementsByAttribute("href").get(0).attr("href")
BLog.LOGE("doc.getElementsByClass(prev).get(0).html() ${prevUrl}") // BLog.LOGE("doc.getElementsByClass(prev).get(0).html() ${prevUrl}")
doc.getElementsByClass("column").forEach { doc.getElementsByClass("column").forEach {
var title = it.getElementsByAttribute("title").get(0).text() var title = it.getElementsByAttribute("title").get(0).text()
var model = title.replace("[","").split("]")[0] var model = title.replace("[","").split("]")[0]
@ -462,18 +486,14 @@ internal class LauncherActivity : AppCompatActivity() {
var tags = it.getElementsByClass("tags").get(0).text() var tags = it.getElementsByClass("tags").get(0).text()
var date = it.getElementsByClass("date").get(0).text() var date = it.getElementsByClass("date").get(0).text()
var regDate = simpldateFormat.parse(date).time var regDate = simpldateFormat.parse(date).time
minDate = Math.min(minDate,regDate) minDate = Math.min(minDate,regDate)
maxDate = Math.max(maxDate,regDate) maxDate = Math.max(maxDate,regDate)
listItem.add(RssItem(model = model, title = title, pageLink = pageLink, image = imgg, tags = tags, date = simpldateFormat.parse(date).time)) listItem.add(RssItem(model = model, title = title, pageLink = pageLink, image = imgg, tags = tags, date = simpldateFormat.parse(date).time))
}.apply { }.apply {
BLog.LOGE("listItem.size >>> ${listItem.size}") BLog.LOGE("listItem.size >>> ${listItem.size}")
if (prevUrl!=null && prevUrl.length > TEST_PAG.length && prevUrl.contains("/page/") && (maxDate - minDate) < (1000L * 60L * 60L * 24L * 3L)) { if (prevUrl!=null && prevUrl.length > TEST_PAG.length && prevUrl.contains("/page/") && ((maxDate - minDate) < triple)) {
BLog.LOGE("listItem.size >>> ${listItem.size} do next ") listItem.sortByDescending { it.date }
BLog.LOGE("saving data :: ${listItem.size}items ${simpldateFormat.format(Date(minDate))} ~ ${simpldateFormat.format(Date(maxDate))}")
binding.searcher01.postDelayed({binding.searcher01.loadUrl(prevUrl)}, 5000L) binding.searcher01.postDelayed({binding.searcher01.loadUrl(prevUrl)}, 5000L)
} else { } else {
listItem.sortByDescending { it.date } listItem.sortByDescending { it.date }
@ -481,11 +501,11 @@ internal class LauncherActivity : AppCompatActivity() {
Toast.makeText(this@LauncherActivity, Toast.makeText(this@LauncherActivity,
"Stored data :: ${listItem.size} items :: [${simpldateFormat.format(Date(minDate))} ~ ${simpldateFormat.format(Date(maxDate))}]", Toast.LENGTH_LONG).show() "Stored data :: ${listItem.size} items :: [${simpldateFormat.format(Date(minDate))} ~ ${simpldateFormat.format(Date(maxDate))}]", Toast.LENGTH_LONG).show()
} }
this@LauncherActivity.callBack?.invoke()
} }
} }
fun jGuruTag(doc: Document) { fun jGuruTag(doc: Document) {
listTags.clear()
doc.getElementsByTag("ul").forEach { doc.getElementsByTag("ul").forEach {
it.children().forEach { it.children().forEach {
if (it.tag().name.contains("li")) { if (it.tag().name.contains("li")) {
@ -502,6 +522,7 @@ internal class LauncherActivity : AppCompatActivity() {
listTags.sortByDescending { it.count } listTags.sortByDescending { it.count }
Toast.makeText(this@LauncherActivity, Toast.makeText(this@LauncherActivity,
"Stored data :: ${listTags.size}tags", Toast.LENGTH_SHORT).show() "Stored data :: ${listTags.size}tags", Toast.LENGTH_SHORT).show()
this@LauncherActivity.callBack?.invoke()
} }
} }

View File

@ -27,7 +27,7 @@ import com.squareup.picasso.Picasso
internal class LunarLauncher : Application() { internal class LunarLauncher : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
Picasso.get().setIndicatorsEnabled(true) // Picasso.get().setIndicatorsEnabled(true)
} }
override fun onTrimMemory(level: Int) { override fun onTrimMemory(level: Int) {
super.onTrimMemory(level) super.onTrimMemory(level)

View File

@ -379,7 +379,7 @@ internal class AppDrawer : Fragment() {
val chechHandler = Handler(Looper.getMainLooper()) val chechHandler = Handler(Looper.getMainLooper())
val cancelSearch = Runnable { timerCheck() } val cancelSearch = Runnable { lActivity?.viewPager?.currentItem = 1 }
fun registCancelSearch() { fun registCancelSearch() {
BLog.LOGE("Called registCancelSearch") BLog.LOGE("Called registCancelSearch")
@ -391,10 +391,6 @@ internal class AppDrawer : Fragment() {
chechHandler.removeCallbacks(cancelSearch) chechHandler.removeCallbacks(cancelSearch)
} }
private fun timerCheck() {
lActivity?.onBackPressed()
}
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
closeSearch() closeSearch()

View File

@ -36,11 +36,13 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.button.MaterialButtonToggleGroup import com.google.android.material.button.MaterialButtonToggleGroup
import kotlinx.coroutines.* import kotlinx.coroutines.*
import rasel.lunar.launcher.LauncherActivity.Companion.TEST_PAG import rasel.lunar.launcher.LauncherActivity.Companion.TEST_PAG
import rasel.lunar.launcher.LauncherActivity.Companion.appWidgetHost import rasel.lunar.launcher.LauncherActivity.Companion.appWidgetHost
import rasel.lunar.launcher.LauncherActivity.Companion.appWidgetManager import rasel.lunar.launcher.LauncherActivity.Companion.appWidgetManager
import rasel.lunar.launcher.LauncherActivity.Companion.isOpendFold
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.FeedsBinding import rasel.lunar.launcher.databinding.FeedsBinding
@ -52,6 +54,9 @@ import rasel.lunar.launcher.helpers.Constants.Companion.SEPARATOR
import rasel.lunar.launcher.helpers.Constants.Companion.requestCreateWidget import rasel.lunar.launcher.helpers.Constants.Companion.requestCreateWidget
import rasel.lunar.launcher.helpers.Constants.Companion.requestPickWidget import rasel.lunar.launcher.helpers.Constants.Companion.requestPickWidget
import rasel.lunar.launcher.home.LauncherHome.Companion.listItem import rasel.lunar.launcher.home.LauncherHome.Companion.listItem
import rasel.lunar.launcher.home.LauncherHome.Companion.listTags
import rasel.lunar.launcher.home.RssItem
import rasel.lunar.launcher.home.RssTagItem
import java.util.* import java.util.*
@ -59,11 +64,14 @@ internal class Feeds : Fragment() {
private lateinit var binding: FeedsBinding private lateinit var binding: FeedsBinding
private val requestCodeString = "requestCode" private val requestCodeString = "requestCode"
var mRssAdapter : RssAdapter? = null var mRssAdapter : RssAdapter<RssItem>? = null
var mRssAdapter2 : RssAdapter<RssTagItem>? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = FeedsBinding.inflate(inflater, container, false) binding = FeedsBinding.inflate(inflater, container, false)
mRssAdapter = RssAdapter(listItem, requireContext()) mRssAdapter = RssAdapter(listItem, requireContext())
mRssAdapter2 = RssAdapter(listTags, requireContext())
binding.feedsRss.rss.adapter = mRssAdapter binding.feedsRss.rss.adapter = mRssAdapter
binding.feedsRss.rss2.adapter = mRssAdapter2
updateWidgets() updateWidgets()
return binding.root return binding.root
} }
@ -104,6 +112,8 @@ internal class Feeds : Fragment() {
if (isChecked) { if (isChecked) {
when (checkedId) { when (checkedId) {
binding.expandRss.id -> { binding.expandRss.id -> {
binding.feedsRss.rss.visibility = View.GONE
binding.feedsRss.rss2.visibility = View.GONE
binding.feedsSysInfos.expandableSystemInfo.collapse() binding.feedsSysInfos.expandableSystemInfo.collapse()
binding.feedsRss.expandableRss.expand() binding.feedsRss.expandableRss.expand()
startService() startService()
@ -125,6 +135,7 @@ internal class Feeds : Fragment() {
/* start rss service if network is active and rss url is not empty */ /* start rss service if network is active and rss url is not empty */
private fun startService() { private fun startService() {
binding.feedsRss.rss.visibility = View.GONE binding.feedsRss.rss.visibility = View.GONE
binding.feedsRss.rss2.visibility = View.GONE
binding.feedsRss.loading.visibility = View.VISIBLE binding.feedsRss.loading.visibility = View.VISIBLE
binding.feedsRss.refresh.visibility = View.VISIBLE binding.feedsRss.refresh.visibility = View.VISIBLE
val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext()) val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
@ -138,24 +149,27 @@ internal class Feeds : Fragment() {
dialog.dismiss() dialog.dismiss()
when(input.text.toString()) { when(input.text.toString()) {
"jJguru","vVioPup*383v" -> { "jJguru","vVioPup*383v" -> {
mRssAdapter?.updateData(listItem)
binding.feedsRss.apply { binding.feedsRss.apply {
rss.adapter = mRssAdapter
loading.visibility = View.VISIBLE loading.visibility = View.VISIBLE
if (listItem.size > 0) { if (listItem.size > 0) {
mRssAdapter?.updateData(listItem)
rss.visibility = View.VISIBLE rss.visibility = View.VISIBLE
loading.visibility = View.GONE loading.visibility = View.GONE
refresh.visibility = View.GONE
} else { } else {
refresh.visibility = View.VISIBLE refresh.visibility = View.VISIBLE
rss.visibility = View.GONE rss.visibility = View.GONE
refresh.setOnClickListener { refresh.setOnClickListener {
lActivity?.doWebPare(TEST_PAG) { lActivity?.doWebPare(TEST_PAG) {
if (listItem.size > 0) { if (listItem.size > 0) {
mRssAdapter?.updateData(listItem) rss?.postDelayed( {
rss?.post { mRssAdapter?.updateData(listItem)
loading.visibility = View.GONE loading.visibility = View.GONE
refresh.visibility = View.GONE refresh.visibility = View.GONE
rss.visibility = View.VISIBLE rss.visibility = View.VISIBLE
} },500L)
} }
} }
} }
@ -163,7 +177,35 @@ internal class Feeds : Fragment() {
} }
} }
"jJTag"-> { "jJTag"-> {
// lActivity?.doWebPare(TEST_PAG.plus("tags")) // lActivity?.doWebPare(TEST_PAG.plus("tags")) {
binding.feedsRss.apply {
rss2.adapter = mRssAdapter2
loading.visibility = View.VISIBLE
if (listTags.size > 0) {
mRssAdapter2?.updateData(listTags)
rss2.visibility = View.VISIBLE
loading.visibility = View.GONE
refresh.visibility = View.GONE
} else {
refresh.visibility = View.VISIBLE
rss2.visibility = View.GONE
refresh.setOnClickListener {
lActivity?.doWebPare(TEST_PAG.plus("tags")) {
if (listTags.size > 0) {
rss2?.postDelayed( {
mRssAdapter2?.updateData(listTags)
loading.visibility = View.GONE
refresh.visibility = View.GONE
rss2.visibility = View.VISIBLE
},500L)
}
}
}
}
}
// }
} }
else -> { else -> {
binding.expandRss.isChecked = false binding.expandRss.isChecked = false

View File

@ -30,6 +30,9 @@ import android.graphics.Typeface
import android.util.TypedValue import android.util.TypedValue
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.net.Uri import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.view.MotionEvent
import android.view.View import android.view.View
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
@ -40,6 +43,7 @@ import rasel.lunar.launcher.databinding.ListItemWithBinding
import rasel.lunar.launcher.helpers.UniUtils.Companion.getColorResId import rasel.lunar.launcher.helpers.UniUtils.Companion.getColorResId
import rasel.lunar.launcher.home.RssItem import rasel.lunar.launcher.home.RssItem
import rasel.lunar.launcher.todos.RssDataItem import rasel.lunar.launcher.todos.RssDataItem
import rasel.lunar.launcher.todos.RssDataType
import rasel.lunar.launcher.todos.RssItemDiffUtil import rasel.lunar.launcher.todos.RssItemDiffUtil
import java.net.URLEncoder import java.net.URLEncoder
import java.nio.charset.Charset import java.nio.charset.Charset
@ -47,8 +51,8 @@ import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
internal class RssAdapter(var items: ArrayList<RssItem> = arrayListOf(), private val context: Context) : internal class RssAdapter<T : RssDataItem>(var items: ArrayList<T> = arrayListOf<T>(), private val context: Context) :
RecyclerView.Adapter<RssAdapter.RssViewHolder>() { RecyclerView.Adapter<RssViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RssViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RssViewHolder {
val binding = ListItemWithBinding.inflate(LayoutInflater.from(parent.context), parent, false) val binding = ListItemWithBinding.inflate(LayoutInflater.from(parent.context), parent, false)
@ -60,35 +64,58 @@ internal class RssAdapter(var items: ArrayList<RssItem> = arrayListOf(), private
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RssViewHolder, position: Int) { override fun onBindViewHolder(holder: RssViewHolder, position: Int) {
val item = items[position] val item = items[position]
/* customize the first item */
// if (position == 0) {
holder.view.title.apply {
text = item.title
}
holder.view.date.text = dateFormat.format(Date(item.date))
holder.view.desc.text = item.tags.plus("\n").plus(item.model)
holder.view.circlePreview.visibility = View.GONE holder.view.circlePreview.visibility = View.GONE
/* reset customization for rest */ if (item.category() == RssDataType.TAGS) {
// } else { var txts = item.title().split("(")
// holder.view.desc.apply { holder.view.title.text = "\n".plus(txts[0])
// text = items[position].title holder.view.title.gravity = Gravity.CENTER
//// gravity = holder.gravity if (txts.size > 1) {
//// setTextColor(holder.color) holder.view.desc.text = "(".plus(txts[1])
//// typeface = holder.typeface holder.view.desc.gravity = Gravity.RIGHT
//// setTextSize(TypedValue.COMPLEX_UNIT_PX, holder.size) holder.view.desc.visibility = View.VISIBLE
// }
// } } else {
Picasso.get().load(item.image).into(holder.view.circlePreview) holder.view.desc.text = ""
}
holder.view.date.visibility = View.GONE
holder.view.date.text = ""
} else {
holder.view.title.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT)
holder.view.desc.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT)
holder.view.date.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT)
holder.view.title.text = item.title()
if (item.pubDate() > 1000L) {
holder.view.date.text = dateFormat.format(Date(item.pubDate()))
}
holder.view.desc.text = item.description()
holder.view.desc.visibility = View.VISIBLE
holder.view.date.visibility = View.VISIBLE
}
if (item.thumbnailUrl().length ?: 0 > 6) {
Picasso.get().load(item.thumbnailUrl()).into(holder.view.circlePreview)
}
holder.view.root.setOnClickListener { holder.view.root.setOnClickListener {
holder.view.circlePreview.visibility = View.VISIBLE holder.view.circlePreview.visibility = View.VISIBLE
holder.view.circlePreview.postDelayed({ holder.view.circlePreview.postDelayed({
holder.view.circlePreview.visibility = View.GONE holder.view.circlePreview.visibility = View.GONE
},500L) },500L)
} }
/* on click - open in browser */
holder.view.root.setOnLongClickListener { holder.view.root.setOnLongClickListener {
openOpera("https://cili.site/search?q=${URLEncoder.encode(item.model, Charset.defaultCharset().name())}") if(item is RssItem) {
openOpera(item.pageLink) openOpera(
"https://cili.site/search?q=${
URLEncoder.encode(
item.model,
Charset.defaultCharset().name()
)
}"
)
}
openOpera(item.originPage())
true true
} }
} }
@ -96,30 +123,47 @@ internal class RssAdapter(var items: ArrayList<RssItem> = arrayListOf(), private
fun openOpera(schemeString : String) { fun openOpera(schemeString : String) {
val gmmIntentUri = Uri.parse(schemeString) val gmmIntentUri = Uri.parse(schemeString)
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
mapIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
mapIntent.setPackage("com.opera.browser") mapIntent.setPackage("com.opera.browser")
lActivity?.startActivity(mapIntent) lActivity?.startActivity(mapIntent)
} }
fun updateData(newList: List<RssItem>) { fun <T : RssDataItem>updateData(newList: List<T>) {
DiffUtil.calculateDiff(RssItemDiffUtil(items, newList)).dispatchUpdatesTo(this) DiffUtil.calculateDiff(RssItemDiffUtil(items, newList)).dispatchUpdatesTo(this)
} }
inner class RssViewHolder(var view: ListItemWithBinding) : RecyclerView.ViewHolder(view.root) { }
} class RssViewHolder(var view: ListItemWithBinding) : RecyclerView.ViewHolder(view.root) {
} }
internal class RssItemDiffUtil( internal class RssItemDiffUtil(
private val oldList: List<RssItem>, private val newList: List<RssItem> private val oldList: List<RssDataItem>, private val newList: List<RssDataItem>
) : DiffUtil.Callback() { ) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean = override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].pageLink == newList[newItemPosition].pageLink oldList[oldItemPosition].originPage() == newList[newItemPosition].originPage()
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean = override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].pageLink == newList[newItemPosition].pageLink oldList[oldItemPosition].originPage() == newList[newItemPosition].originPage()
} }
//fun View.setOnVeryLongClickListener(listener: () -> Unit) {
// setOnTouchListener(object : View.OnTouchListener {
//
// private val longClickDuration = 2000L
// private val handler = Handler(Looper.getMainLooper())
//
// override fun onTouch(v: View?, event: MotionEvent?): Boolean {
// if (event?.action == MotionEvent.ACTION_DOWN) {
// handler.postDelayed({ listener.invoke() }, longClickDuration)
// } else if (event?.action == MotionEvent.ACTION_UP) {
// handler.removeCallbacksAndMessages(null)
// }
// return true
// }
// })
//}

View File

@ -25,23 +25,14 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.Color
import android.net.http.SslError
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.provider.AlarmClock import android.provider.AlarmClock
import android.telephony.TelephonyManager
import android.text.format.DateFormat import android.text.format.DateFormat
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.webkit.JavascriptInterface
import android.webkit.SslErrorHandler
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Toast import android.widget.Toast
import androidx.biometric.BiometricPrompt import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat.RECEIVER_EXPORTED import androidx.core.content.ContextCompat.RECEIVER_EXPORTED
@ -49,21 +40,12 @@ import androidx.core.content.ContextCompat.registerReceiver
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.google.gson.Gson import com.google.gson.Gson
import org.apache.commons.text.StringEscapeUtils
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserFactory
import rasel.lunar.launcher.LauncherActivity.Companion.CALL_WORK_TAG import rasel.lunar.launcher.LauncherActivity.Companion.CALL_WORK_TAG
import rasel.lunar.launcher.LauncherActivity.Companion.FEDDS_WORK_TAG import rasel.lunar.launcher.LauncherActivity.Companion.FEDDS_WORK_TAG
import rasel.lunar.launcher.LauncherActivity.Companion.SMS_WORK_TAG import rasel.lunar.launcher.LauncherActivity.Companion.SMS_WORK_TAG
import rasel.lunar.launcher.LauncherActivity.Companion.TEST_PAG
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.LauncherActivity.Companion.workmanager import rasel.lunar.launcher.LauncherActivity.Companion.workmanager
import rasel.lunar.launcher.R import rasel.lunar.launcher.R
@ -82,32 +64,18 @@ import rasel.lunar.launcher.helpers.UniUtils.Companion.lockMethod
import rasel.lunar.launcher.home.weather.WeatherExecutor import rasel.lunar.launcher.home.weather.WeatherExecutor
import rasel.lunar.launcher.qaccess.QuickAccess import rasel.lunar.launcher.qaccess.QuickAccess
import rasel.lunar.launcher.settings.SettingsActivity import rasel.lunar.launcher.settings.SettingsActivity
import rasel.lunar.launcher.todos.LinearLayoutManagerWrapper
import rasel.lunar.launcher.todos.MissedCallsAdapter import rasel.lunar.launcher.todos.MissedCallsAdapter
import rasel.lunar.launcher.todos.Root
import rasel.lunar.launcher.todos.RssDataItem import rasel.lunar.launcher.todos.RssDataItem
import rasel.lunar.launcher.todos.RssDataType import rasel.lunar.launcher.todos.RssDataType
import rasel.lunar.launcher.todos.RssFeedsParser
import rasel.lunar.launcher.todos.RssItemAdapter import rasel.lunar.launcher.todos.RssItemAdapter
import rasel.lunar.launcher.todos.SmsLogsAdapter import rasel.lunar.launcher.todos.SmsLogsAdapter
import rasel.lunar.launcher.todos.TwoColumnBrowseResultsRenderer
import rasel.lunar.launcher.utils.BLog import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.MissedCallGetter
import rasel.lunar.launcher.utils.NewsFeedsGetter
import rasel.lunar.launcher.utils.RecentSmsGetter
import rasel.lunar.launcher.utils.RecentSmsLog import rasel.lunar.launcher.utils.RecentSmsLog
import rasel.lunar.launcher.utils.RssList
import rasel.lunar.launcher.utils.SimpleFingerGestures import rasel.lunar.launcher.utils.SimpleFingerGestures
import rasel.lunar.launcher.utils.beforeDay import rasel.lunar.launcher.utils.beforeDay
import java.io.ByteArrayInputStream
import java.io.InputStream
import java.nio.charset.Charset
import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
internal class LauncherHome : Fragment() { internal class LauncherHome : Fragment() {
@ -255,11 +223,11 @@ internal class LauncherHome : Fragment() {
chooseAdpater() chooseAdpater()
} }
binding.otherCheck.setOnLongClickListener { // binding.otherCheck.setOnLongClickListener {
listItem.clear() // listItem.clear()
lActivity?.doWebPare(TEST_PAG, null) // lActivity?.doWebPare(TEST_PAG, null)
true // true
} // }
// binding.summaryChoose.setOnCheckedChangeListener { group, checkedId -> // binding.summaryChoose.setOnCheckedChangeListener { group, checkedId ->
// chooseAdpater() // chooseAdpater()
// } // }
@ -314,6 +282,8 @@ internal class LauncherHome : Fragment() {
rssSet.remove(k,v) rssSet.remove(k,v)
} }
}.apply { }.apply {
rssList.sortByDescending{ it.pubDate() }
binding.infoList.visibility = View.VISIBLE
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
mRssAdapter.updateData(rssList) mRssAdapter.updateData(rssList)
binding.infoList.visibility = View.VISIBLE binding.infoList.visibility = View.VISIBLE
@ -633,10 +603,35 @@ class MissedCall {
class RssTagItem { class RssTagItem : RssDataItem{
var link : String = "" var link : String = ""
var tagTitle = "" var tagTitle = ""
var count = 0 var count = 0
override fun title(): String {
return tagTitle
}
override fun thumbnailUrl(): String {
return ""
}
override fun originPage(): String {
return link
}
override fun description(): String {
return " "
}
override fun pubDate(): Long {
return 0L
}
override fun category(): RssDataType {
return RssDataType.TAGS
}
constructor(link: String, tagTitle: String) { constructor(link: String, tagTitle: String) {
this.link = link this.link = link
this.tagTitle = tagTitle this.tagTitle = tagTitle
@ -647,7 +642,7 @@ class RssTagItem {
} }
} }
} }
class RssItem { class RssItem : RssDataItem {
var model : String = "" var model : String = ""
var title : String = "" var title : String = ""
var pageLink : String = "" var pageLink : String = ""
@ -670,4 +665,28 @@ class RssItem {
this.tags = tags this.tags = tags
this.date = date this.date = date
} }
override fun title(): String {
return title
}
override fun thumbnailUrl(): String {
return image
}
override fun originPage(): String {
return pageLink
}
override fun description(): String {
return tags.plus(model)
}
override fun pubDate(): Long {
return date
}
override fun category(): RssDataType {
return RssDataType.GURU
}
} }

View File

@ -0,0 +1,388 @@
package rasel.lunar.launcher.model
import rasel.lunar.launcher.todos.Image
import rasel.lunar.launcher.todos.RssDataItem
import rasel.lunar.launcher.todos.RssDataType
import rasel.lunar.launcher.todos.Source
class Reddit {
}
class Child {
var kind: String? = null
var data: Data? = null
}
class CrosspostParentList {
var approved_at_utc: Any? = null
var subreddit: String? = null
var selftext: String? = null
var author_fullname: String? = null
var saved: Boolean = false
var mod_reason_title: Any? = null
var gilded: Int = 0
var clicked: Boolean = false
var title: String? = null
var link_flair_richtext: ArrayList<Any>? = null
var subreddit_name_prefixed: String? = null
var hidden: Boolean = false
var pwls: Any? = null
var link_flair_css_class: String? = null
var downs: Int = 0
var thumbnail_height: Int = 0
var top_awarded_type: Any? = null
var hide_score: Boolean = false
var name: String? = null
var quarantine: Boolean = false
var link_flair_text_color: String? = null
var upvote_ratio: Double = 0.0
var author_flair_background_color: Any? = null
var subreddit_type: String? = null
var ups: Int = 0
var total_awards_received: Int = 0
var media_embed: MediaEmbed? = null
var thumbnail_width: Int = 0
var author_flair_template_id: Any? = null
var is_original_content: Boolean = false
var user_reports: ArrayList<Any>? = null
var secure_media: SecureMedia? = null
var is_reddit_media_domain: Boolean = false
var is_meta: Boolean = false
var category: Any? = null
var secure_media_embed: SecureMediaEmbed? = null
var link_flair_text: String? = null
var can_mod_post: Boolean = false
var score: Int = 0
var approved_by: Any? = null
var is_created_from_ads_ui: Boolean = false
var author_premium: Boolean = false
var thumbnail: String? = null
var edited: Boolean = false
var author_flair_css_class: Any? = null
var author_flair_richtext: ArrayList<Any>? = null
var gildings: Gildings? = null
var post_hint: String? = null
var content_categories: Any? = null
var is_self: Boolean = false
var mod_note: Any? = null
var created: Double = 0.0
var link_flair_type: String? = null
var wls: Any? = null
var removed_by_category: Any? = null
var banned_by: Any? = null
var author_flair_type: String? = null
var domain: String? = null
var allow_live_comments: Boolean = false
var selftext_html: Any? = null
var likes: Any? = null
var suggested_sort: Any? = null
var banned_at_utc: Any? = null
var url_overridden_by_dest: String? = null
var view_count: Any? = null
var archived: Boolean = false
var no_follow: Boolean = false
var is_crosspostable: Boolean = false
var pinned: Boolean = false
var over_18: Boolean = false
var preview: Preview? = null
var all_awardings: ArrayList<Any>? = null
var awarders: ArrayList<Any>? = null
var media_only: Boolean = false
var can_gild: Boolean = false
var spoiler: Boolean = false
var locked: Boolean = false
var author_flair_text: Any? = null
var treatment_tags: ArrayList<Any>? = null
var visited: Boolean = false
var removed_by: Any? = null
var num_reports: Any? = null
var distinguished: Any? = null
var subreddit_id: String? = null
var author_is_blocked: Boolean = false
var mod_reason_by: Any? = null
var removal_reason: Any? = null
var link_flair_background_color: String? = null
var id: String? = null
var is_robot_indexable: Boolean = false
var report_reasons: Any? = null
var author: String? = null
var discussion_type: Any? = null
var num_comments: Int = 0
var send_replies: Boolean = false
var whitelist_status: Any? = null
var contest_mode: Boolean = false
var mod_reports: ArrayList<Any>? = null
var author_patreon_flair: Boolean = false
var author_flair_text_color: Any? = null
var permalink: String? = null
var parent_whitelist_status: Any? = null
var stickied: Boolean = false
var url: String? = null
var subreddit_subscribers: Int = 0
var created_utc: Double = 0.0
var num_crossposts: Int = 0
var media: Media? = null
var is_video: Boolean = false
var link_flair_template_id: String? = null
}
class Data : RssDataItem {
var after: String? = null
var dist: Int = 0
var modhash: String? = null
var geo_filter: Any? = null
var children: ArrayList<Child>? = null
var before: Any? = null
var approved_at_utc: Any? = null
var subreddit: String? = null
var selftext: String? = null
var user_reports: ArrayList<Any>? = null
var saved: Boolean = false
var mod_reason_title: Any? = null
var gilded: Int = 0
var clicked: Boolean = false
var title: String? = null
var link_flair_richtext: ArrayList<Any>? = null
var subreddit_name_prefixed: String? = null
var hidden: Boolean = false
var pwls: Any? = null
var link_flair_css_class: Any? = null
var downs: Int = 0
var thumbnail_height: Int = 0
var top_awarded_type: Any? = null
var hide_score: Boolean = false
var name: String? = null
var quarantine: Boolean = false
var link_flair_text_color: String? = null
var upvote_ratio: Double = 0.0
var author_flair_background_color: Any? = null
var subreddit_type: String? = null
var ups: Int = 0
var total_awards_received: Int = 0
var media_embed: MediaEmbed? = null
var thumbnail_width: Int = 0
var author_flair_template_id: Any? = null
var is_original_content: Boolean = false
var author_fullname: String? = null
var secure_media: SecureMedia? = null
var is_reddit_media_domain: Boolean = false
var is_meta: Boolean = false
var category: Any? = null
var secure_media_embed: SecureMediaEmbed? = null
var link_flair_text: Any? = null
var can_mod_post: Boolean = false
var score: Int = 0
var approved_by: Any? = null
var is_created_from_ads_ui: Boolean = false
var author_premium: Boolean = false
var thumbnail: String? = null
var edited: Boolean = false
var author_flair_css_class: Any? = null
var author_flair_richtext: ArrayList<Any>? = null
var gildings: Gildings? = null
var post_hint: String? = null
var content_categories: Any? = null
var is_self: Boolean = false
var mod_note: Any? = null
var crosspost_parent_list: ArrayList<CrosspostParentList>? = null
var created: Double = 0.0
var link_flair_type: String? = null
var wls: Any? = null
var removed_by_category: Any? = null
var banned_by: Any? = null
var author_flair_type: String? = null
var domain: String? = null
var allow_live_comments: Boolean = false
var selftext_html: Any? = null
var likes: Any? = null
var suggested_sort: Any? = null
var banned_at_utc: Any? = null
var url_overridden_by_dest: String? = null
var view_count: Any? = null
var archived: Boolean = false
var no_follow: Boolean = false
var is_crosspostable: Boolean = false
var pinned: Boolean = false
var over_18: Boolean = false
var preview: Preview? = null
var all_awardings: ArrayList<Any>? = null
var awarders: ArrayList<Any>? = null
var media_only: Boolean = false
var can_gild: Boolean = false
var spoiler: Boolean = false
var locked: Boolean = false
var author_flair_text: Any? = null
var treatment_tags: ArrayList<Any>? = null
var visited: Boolean = false
var removed_by: Any? = null
var num_reports: Any? = null
var distinguished: Any? = null
var subreddit_id: String? = null
var author_is_blocked: Boolean = false
var mod_reason_by: Any? = null
var removal_reason: Any? = null
var link_flair_background_color: String? = null
var id: String? = null
var is_robot_indexable: Boolean = false
var report_reasons: Any? = null
var author: String? = null
var discussion_type: Any? = null
var num_comments: Int = 0
var send_replies: Boolean = false
var whitelist_status: Any? = null
var contest_mode: Boolean = false
var mod_reports: ArrayList<Any>? = null
var author_patreon_flair: Boolean = false
var crosspost_parent: String? = null
var author_flair_text_color: Any? = null
var permalink: String? = null
var parent_whitelist_status: Any? = null
var stickied: Boolean = false
var url: String? = null
var subreddit_subscribers: Int = 0
var created_utc: Double = 0.0
var num_crossposts: Int = 0
var media: Media? = null
var is_video: Boolean = false
override fun title(): String {
return title ?: ""
}
override fun thumbnailUrl(): String {
return thumbnail ?: ""
}
override fun originPage(): String {
return url ?: ""
}
override fun description(): String {
return subreddit_name_prefixed ?: subreddit ?: ""
}
override fun pubDate(): Long {
if (created_utc != null) {
return created_utc!!.toLong() * 1000L
} else if (created != null) {
return created!!.toLong() * 1000L
}
return 0L
}
override fun category(): RssDataType {
return RssDataType.REDDIT
}
}
class Gif {
var source: Source? = null
var resolutions: ArrayList<Resolution>? = null
}
class Gildings
class Image {
var source: Source? = null
var resolutions: ArrayList<Resolution>? = null
var variants: Variants? = null
var id: String? = null
}
class Media {
var type: String? = null
var oembed: Oembed? = null
}
class MediaEmbed {
var content: String? = null
var width: Int = 0
var scrolling: Boolean = false
var height: Int = 0
}
class Mp4 {
var source: Source? = null
var resolutions: ArrayList<Resolution>? = null
}
class Nsfw {
var source: Source? = null
var resolutions: ArrayList<Resolution>? = null
}
class Obfuscated {
var source: Source? = null
var resolutions: ArrayList<Resolution>? = null
}
class Oembed {
var provider_url: String? = null
var version: String? = null
var title: String? = null
var thumbnail_width: Int = 0
var height: Int = 0
var width: Int = 0
var html: String? = null
var provider_name: String? = null
var thumbnail_url: String? = null
var type: String? = null
var thumbnail_height: Int = 0
}
class Preview {
var images: ArrayList<Image>? = null
var reddit_video_preview: RedditVideoPreview? = null
var enabled: Boolean = false
}
class RedditVideoPreview {
var bitrate_kbps: Int = 0
var fallback_url: String? = null
var height: Int = 0
var width: Int = 0
var scrubber_media_url: String? = null
var dash_url: String? = null
var duration: Int = 0
var hls_url: String? = null
var is_gif: Boolean = false
var transcoding_status: String? = null
}
class Resolution {
var url: String? = null
var width: Int = 0
var height: Int = 0
}
class Root {
var kind: String? = null
var data: Data? = null
}
class SecureMedia {
var type: String? = null
var oembed: Oembed? = null
}
class SecureMediaEmbed {
var content: String? = null
var width: Int = 0
var scrolling: Boolean = false
var media_domain_url: String? = null
var height: Int = 0
}
class Source {
var url: String? = null
var width: Int = 0
var height: Int = 0
}
class Variants {
var obfuscated: Obfuscated? = null
var nsfw: Nsfw? = null
var gif: Gif? = null
var mp4: Mp4? = null
}

View File

@ -3,8 +3,10 @@ package rasel.lunar.launcher.todos
enum class RssDataType { enum class RssDataType {
NO_DATA, NO_DATA,
YOUTUBE, YOUTUBE,
NewsFeed NewsFeed,
GURU,
TAGS,
REDDIT,
} }
interface RssDataItem { interface RssDataItem {

View File

@ -1,22 +1,52 @@
package rasel.lunar.launcher.todos package rasel.lunar.launcher.todos
import android.util.Xml import android.util.Xml
import com.google.gson.Gson
import com.google.gson.JsonParser
import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException import org.xmlpull.v1.XmlPullParserException
import rasel.lunar.launcher.model.Root
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.beforeDay
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.io.InputStreamReader
import java.net.URL import java.net.URL
import java.net.URLDecoder
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale import java.util.Locale
object RssFeedsParser { object RssFeedsParser {
var parseDateFormat: SimpleDateFormat = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH) var parseDateFormat: SimpleDateFormat = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH)
var limitDateTime = beforeDay(Date(),3)
fun getFeeds(url : String) : List<RssDataItem> { fun getFeeds(url : String) : List<RssDataItem> {
var returnList = mutableListOf<RssDataItem>() var returnList = mutableListOf<RssDataItem>()
try { try {
returnList.addAll(parse(getInputStream(url)!!)) returnList.addAll(parse(getInputStream(url)!!))
BLog.LOGE("getInputStream >>>>> link ${URLDecoder.decode(url,"utf-8")} , itemSize = ${returnList.size}")
} catch (e : Exception) {
e.printStackTrace()
}
return returnList
}
fun getReddit(url : String): List<RssDataItem> {
var returnList = mutableListOf<RssDataItem>()
var dateTime = beforeDay(Date(),3)
try {
var mRoot = Gson().fromJson(InputStreamReader(getInputStream(url)!!),rasel.lunar.launcher.model.Root::class.java)
mRoot.data?.children?.forEach {
// BLog.LOGE("getReddit >>>>> link ${URLDecoder.decode(url,"utf-8")} , itemSize = ${Gson().toJson(it)}")
if(((it.data?.created_utc ?: 0).toLong() * 1000L > dateTime)) {
// BLog.LOGE("getReddit >>>>> link ${URLDecoder.decode(url,"utf-8")} , itemSize = ${Gson().toJson(it)}")
(it.data as? RssDataItem)?.let {
returnList.add(it)
}
}
}
BLog.LOGE("getReddit >>>>> link ${URLDecoder.decode(url,"utf-8")} , itemSize = ${returnList.size}")
} catch (e : Exception) { } catch (e : Exception) {
e.printStackTrace() e.printStackTrace()
} }
@ -27,9 +57,12 @@ object RssFeedsParser {
return try { return try {
val url = URL(link) val url = URL(link)
url.openConnection().getInputStream() url.openConnection().getInputStream()
} catch (ioException: IOException) { } catch (ioException: IOException) {
ioException.printStackTrace() ioException.printStackTrace()
null null
}.apply {
BLog.LOGE("getInputStream >>>>> link $link")
} }
} }
@ -47,6 +80,7 @@ object RssFeedsParser {
@Throws(XmlPullParserException::class, IOException::class) @Throws(XmlPullParserException::class, IOException::class)
private fun readFeed(parser: XmlPullParser): List<RssFeed> { private fun readFeed(parser: XmlPullParser): List<RssFeed> {
parser.require(XmlPullParser.START_TAG, null, "rss") parser.require(XmlPullParser.START_TAG, null, "rss")
var title: String? = null var title: String? = null
var link: String? = null var link: String? = null
@ -77,7 +111,7 @@ object RssFeedsParser {
source = readThumbnail(parser) source = readThumbnail(parser)
} }
if (title != null && link != null) { if (date > limitDateTime && title != null && link != null) {
val item = RssFeed(title, link) val item = RssFeed(title, link)
item.pubDate = date item.pubDate = date
item.source = source item.source = source
@ -88,7 +122,6 @@ object RssFeedsParser {
source = null source = null
desc = null desc = null
date = 0 date = 0
} }
} }
return items return items

View File

@ -66,39 +66,70 @@ internal class RssItemAdapter (
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RssTag, position: Int) { override fun onBindViewHolder(holder: RssTag, position: Int) {
val todo = smsList[position] val todo = smsList[position]
holder.view.title.text = "${todo.title()}"
holder.view.date.text = "${dateFormat.format(Date(todo.pubDate()))}" holder.view.date.text = "${dateFormat.format(Date(todo.pubDate()))}"
holder.view.desc.visibility = View.GONE // holder.view.desc.visibility = View.GONE
holder.view.circlePreview.visibility = View.GONE
when(todo.category()) { when(todo.category()) {
RssDataType.YOUTUBE -> { RssDataType.YOUTUBE -> {
if(todo.thumbnailUrl()?.length ?: 0 > 6) { if(todo.thumbnailUrl()?.length ?: 0 > 6) {
Picasso.get().load(todo.thumbnailUrl().toUri()).into(holder.view.circlePreview) Picasso.get().load(todo.thumbnailUrl().toUri()).into(holder.view.circlePreview)
holder.view.circlePreview.visibility = View.VISIBLE holder.view.circlePreview.visibility = View.VISIBLE
} }
holder.view.title.text = "${todo.title()}"
holder.view.title.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT) holder.view.title.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT)
holder.view.desc.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT) holder.view.desc.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT)
holder.view.date.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT) holder.view.date.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT)
holder.view.desc.visibility = View.VISIBLE holder.view.desc.visibility = View.VISIBLE
holder.view.desc.text = if(todo.description().contains("게시자")) todo.description().split("게시자")[0] else todo.description() holder.view.desc.text = if(todo.description().contains("게시자")) todo.description().split("게시자")[0] else todo.description()
holder.view.root.setOnClickListener { openYouTube(todo.originPage()) } // holder.view.root.setOnClickListener { openYouTube(todo.originPage()) }
} }
RssDataType.NewsFeed -> { RssDataType.NewsFeed -> {
holder.view.desc.text = ""
holder.view.circlePreview.visibility = View.GONE
holder.view.title.text = if(todo.title().length > 30)todo.title().substring(0,30).plus("...") else todo.title()
holder.view.title.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.LEFT) holder.view.title.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.LEFT)
holder.view.desc.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.LEFT) holder.view.desc.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.LEFT)
holder.view.date.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT) holder.view.date.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT)
holder.view.root.setOnClickListener { openNews(todo.originPage()) } // holder.view.root.setOnClickListener { openNews(todo.originPage()) }
} }
RssDataType.NO_DATA -> {} RssDataType.NO_DATA -> {}
else -> {
holder.view.title.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT)
holder.view.desc.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT)
holder.view.date.gravity = Gravity.CENTER_VERTICAL.plus(Gravity.RIGHT)
holder.view.title.text = todo.title()
if (todo.pubDate() > 1000L) {
holder.view.date.text = dateFormat.format(Date(todo.pubDate()))
}
if(todo.thumbnailUrl()?.length ?: 0 > 6) {
Picasso.get().load(todo.thumbnailUrl().toUri()).into(holder.view.circlePreview)
}
holder.view.circlePreview.visibility = View.GONE
holder.view.desc.text = todo.description()
holder.view.desc.visibility = View.VISIBLE
holder.view.date.visibility = View.VISIBLE
holder.view.root.setOnClickListener {
holder.view.circlePreview.visibility = View.VISIBLE
holder.view.circlePreview.postDelayed({
holder.view.circlePreview.visibility = View.GONE
},500L)
}
}
} }
holder.view.root.setOnLongClickListener { holder.view.root.setOnLongClickListener {
when(todo.category()) { when(todo.category()) {
RssDataType.YOUTUBE -> {} RssDataType.YOUTUBE -> {
openYouTube(todo.originPage())
}
RssDataType.NewsFeed -> { RssDataType.NewsFeed -> {
openNews(todo.originPage()) openNews(todo.originPage())
} }
RssDataType.NO_DATA -> {} RssDataType.NO_DATA -> {}
else -> {
}
} }
// val clipBoard = // val clipBoard =
// lActivity!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager // lActivity!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
@ -126,9 +157,7 @@ internal class RssItemAdapter (
lActivity?.startActivity(mapIntent) lActivity?.startActivity(mapIntent)
} }
} }
internal class RssTag(var view: ListItemWithBinding) : RecyclerView.ViewHolder(view.root)
class RssTag(var view: ListItemWithBinding) : RecyclerView.ViewHolder(view.root)
internal class RssItemDiffUtil( internal class RssItemDiffUtil(
private val oldList: List<RssDataItem>, private val newList: List<RssDataItem> private val oldList: List<RssDataItem>, private val newList: List<RssDataItem>
) : DiffUtil.Callback() { ) : DiffUtil.Callback() {

View File

@ -1,7 +1,9 @@
package rasel.lunar.launcher.todos package rasel.lunar.launcher.todos
import org.json.JSONObject import org.json.JSONObject
import rasel.lunar.launcher.utils.BLog import rasel.lunar.launcher.model.Image
import rasel.lunar.launcher.model.Source
import rasel.lunar.launcher.utils.afterDay
import rasel.lunar.launcher.utils.beforeDay import rasel.lunar.launcher.utils.beforeDay
import java.util.Date import java.util.Date
@ -1613,24 +1615,24 @@ open class VideoRenderer : RssDataItem {
var targetDate = publishedTimeText?.simpleText ?: publishedTimeText?.runs?.first()?.text ?: "" var targetDate = publishedTimeText?.simpleText ?: publishedTimeText?.runs?.first()?.text ?: ""
if (targetDate?.length ?: 0 > 1) { if (targetDate?.length ?: 0 > 1) {
var dateDesc = targetDate var dateDesc = targetDate
dateDesc = dateDesc!!.split("")[0].trim() var isBefore = dateDesc.contains("")
val dayString = dateDesc.replace("[^0-9]".toRegex(), "") val dayString = dateDesc.replace("[^0-9]".toRegex(), "")
before = dayString.toInt() before = dayString.toInt()
if (dateDesc.contains("")) { if (dateDesc.contains("")) {
before = 365 * before before = 365 * before
dateTime = beforeDay(date, before) dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
} else if (dateDesc.contains("")) { } else if (dateDesc.contains("")) {
before = 30 * before before = 30 * before
dateTime = beforeDay(date, before) dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
} else if (dateDesc.contains("")) { } else if (dateDesc.contains("")) {
before = 7 * before before = 7 * before
dateTime = beforeDay(date, before) dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
} else if (dateDesc.contains("")) { } else if (dateDesc.contains("")) {
dateTime = beforeDay(date, before) dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
} else if (dateDesc.contains("시간")) { } else if (dateDesc.contains("시간")) {
dateTime = dateTime.minus(before.times(1000L * 60L * 60L)) dateTime = if (isBefore)dateTime.minus(before.times(1000L * 60L * 60L)) else dateTime.plus(before.times(1000L * 60L * 60L))
} else if (dateDesc.contains("")) { } else if (dateDesc.contains("")) {
dateTime = dateTime.minus(before.times(1000L * 60L)) dateTime = if (isBefore)dateTime.minus(before.times(1000L * 60L)) else dateTime.plus(before.times(1000L * 60L))
} }
} }
}catch (e : Exception) { }catch (e : Exception) {

View File

@ -7,13 +7,10 @@ import android.database.Cursor
import android.net.Uri import android.net.Uri
import android.provider.CallLog import android.provider.CallLog
import android.provider.ContactsContract.PhoneLookup import android.provider.ContactsContract.PhoneLookup
import android.provider.Settings.Global
import android.provider.Telephony import android.provider.Telephony
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
@ -23,8 +20,10 @@ import rasel.lunar.launcher.home.LauncherHome.Companion.rssSet
import rasel.lunar.launcher.home.LauncherHome.Companion.smsList import rasel.lunar.launcher.home.LauncherHome.Companion.smsList
import rasel.lunar.launcher.home.MissedCall import rasel.lunar.launcher.home.MissedCall
import rasel.lunar.launcher.todos.Root import rasel.lunar.launcher.todos.Root
import rasel.lunar.launcher.todos.RssDataItem import rasel.lunar.launcher.todos.RssDataItem
import rasel.lunar.launcher.todos.RssFeedsParser import rasel.lunar.launcher.todos.RssFeedsParser
import rasel.lunar.launcher.utils.RssList.feedJsons
import java.io.BufferedReader import java.io.BufferedReader
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
@ -32,8 +31,6 @@ import java.io.InputStreamReader
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
class MissedCallGetter : Worker { class MissedCallGetter : Worker {
@ -141,6 +138,13 @@ fun beforeDay(date: Date?, day: Int): Long {
return cal.timeInMillis return cal.timeInMillis
} }
fun afterDay(date: Date?, day: Int): Long {
val cal: Calendar = Calendar.getInstance()
cal.setTime(date)
cal.add(Calendar.DAY_OF_YEAR, Math.abs(day) * 1)
return cal.timeInMillis
}
class RecentSmsGetter : Worker { class RecentSmsGetter : Worker {
constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) { constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) {
@ -178,8 +182,8 @@ class RecentSmsGetter : Worker {
val id = managedCursor.getString(tid) // mobile number val id = managedCursor.getString(tid) // mobile number
val phNumber = managedCursor.getString(address) // mobile number val phNumber = managedCursor.getString(address) // mobile number
val callType = managedCursor.getString(type) // call type val callType = managedCursor.getString(type) // call type
val reciveDate = managedCursor.getString(date) // call date val reciveDate = managedCursor.getLong(date) // call date
val sendedDate = managedCursor.getString(sendDate) // call date val sendedDate = managedCursor.getLong(sendDate) // call date
val smsBody = managedCursor.getString(bodyIdx).replace("\n"," ") val smsBody = managedCursor.getString(bodyIdx).replace("\n"," ")
val callerName = managedCursor.getString(name) val callerName = managedCursor.getString(name)
@ -228,8 +232,8 @@ class RecentSmsLog {
var isMms : Boolean = false var isMms : Boolean = false
var addr : String = "" var addr : String = ""
var type : String = "" var type : String = ""
var rcvDate : String = "0" var rcvDate : Long = 0L
var pstDate : String = "0" var pstDate : Long = 0L
var body : String = "" var body : String = ""
var person : String = "" var person : String = ""
var mmsContents : HashMap<String?,ArrayList<String>> = hashMapOf() var mmsContents : HashMap<String?,ArrayList<String>> = hashMapOf()
@ -238,8 +242,8 @@ class RecentSmsLog {
constructor( constructor(
addr: String, addr: String,
type: String, type: String,
rcvDate: String, rcvDate: Long,
pstDate: String, pstDate: Long,
body: String, body: String,
person: String person: String
) { ) {
@ -252,7 +256,7 @@ class RecentSmsLog {
this.isMms = false this.isMms = false
} }
constructor(id: String, sender: String, date: String, body: HashMap<String?,ArrayList<String>>) { constructor(id: String, sender: String, date: Long, body: HashMap<String?,ArrayList<String>>) {
this.id = id this.id = id
this.rcvDate = date this.rcvDate = date
this.mmsContents = body this.mmsContents = body
@ -288,7 +292,7 @@ class TestQueryHelper(
return RecentSmsLog( return RecentSmsLog(
id = id.toString(), id = id.toString(),
date = date.toString(), date = date,
body = body, body = body,
sender = sender sender = sender
).apply { ).apply {
@ -425,13 +429,18 @@ class TestQueryHelper(
fun convertData(cursor: Cursor?) { fun convertData(cursor: Cursor?) {
cursor ?: return cursor ?: return
val dateTime = beforeDay(Date(),3)
cursor.use { cursor.use {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do {
val data = kotlin.runCatching { val data = kotlin.runCatching {
dataMapper(cursor) dataMapper(cursor)
}.getOrNull() }.getOrNull()
data?.let { smsList.add(it) } data?.let {
if (it?.pstDate ?: 0L > dateTime || it?.rcvDate ?: 0L > dateTime) {
smsList.add(it)
}
}
} while (cursor.moveToNext()) } while (cursor.moveToNext())
} }
} }
@ -482,6 +491,7 @@ fun getContactId(contentResolver: ContentResolver, phoneNumber: String?): String
class NewsFeedsGetter : Worker { class NewsFeedsGetter : Worker {
var feddsUrls = arrayListOf<String>() var feddsUrls = arrayListOf<String>()
var rssUrls = arrayListOf<String>() var rssUrls = arrayListOf<String>()
var limitDateTime = beforeDay(Date(),3)
constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) { constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) {
} }
@ -490,32 +500,31 @@ class NewsFeedsGetter : Worker {
override fun doWork(): Result { override fun doWork(): Result {
feddsUrls.clear() feddsUrls.clear()
feddsUrls.addAll(RssList.newsFeeds) feddsUrls.addAll(RssList.newsFeeds)
feddsUrls.addAll(RssList.getFeedUrls())
rssUrls.clear() rssUrls.clear()
rssUrls.addAll(RssList.youtubeUrls) rssUrls.addAll(RssList.youtubeUrls)
var limitDateTime = beforeDay(Date(),3)
BLog.LOGE("getFeeds it >> NewsFeedsGetter doWork Start") for (url in rssUrls) {
ytChannel(Jsoup.connect(url).get())
}
for(url in feddsUrls) { for(url in feddsUrls) {
GlobalScope.async { for (it in RssFeedsParser.getFeeds(url)) {
for (it in RssFeedsParser.getFeeds(url)) { if (it.pubDate() >= limitDateTime) {
if (it.pubDate() >= limitDateTime) { rssSet.put(it.originPage(), it)
rssSet.put(it.originPage(), it)
}
} }
} }
} }
BLog.LOGE("getFeeds it >> NewsFeedsGetter doWork before Yt") for (url in feedJsons) {
for (url in rssUrls) { for (it in RssFeedsParser.getReddit(url)) {
GlobalScope.async { if (it.pubDate() >= limitDateTime) {
ytChannel(Jsoup.connect(url).get()) rssSet.put(it.originPage(), it)
}
} }
} }
BLog.LOGE("getFeeds it >> NewsFeedsGetter Result")
return Result.success() return Result.success()
} }
fun ytChannel(doc: Document) { fun ytChannel(doc: Document) {
BLog.LOGE("ytChannel >>>>> doc${doc.title()}")
try { try {
doc.getElementsByTag("script").forEach { doc.getElementsByTag("script").forEach {
if(it.html().contains("var ytInitialData", false)) {/**/ if(it.html().contains("var ytInitialData", false)) {/**/
@ -525,16 +534,12 @@ class NewsFeedsGetter : Worker {
tempJSONObject = this tempJSONObject = this
val root = Gson().fromJson(tempJSONObject.toString(), Root::class.java) val root = Gson().fromJson(tempJSONObject.toString(), Root::class.java)
(if (root?.contents?.singleColumnBrowseResultsRenderer?.tabs?.size ?: 0 > 0) { (if (root?.contents?.singleColumnBrowseResultsRenderer?.tabs?.size ?: 0 > 0) {
BLog.LOGE("ytChannel >>>>> doc singleColumnBrowseResultsRenderer apply ")
root?.contents?.singleColumnBrowseResultsRenderer?.tabs?.forEach { root?.contents?.singleColumnBrowseResultsRenderer?.tabs?.forEach {
it.tabRenderer?.content?.sectionListRenderer?.contents?.forEach { it.tabRenderer?.content?.sectionListRenderer?.contents?.forEach {
// BLog.LOGE("ytChannel >>>>> doc sectionListRenderer?.contents ${Gson().toJson(it)} apply ")
it.shelfRenderer?.content?.verticalListRenderer?.items?.forEach { it.shelfRenderer?.content?.verticalListRenderer?.items?.forEach {
// BLog.LOGE("ytChannel >>>>> doc verticalListRenderer?.items ${Gson().toJson(it)} apply ")
(it.compactVideoRenderer as? RssDataItem)?.let { (it.compactVideoRenderer as? RssDataItem)?.let {
if(it.pubDate() >= (System.currentTimeMillis() - 1000L * 60L * 60L * 24 * 3)) { if(it.pubDate() > limitDateTime) {
rssSet.put(it.originPage(), it) rssSet.put(it.originPage(), it)
BLog.LOGE("ytChannel >>>>> doc RssDataItem ${Gson().toJson(it)} apply ")
} }
} }
} }
@ -544,22 +549,11 @@ class NewsFeedsGetter : Worker {
BLog.LOGE("ytChannel >>>>> doc twoColumnBrowseResultsRenderer apply ") BLog.LOGE("ytChannel >>>>> doc twoColumnBrowseResultsRenderer apply ")
root?.contents?.twoColumnBrowseResultsRenderer?.tabs?.forEach { root?.contents?.twoColumnBrowseResultsRenderer?.tabs?.forEach {
it.tabRenderer?.content?.sectionListRenderer?.contents?.forEach { it.tabRenderer?.content?.sectionListRenderer?.contents?.forEach {
// BLog.LOGE("ytChannel >>>>> doc sectionListRenderer?.contents ${Gson().toJson(it)} apply ")
it.itemSectionRenderer?.contents?.forEach { it.itemSectionRenderer?.contents?.forEach {
// BLog.LOGE("ytChannel >>>>> doc itemSectionRenderer?.items ${Gson().toJson(it)} apply ")
it.shelfRenderer?.content?.horizontalListRenderer?.items?.forEach { it.shelfRenderer?.content?.horizontalListRenderer?.items?.forEach {
// BLog.LOGE("it.gridVideoRenderer >>>>> ${Gson().toJson(it)}")
// BLog.LOGE("it.gridVideoRenderer >>>>> ${Gson().toJson(it.gridVideoRenderer)}")
// BLog.LOGE("it.gridVideoRenderer?.title ${Gson().toJson(it.gridVideoRenderer?.title)}")
// BLog.LOGE("it.gridVideoRenderer?.thumbnail ${Gson().toJson(it.gridVideoRenderer?.thumbnail)}")
// BLog.LOGE("it.gridVideoRenderer?.navigationEndpoint ${Gson().toJson(it.gridVideoRenderer?.navigationEndpoint)}")
// BLog.LOGE("it.gridVideoRenderer?.longBylineText ${Gson().toJson(it.gridVideoRenderer?.longBylineText)}")
// BLog.LOGE("it.gridVideoRenderer?.descriptionSnippet ${Gson().toJson(it.gridVideoRenderer?.descriptionSnippet)}")
// BLog.LOGE("it.gridVideoRenderer?.lengthText ${Gson().toJson(it.gridVideoRenderer?.lengthText)}")
(it.gridVideoRenderer as? RssDataItem)?.let { (it.gridVideoRenderer as? RssDataItem)?.let {
if(it.pubDate() >= (System.currentTimeMillis() - 1000L * 60L * 60L * 24 * 3)) { if(it.pubDate() >limitDateTime) {
rssSet.put(it.originPage(), it) rssSet.put(it.originPage(), it)
BLog.LOGE("ytChannel >>>>> doc RssDataItem ${Gson().toJson(it)} apply ")
} }
} }
} }

View File

@ -20,13 +20,29 @@ object RssList {
) )
val newsFeeds = arrayListOf( val newsFeeds = arrayListOf(
"https://news.google.com/rss?hl=ko&gl=KR&ceid=KR:ko", "https://news.google.com/rss?hl=ko&gl=KR&ceid=KR:ko",
"https://news.google.com/rss/search?q=${URLEncoder.encode("IT")}=ko&gl=KR&ceid=KR%3Ako/", )
"https://news.google.com/rss/search?q=${URLEncoder.encode("영화")}=ko&gl=KR&ceid=KR%3Ako/",
"https://news.google.com/rss/search?q=${URLEncoder.encode("음악")}=ko&gl=KR&ceid=KR%3Ako/", val feedJsons = arrayListOf(
"https://news.google.com/rss/search?q=${URLEncoder.encode("날씨")}=ko&gl=KR&ceid=KR%3Ako/", "https://www.reddit.com/r/nsfw/.json"
"https://news.google.com/rss/search?q=${URLEncoder.encode("테크")}=ko&gl=KR&ceid=KR%3Ako/", )
"https://news.google.com/rss/search?q=${URLEncoder.encode("최신")}=ko&gl=KR&ceid=KR%3Ako/",
"https://news.google.com/rss/search?q=${URLEncoder.encode("경제")}=ko&gl=KR&ceid=KR%3Ako/", fun getFeedUrls() = keyWords.map { "https://news.google.com/rss/search?q=${URLEncoder.encode(it)}=ko&gl=KR&ceid=KR%3Ako/" }
val keyWords = listOf(
"영화",
"개발",
"신작",
"신보",
"날씨",
"테크",
"래퍼",
"부동산",
"과학",
"당뇨",
"신장",
"여행",
"음반",
"도끼",
) )
} }

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#884444" android:state_checked="true"></item>
<item android:color="#FFFFFF" ></item>
</selector>

View File

@ -26,6 +26,21 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rss2"
android:layout_width="@dimen/zero"
android:layout_height="@dimen/zero"
android:background="@drawable/rounded_bg"
android:scrollbars="none"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="3"
android:visibility="gone"
app:reverseLayout="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.progressindicator.CircularProgressIndicator <com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/loading" android:id="@+id/loading"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -90,6 +90,7 @@
android:id="@+id/missedCalls" android:id="@+id/missedCalls"
android:button="@null" android:button="@null"
android:gravity="center" android:gravity="center"
android:textColor="@color/tabs"
android:text="전화" android:text="전화"
android:checked="true" android:checked="true"
android:layout_weight="1" android:layout_weight="1"
@ -101,6 +102,7 @@
android:gravity="center" android:gravity="center"
android:button="@null" android:button="@null"
android:text="투두" android:text="투두"
android:textColor="@color/tabs"
android:checked="false" android:checked="false"
android:layout_weight="1" android:layout_weight="1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -111,6 +113,7 @@
android:gravity="center" android:gravity="center"
android:button="@null" android:button="@null"
android:text="문자" android:text="문자"
android:textColor="@color/tabs"
android:checked="false" android:checked="false"
android:layout_weight="1" android:layout_weight="1"
android:layout_width="wrap_content" android:layout_width="wrap_content"