This commit is contained in:
lunaticbum 2024-09-11 18:09:16 +09:00
parent 87263747f3
commit 7b9dab0891
26 changed files with 1000 additions and 266 deletions

View File

@ -90,4 +90,6 @@ dependencies {
implementation ("org.jsoup:jsoup:1.18.1")
implementation ("org.apache.commons:commons-text:1.12.0")
implementation("com.squareup.okhttp:okhttp:2.7.5")
// implementation ("androidx.window:window:1.0.0")
// implementation("io.github.vaneproject:hanguleditor:1.0.0")
}

View File

@ -20,6 +20,7 @@ package rasel.lunar.launcher
//import rasel.lunar.launcher.home.LauncherHome.Companion.rssSet
import android.Manifest
import android.annotation.SuppressLint
import android.app.NotificationManager
import android.appwidget.AppWidgetManager
import android.content.BroadcastReceiver
@ -37,12 +38,15 @@ import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.Environment.isExternalStorageManager
import android.os.Handler
import android.os.Looper
import android.print.PDFPrint
import android.provider.Settings
import android.telephony.TelephonyManager
import android.view.View
import android.view.WindowInsets
import android.view.WindowManager
import android.webkit.JavascriptInterface
import android.webkit.SslErrorHandler
import android.webkit.WebResourceError
@ -63,8 +67,12 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import androidx.window.layout.FoldingFeature
import androidx.window.layout.WindowLayoutInfo
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
@ -96,12 +104,15 @@ import rasel.lunar.launcher.model.RssTagItem
import rasel.lunar.launcher.model.getRssData
import rasel.lunar.launcher.model.getT
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.JamoUtils
import rasel.lunar.launcher.utils.NLService
import rasel.lunar.launcher.utils.RssList.jGuruMain
import rasel.lunar.launcher.utils.beforeDay
import rasel.lunar.launcher.utils.make0H
import rasel.lunar.launcher.workers.AppInfoGetter
import rasel.lunar.launcher.workers.ArcaGetter
import rasel.lunar.launcher.workers.ClienGetter
import rasel.lunar.launcher.workers.ContactInfoGetter
import rasel.lunar.launcher.workers.DCGetter
import rasel.lunar.launcher.workers.DotaxGetter
import rasel.lunar.launcher.workers.FmKoreaGetter
@ -160,16 +171,37 @@ internal class LauncherActivity : AppCompatActivity() {
}, 1, TimeUnit.SECONDS)
}
fun refreshCalls() {
var delay = 1L
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(CALL_WORK_TAG)
mWorkManager?.cancelAllWorkByTag(ContactInfoGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
CALL_WORK_TAG,
ContactInfoGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<ContactInfoGetter>(12, TimeUnit.HOURS)
.addTag(ContactInfoGetter.TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay = delay + 3L
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(AppInfoGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
AppInfoGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<AppInfoGetter>(12, TimeUnit.HOURS)
.addTag(AppInfoGetter.TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay = delay + 3L
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(RecentCallGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
RecentCallGetter.TAG,
ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<RecentCallGetter>(longTimePeriod, TimeUnit.MINUTES)
.addTag(CALL_WORK_TAG)
.addTag(RecentCallGetter.TAG)
.build())
}, 1, TimeUnit.SECONDS)
}, delay, TimeUnit.SECONDS)
}
fun refreshFeeds() {
var delay = 5L
Executors.newSingleThreadScheduledExecutor().schedule({
@ -300,11 +332,13 @@ internal class LauncherActivity : AppCompatActivity() {
// }
}
@SuppressLint("NewApi")
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
mWorkManager = WorkManager.getInstance(this)
DynamicColors.applyToActivityIfAvailable(this)
settingsPrefs = getSharedPreferences(PREFS_SETTINGS, 0)
AppCompatDelegate.setDefaultNightMode(settingsPrefs.getInt(KEY_APPLICATION_THEME, MODE_NIGHT_FOLLOW_SYSTEM))
@ -325,28 +359,7 @@ internal class LauncherActivity : AppCompatActivity() {
/* handle navigation back events */
handleBackPress()
refreshSms()
refreshCalls()
refreshFeeds()
}
override fun onDestroy() {
super.onDestroy()
appWidgetHost?.stopListening()
}
override fun onStart() {
super.onStart()
BLog.LOGE("LauncherActivity onStart()")
statusBarView()
setBgColor()
}
@RequiresApi(Build.VERSION_CODES.O_MR1)
override fun onResume() {
super.onResume()
BLog.LOGE("LauncherActivity onResume")
val cn: ComponentName = ComponentName(this, NLService::class.java)
val n = applicationContext.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
if (n.isNotificationListenerAccessGranted(cn)) {
@ -368,6 +381,25 @@ internal class LauncherActivity : AppCompatActivity() {
}
}
}
}
override fun onDestroy() {
super.onDestroy()
appWidgetHost?.stopListening()
}
override fun onStart() {
super.onStart()
BLog.LOGE("LauncherActivity onStart()")
statusBarView()
setBgColor()
}
@RequiresApi(Build.VERSION_CODES.O_MR1)
override fun onResume() {
super.onResume()
BLog.LOGE("LauncherActivity onResume")
}
private fun welcomeDialog() {
@ -397,6 +429,12 @@ internal class LauncherActivity : AppCompatActivity() {
}.show()
}
}
if (!needAsk) {
refreshSms()
refreshCalls()
refreshFeeds()
}
}
/* ask for the permissions */
@ -728,6 +766,18 @@ internal class LauncherActivity : AppCompatActivity() {
}
}
} else if(url?.contains("translate.google.com") == true) {
binding.searcher01.postDelayed({
binding.searcher01.evaluateJavascript(
"function getAll() {\n" +
" MyJavaScriptInterface.sendValueFromHtml(document.getElementsByTagName('html')[0].innerHTML)" +
" };getAll()"
) { result ->
(result as? String)?.let {
}
}
}, 6000L)
} else {
//if (url?.contains("guru", true) == true)
view?.evaluateJavascript(
@ -939,6 +989,29 @@ internal class LauncherActivity : AppCompatActivity() {
"date >>>>> ${date}" +
"")
}
} else if(lastedFinishedPageUrl?.contains("https://translate.google.com") == true){
callBackHandler.removeCallbacks(postNext)
val doc: Document = Jsoup.parse(result)
doc.getElementsByTag("span").forEach { span ->
// BLog.LOGE("on getHangule ${span.text()}")
if(span.hasAttr("jsaction") &&
span.attr("jsaction").contains("mouseout") &&
span.attr("jsaction").contains("contextmenu") &&
span.attr("jsaction").contains("click") &&
span.attr("jsaction").contains("mouseover")
) {
BLog.LOGE("on getHangule $span")
val resultString = span.text()
if (resultString != null && resultString.length > 0) {
callBackHandler.removeCallbacks(postNext)
callBack?.onConsoleLog("result::${span.text()}")
callBack = null
}
}
}.apply {
callBackHandler.removeCallbacks(postNext)
callBackHandler.postDelayed(postNext,25000L)
}
} else {
val doc: Document = Jsoup.parse(result)
callBack?.onConsoleLog("lastedFinishedPageUrl >>> ${doc}")
@ -947,8 +1020,17 @@ internal class LauncherActivity : AppCompatActivity() {
}
}
var postNext : Runnable = Runnable{
callBack?.collectComplete()
}
val callBackHandler = Handler(Looper.getMainLooper())
}
class MissD : RssDataInterface {
var link : String? = null
@ -981,6 +1063,10 @@ class MissD : RssDataInterface {
override fun category(): RssDataType {
return RssDataType.GURU
}
override fun getCho(): String? {
return JamoUtils.split(title!!).joinToString("")
}
}
fun beforeDay(date: Date): Long {
val cal: Calendar = Calendar.getInstance()

View File

@ -33,7 +33,6 @@ import android.os.Looper
import android.provider.ContactsContract
import android.util.Log
import android.view.KeyEvent
import android.view.KeyEvent.ACTION_UP
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
@ -44,18 +43,36 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import kotlinx.coroutines.GlobalScope
import io.realm.kotlin.ext.query
import io.realm.kotlin.notifications.InitialResults
import io.realm.kotlin.notifications.ResultsChange
import io.realm.kotlin.notifications.UpdatedResults
import io.realm.kotlin.query.RealmResults
import io.realm.kotlin.query.Sort
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.jsoup.Jsoup
import rasel.lunar.launcher.BuildConfig
import rasel.lunar.launcher.CommadCallabck
import rasel.lunar.launcher.LauncherActivity
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.databinding.AppDrawerBinding
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_APPS_COUNT
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_APPS_LAYOUT
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_APP_NAMES
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_SETTINGS
import rasel.lunar.launcher.model.AppInfo
import rasel.lunar.launcher.model.RssData
import rasel.lunar.launcher.utils.AlphabetToChosungMap
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.JamoUtils
import rasel.lunar.launcher.workers.WorkersDb
import java.net.URLEncoder
import java.text.Normalizer
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
@ -63,36 +80,25 @@ internal class AppDrawer : Fragment() {
private lateinit var binding: AppDrawerBinding
private var layoutType: Int = 0
// private var isSearchShown: Boolean = false
// private var isSearchShown: Boolean = false
private var isKeyboardShowing: Boolean = false
companion object {
private var packageManager: PackageManager? = null
private var appsAdapter: AppsAdapter? = null
private var contactAdapter : ContactAdapter? = null
private var packageInfoList: MutableList<ResolveInfo> = mutableListOf()
private var packageList = mutableListOf<Packages>()
var oringinPackageList = mutableListOf<Packages>()
val originContactList = arrayListOf<SimpleContact>()
// private val numberPattern = Pattern.compile("[0-9]")
// private val alphabetPattern = Pattern.compile("[A-Z]")
private var packageList = mutableListOf<AppInfo>()
@JvmStatic var settingsPrefs: SharedPreferences? = null
@JvmStatic var appNamesPrefs: SharedPreferences? = null
private fun appName(resolver: ResolveInfo): String {
if(appNamesPrefs?.contains(resolver.activityInfo.packageName) != null && appNamesPrefs?.getString(resolver.activityInfo.packageName,"")?.length ?: 0 > 0) {
BLog.LOGE("it.activityInfo.packageName >>>> ${resolver.activityInfo.packageName} == name : ${appNamesPrefs?.getString(resolver.activityInfo.packageName,"") ?: ""}")
return appNamesPrefs?.getString(resolver.activityInfo.packageName,"") ?: ""
} else {
return resolver.loadLabel(packageManager).toString().apply {
appNamesPrefs?.edit()?.putString(resolver.activityInfo.packageName, this)?.apply()
}
fun appName(resolver: ResolveInfo): String {
return resolver.loadLabel(packageManager).toString().apply {
appNamesPrefs?.edit()?.putString(resolver.activityInfo.packageName, this)?.apply()
}
}
private fun getCategory(category : Int) : String {
fun getCategory(category : Int) : String {
return when(category) {
ApplicationInfo.CATEGORY_UNDEFINED -> "UNDEFINED"
ApplicationInfo.CATEGORY_GAME -> "GAME"
@ -192,53 +198,8 @@ internal class AppDrawer : Fragment() {
}
}
val appNames = hashSetOf<AppInfo>()
val contactList = arrayListOf<SimpleContact>()
private fun GetContact() {
if (originContactList.size > 0) {
contactList.clear()
for (item in originContactList) {
contactList.add(item)
}
} else {
contactList.clear()
originContactList.clear()
val resolver = lActivity!!.contentResolver
val phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI
val projection = arrayOf(
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
)
try {
val cursor = resolver.query(phoneUri, projection, null, null, null)
if (cursor != null) {
while (cursor.moveToNext()) {
val idx =cursor.getColumnIndex(projection[0])
val nameIndex = cursor.getColumnIndex(projection[1])
val numberIndex = cursor.getColumnIndex(projection[2])
var contactId = cursor.getString(idx)
val name = cursor.getString(nameIndex)
var number = cursor.getString(numberIndex)
number = number.replace("-", "")
if (name?.length ?: 0 > 0 && number?.length ?: 0 > 0) {
contactList.add(SimpleContact(contactId,name, number))
originContactList.add(SimpleContact(contactId,name, number))
}
Log.d("GetContact", "이름 : $name 번호 : $number ")
}
}
// 데이터 계열은 반드시 닫아줘야 한다.
cursor?.close()
} catch ( e : Exception) {
e.printStackTrace()
}
}
}
fun openSearchApps(schemeString : String, pakage : String? = null) {
val gmmIntentUri = Uri.parse(schemeString)
@ -281,7 +242,7 @@ internal class AppDrawer : Fragment() {
dialog?.setMessage("${keyword} 검색 결과 '${packageList[0].appName}' 준비됨")
dialog?.setPositiveButton("실행") { s, d ->
runonUi {
startActivity(packageManager?.getLaunchIntentForPackage(packageList[0].packageName))
startActivity(packageManager?.getLaunchIntentForPackage(packageList[0].pkgName!!))
s.dismiss()
}
}
@ -289,14 +250,14 @@ internal class AppDrawer : Fragment() {
dialog?.setMessage("${keyword} 검색 결과 '${filted[0].appName}' 준비됨")
dialog?.setPositiveButton("${filted[0].appName} 실행") { s, d ->
runonUi {
startActivity(packageManager?.getLaunchIntentForPackage(filted[0].packageName))
startActivity(packageManager?.getLaunchIntentForPackage(filted[0].pkgName!!))
s.dismiss()
}
}
if(filted.size > 1) {
dialog?.setNeutralButton("${filted[1].appName} 실행") { s, d ->
runonUi {
startActivity(packageManager?.getLaunchIntentForPackage(filted[1].packageName))
startActivity(packageManager?.getLaunchIntentForPackage(filted[1].pkgName!!))
s.dismiss()
}
}
@ -366,23 +327,10 @@ internal class AppDrawer : Fragment() {
super.onResume()
BLog.LOGE("onResume")
fetchApps()
GetContact()
binding.appsCount.visibility = if (settingsPrefs!!.getBoolean(KEY_APPS_COUNT, true)) VISIBLE else GONE
// if (settingsPrefs!!.getInt(KEY_APPS_LAYOUT, 0) in 0..1) {
// appsAdapter?.updateGravity(settingsPrefs!!.getInt(KEY_DRAW_ALIGN, Gravity.CENTER))
// }
// openSearch()
// setKeyboardPadding()
contactList.sortBy { it.name }
contactAdapter?.updateData(contactList)
/* pop up the keyboard */
openSearch()
registCancelSearch()
BLog.LOGE("onResume after chechHandler.postDelayed(cancelSearch, 3000L)")
}
@ -420,35 +368,142 @@ internal class AppDrawer : Fragment() {
binding.appsList.adapter = appsAdapter
binding.contactList.adapter = contactAdapter
}
var appQuery : RealmResults<AppInfo>? = null
fun fetchApps(keyword : String? = null) {
WorkersDb.getRealm().apply {
var newQ = query<AppInfo>()
if (keyword != null && keyword.length > 0) {
if (JamoUtils.CHOSUNG.contains(keyword.split("")[0])) {
newQ = newQ.query("appName CONTAINS $0 OR appNameChosung CONTAINS $0 OR koreanName CONTAINS $0 OR alphaCho CONTAINS $0 OR category CONTAINS $0", keyword)
} else if(Pattern.matches("^[가-힣]*\$", keyword)){
newQ = newQ.query("appName CONTAINS $0 OR koreanName CONTAINS $0 OR category CONTAINS $0", keyword)
}else {
keyword.split("").forEach {
if (it.length > 0) {
newQ = newQ.query(
"appName CONTAINS $0 OR category CONTAINS $0 OR pkgName CONTAINS $0 OR appName CONTAINS $1 OR category CONTAINS $1 OR pkgName CONTAINS $1",
keyword.lowercase(),
keyword.uppercase()
)
}
}
}
}
appQuery = newQ.sort(Pair("clickCount", Sort.DESCENDING),Pair("lastUseDate",Sort.DESCENDING)).limit(20).find()
appQuery?.let {
if(it.size > 0) {
WorkersDb.getRealm().apply {
packageList.clear()
packageList.addAll(copyFromRealm(it))
BLog.LOGE("packageList >>> ${packageList.size}")
binding.appsList.post { if (packageList.size > 0) {
appsAdapter?.updateData(packageList)
} }
// val clo = packageList.clone()
// appNames.clear()
// appNames.addAll(packageList.filter { it.koreanName?.trim()?.length ?: 0 < 1 })
// getHangule()
}
}
}
}
fetcContact(keyword)
}
/* update app list with app and package name */
fun fetchApps() {
packageList.clear()
oringinPackageList.clear()
try {
packageInfoList = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager?.queryIntentActivities(
Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER),
PackageManager.ResolveInfoFlags.of(0)
)
} else {
(packageManager?.queryIntentActivities(
Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER), 0
))
})?.apply {
removeIf { it.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID) }
forEach { oringinPackageList.add(Packages(it.activityInfo.packageName, normalize(appName(it)), getCategory(it.activityInfo.applicationInfo.category))) }
oringinPackageList.sortBy { it.appName }
packageList.addAll(
oringinPackageList
)
binding.appsList.post { if (packageList.size > 0) {
appsAdapter?.updateData(packageList)
} }
}!!
var contactQuery : RealmResults<SimpleContact>? = null
fun fetcContact(keyword : String? = null) {
WorkersDb.getRealm().apply {
var newQ = query<SimpleContact>()
if (keyword != null && keyword.length > 0) {
if(Pattern.matches("^[0-9]*\$", keyword)){
keyword.split("").forEach {
if (it.length > 0) newQ = newQ.query("phoneNumber CONTAINS $0", keyword)
}
} else {
newQ = newQ.query(
"name CONTAINS $0 OR chosung CONTAINS $0",
keyword
)
}
}
} catch (e : Exception) {e.printStackTrace()}
contactQuery = newQ.sort(Pair("touchCount", Sort.DESCENDING),Pair("lastedTouchDateTime",Sort.DESCENDING)).find()
contactQuery?.let {
if (it.size > 0)
WorkersDb.getRealm().apply {
contactList.clear()
contactList.addAll(copyFromRealm(it).toList())
BLog.LOGE("packageList >>> ${contactList.size}")
binding.contactList.post { if (contactList.size > 0) {
contactAdapter?.updateData(contactList)
} }
}
}
}
}
fun getHangule() {
BLog.LOGE("on getHangule")
Executors.newSingleThreadScheduledExecutor().schedule({
if (appNames.size > 0) {
val info = appNames.first()
appNames.remove(info)
if (info.koreanName?.length ?: 0 > 0 || info.appNameChosung?.length ?: 0 > 0) {
getHangule()
} else {
BLog.LOGE("on getHangule ${info.appName}")
if (Pattern.matches("^[a-zA-Z]*$", info.appName)) {
// Jsoup.connect("https://translate.google.com/?hl=ko&sl=en&tl=ko&text=${info.appName}&op=translate").get().let { trans ->
// BLog.LOGE("on getHangule ${trans.title()}")
// trans.getElementsByTag("span").forEach {
// BLog.LOGE("on getHangule ${it.text()}")
// if(it.hasAttr("jsaction") &&
// it.attr("jsaction").contains("mouseout") &&
// it.attr("jsaction").contains("contextmenu") &&
// it.attr("jsaction").contains("mouseover")
// ) {
// BLog.LOGE("on getHangule $it")
// }
// }
//
// }.apply {
// getHangule()
// }
Handler(Looper.getMainLooper()).post {
LauncherActivity.Companion.lActivity?.doWebParseStart(
"https://translate.google.com/?hl=ko&sl=en&tl=ko&text=${info.appName}&op=translate",
object : CommadCallabck {
override fun onConsoleLog(log: String) {
if (log.contains("result::")) {
val appHangulName = log.split("result::")[1]
if(appHangulName?.length ?: 0 > 0) {
info.appNameChosung = JamoUtils.split(appHangulName).joinToString("")
info.koreanName = appHangulName
BLog.LOGE("appHangulName >>> $appHangulName")
BLog.LOGE("appHangulName >>> ${info.appNameChosung}")
WorkersDb.update(info)
getHangule()
}
}
}
override fun collectComplete() {
getHangule()
}
})
}
} else {
info.appNameChosung = JamoUtils.split(info.appName).joinToString("")
info.koreanName = info.appName
WorkersDb.update(info)
getHangule()
BLog.LOGE("on getHangule to next")
}
}
}
},5,TimeUnit.SECONDS)
}
private fun getAlphabetItems() {
@ -480,73 +535,52 @@ internal class AppDrawer : Fragment() {
var lastSearchString : String = ""
private fun filterAppsList(searchString: String) {
/* check each app name and add if it matches the search string */
if (searchString.length > 0 && (lastSearchStringLength != searchString.length || lastSearchString.equals(searchString) == false)) {
BLog.LOGE("START FILTER")
packageList.clear()
for (pkg in oringinPackageList) {
if (pkg.appName.contains(searchString,true) || pkg.category.contains(searchString,true) || pkg.packageName.contains(searchString,true)) {
BLog.LOGE("pkg >>> ${pkg.category} , ${pkg.appName}")
packageList.add(pkg)
}
}
packageList.sortBy { it.appName }
BLog.LOGE("MIDDLE FILTER")
appsAdapter?.updateData(packageList)
contactList.clear()
for (item in originContactList) {
if (item.name.contains(searchString) || item.phoneNumber.contains(searchString)) {
contactList.add(item)
}
}
contactList.sortBy { it.name }
contactAdapter?.updateData(contactList)
BLog.LOGE("END FILTER")
} else if(lastSearchStringLength == 0){
contactList.clear()
for (item in originContactList) {
contactList.add(item)
}
packageList.clear()
for (resolver in oringinPackageList) {
packageList.add(resolver)
}
appsAdapter?.updateData(packageList)
contactAdapter?.updateData(contactList)
} else {
afterClearSearch()
}
fetchApps(searchString)
// if (searchString.length > 0 && (lastSearchStringLength != searchString.length || lastSearchString.equals(searchString) == false)) {
// BLog.LOGE("START FILTER")
// packageList.clear()
// for (pkg in oringinPackageList) {
// if (pkg.appName!!.contains(searchString,true) || pkg.category!!.contains(searchString,true) || pkg.pkgName!!.contains(searchString,true)) {
// BLog.LOGE("pkg >>> ${pkg.category} , ${pkg.appName}")
// packageList.add(pkg)
// }
// }
// packageList.sortBy { it.appName }
// BLog.LOGE("MIDDLE FILTER")
//
// appsAdapter?.updateData(packageList)
//
// contactList.clear()
// for (item in originContactList) {
// if (item.name!!.contains(searchString) || item.phoneNumber!!.contains(searchString)) {
// contactList.add(item)
// }
// }
// contactList.sortBy { it.name }
// contactAdapter?.updateData(contactList)
// BLog.LOGE("END FILTER")
//
//
// } else if(lastSearchStringLength == 0){
// contactList.clear()
// for (item in originContactList) {
// contactList.add(item)
// }
// packageList.clear()
// for (resolver in oringinPackageList) {
// packageList.add(resolver)
// }
// appsAdapter?.updateData(packageList)
// contactAdapter?.updateData(contactList)
// } else {
// afterClearSearch()
//
// }
lastSearchString = searchString
lastSearchStringLength = searchString.length
registCancelSearch()
}
private fun afterClearSearch() {
contactList.clear()
packageList.clear()
for (item in originContactList) {
contactList.add(item)
}
for (resolver in oringinPackageList) {
packageList.add(resolver)
}
packageList.sortBy { it.appName }
contactList.sortBy { it.name }
appsAdapter?.updateData(packageList)
contactAdapter?.updateData(contactList)
}
private fun normalize(str: String): String {
val normalizedString =
Normalizer.normalize(str.replace("\\W".toRegex(), ""), Normalizer.Form.NFC)
val pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+")
return pattern.matcher(normalizedString).replaceAll("").toLowerCase()
}
private fun openSearch() {
binding.searchInput.apply {
visibility = VISIBLE
@ -594,3 +628,9 @@ internal class AppDrawer : Fragment() {
}
fun normalize(str: String): String {
val normalizedString =
Normalizer.normalize(str.replace("\\W".toRegex(), ""), Normalizer.Form.NFC)
val pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+")
return pattern.matcher(normalizedString).replaceAll("").toLowerCase()
}

View File

@ -53,7 +53,6 @@ import com.google.gson.Gson
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R
import rasel.lunar.launcher.apps.AppDrawer.Companion.appNamesPrefs
import rasel.lunar.launcher.apps.AppDrawer.Companion.oringinPackageList
import rasel.lunar.launcher.databinding.ActivityBrowserDialogBinding
import rasel.lunar.launcher.databinding.AppInfoDialogBinding
import rasel.lunar.launcher.databinding.AppMenuBinding

View File

@ -18,7 +18,6 @@
package rasel.lunar.launcher.apps
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.util.TypedValue
import android.view.Gravity
@ -26,18 +25,23 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.view.updatePadding
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.textview.MaterialTextView
import io.realm.kotlin.ext.query
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.async
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R
import rasel.lunar.launcher.apps.IconPackManager.Companion.getDrawableIconForPackage
import rasel.lunar.launcher.databinding.AppsChildBinding
import rasel.lunar.launcher.helpers.UniUtils.Companion.dpToPx
import rasel.lunar.launcher.model.AppInfo
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.EnToKo.engToKor
import rasel.lunar.launcher.workers.WorkersDb
import java.util.regex.Matcher
import java.util.regex.Pattern
internal class AppsAdapter(
@ -46,7 +50,7 @@ internal class AppsAdapter(
private val fragmentManager: FragmentManager,
private val appsCount: TextView) : RecyclerView.Adapter<AppsAdapter.AppsViewHolder>() {
private var oldList = mutableListOf<Packages>()
private var oldList = mutableListOf<AppInfo>()
// private var appGravity: Int = Gravity.CENTER
companion object {
@ -60,12 +64,14 @@ internal class AppsAdapter(
val item = oldList[i]
holder.view.apply {
childTextview.text = item.appName
appIconTwo.visibility = View.VISIBLE
MainScope().async {
getDrawableIconForPackage(item.packageName, packageManager.getApplicationIcon(item.packageName)) {
getDrawableIconForPackage(item.pkgName, packageManager.getApplicationIcon(item.pkgName!!)) {
appIconTwo.post { appIconTwo.setImageDrawable(it) }
} }
childTextview.apply {
@ -77,13 +83,23 @@ internal class AppsAdapter(
holder.view.root.apply {
/* on click - open app */
setOnClickListener {
context.startActivity(packageManager.getLaunchIntentForPackage(item.packageName))
WorkersDb.getRealm().apply {
writeBlocking {
var result = query<AppInfo>("pkgName == $0",item.pkgName).find()
if(result.size > 0) {
val app = result.first()
app.clickCount = app.clickCount + 1
app.lastUseDate = Math.max(app.lastUseDate, System.currentTimeMillis())
}
}
}
context.startActivity(packageManager.getLaunchIntentForPackage(item.pkgName!!))
}
/* on long click - open app menu */
setOnLongClickListener {
AppMenu().apply {
}.show(fragmentManager, item.packageName)
}.show(fragmentManager, item.pkgName)
true
}
}
@ -94,7 +110,7 @@ internal class AppsAdapter(
inner class AppsViewHolder(var view: AppsChildBinding) : RecyclerView.ViewHolder(view.root)
/* update app list */
fun updateData(newList: List<Packages>) {
fun updateData(newList: List<AppInfo>) {
val diffUtilResult = DiffUtil.calculateDiff(AppsDiffUtil(oldList, newList))
//
diffUtilResult.dispatchUpdatesTo(this)
@ -114,14 +130,14 @@ data class Packages (
)
internal class AppsDiffUtil(
private val oldList: List<Packages>, private val newList: List<Packages>
private val oldList: List<AppInfo>, private val newList: List<AppInfo>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].packageName == newList[newItemPosition].packageName
oldList[oldItemPosition].pkgName == newList[newItemPosition].pkgName
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition] == newList[newItemPosition]

View File

@ -33,6 +33,8 @@ import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.textview.MaterialTextView
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.PrimaryKey
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.async
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
@ -42,6 +44,9 @@ import rasel.lunar.launcher.databinding.AppsChildBinding
import rasel.lunar.launcher.databinding.ContactItemBinding
import rasel.lunar.launcher.helpers.UniUtils.Companion.dpToPx
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.JamoUtils
import rasel.lunar.launcher.workers.RecentCallGetter
import java.util.Date
internal class ContactAdapter (
@ -60,13 +65,14 @@ internal class ContactAdapter (
override fun onBindViewHolder(holder: ContactViewHolder, i: Int) {
val item = oldList[i]
BLog.LOGE("name >>> ${item.name} :: ${item.touchCount} :: ${RecentCallGetter.dateFormat.format(
Date(item.lastedTouchDateTime)
)}")
holder.view.apply {
name.text = item.name
number.text= item.phoneNumber
}
holder.view.root.apply {
/* on click - open app */
setOnClickListener {
@ -88,12 +94,18 @@ internal class ContactAdapter (
/* update app list */
fun updateData(newList: List<SimpleContact>) {
val diffUtilResult = DiffUtil.calculateDiff(ContactDiffUtil(oldList, newList))
diffUtilResult.dispatchUpdatesTo(this)
oldList.clear()
oldList.addAll(newList)
newList.size.let {
appsSize = it
synchronized(oldList) {
try {
val diffUtilResult = DiffUtil.calculateDiff(ContactDiffUtil(oldList, newList))
diffUtilResult.dispatchUpdatesTo(this)
oldList.clear()
oldList.addAll(newList)
newList.size.let {
appsSize = it
}
}catch (e : IndexOutOfBoundsException) {
}
}
}
@ -112,7 +124,25 @@ internal class ContactAdapter (
}
}
data class SimpleContact(val id : String,val name : String ,val phoneNumber : String)
class SimpleContact : RealmObject {
@PrimaryKey
var id : String? = ""
var name : String? = ""
var chosung : String? = ""
var phoneNumber : String? = ""
var touchCount = 0
var lastedTouchDateTime = 0L
constructor(id: String, name: String, phoneNumber: String) {
this.id = id
this.name = name
this.phoneNumber = phoneNumber
chosung = JamoUtils.split(name).joinToString("")
}
constructor()
}
internal class ContactDiffUtil(
private val oldList: List<SimpleContact>, private val newList: List<SimpleContact>

View File

@ -62,7 +62,9 @@ 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.refreshCalls
import rasel.lunar.launcher.LauncherActivity.Companion.refreshFeeds
import rasel.lunar.launcher.LauncherActivity.Companion.refreshSms
import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.FeedsBinding
import rasel.lunar.launcher.feeds.rss.RssAdapter
@ -313,6 +315,8 @@ internal class Feeds : Fragment() , CommadCallabck {
"req" -> {
refreshFeeds()
refreshCalls()
refreshSms()
consoleLog("excute refreshFeeds()")
}

View File

@ -30,6 +30,7 @@ import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.PatternMatcher
import android.provider.AlarmClock
import android.view.LayoutInflater
import android.view.View
@ -64,6 +65,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.json.JSONArray
import org.json.JSONObject
@ -110,6 +112,7 @@ import java.nio.charset.Charset
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.regex.Pattern
internal class LauncherHome : Fragment() {
@ -123,7 +126,7 @@ internal class LauncherHome : Fragment() {
companion object {
var home : LauncherHome? = null
var lastedFinishedPageUrl : String = ""
var recentCalls = arrayListOf<RecentCall>()
// var recentCalls = arrayListOf<RecentCall>()
var callList = arrayListOf<RecentCall>()
var smsList = arrayListOf<RecentSms>()
var listTags = arrayListOf<RssDataInterface>()
@ -147,8 +150,7 @@ internal class LauncherHome : Fragment() {
}
val callUpdate = Runnable {
binding.missedCalls.text = "최근 통화 [${recentCalls.size}]"
BLog.LOGE("observeForever missedCalls.size >>> ${recentCalls.size}")
chooseAdpater()
}
@ -352,17 +354,33 @@ internal class LauncherHome : Fragment() {
var rQ = WorkersDb.getRealm().query<RssData>().query("pubDate > $0", beforeDay(Date(),3))
if(keyword.length > 0)
keyword.split("").forEach {
if (Character.codePointAt(it, 0) in 0xAC00..0xD79D) {
rQ = rQ.query("title CONTAINS $0 OR chosung CONTAINS $1 ", it, JamoUtils.splitOne(it))
} else {
rQ = rQ.query("title CONTAINS $0 OR title CONTAINS $1", it.toUpperCase(), it.toLowerCase())
BLog.LOGE("queryInfos it >>> ${it}")
if (it.length > 0) {
if (JamoUtils.CHOSUNG.contains(it)) {
rQ = rQ.query(
"title CONTAINS $0 OR chosung CONTAINS $1 ",
it,
it
)
} else if(Pattern.matches("^[가-힣]*\$", it)){
rQ = rQ.query(
"title CONTAINS $0",
it
)
}else {
rQ = rQ.query(
"title CONTAINS $0 OR title CONTAINS $1",
it.toUpperCase(),
it.toLowerCase()
)
}
}
}
category?.let {
rQ = rQ.query("category == $0", it)
}
BLog.LOGE("queryInfos rQ.description() >>>>> ${rQ.description()}")
//limit(1000)
mRssDataResult = rQ.sort("pubDate ", Sort.DESCENDING).find()
BLog.LOGE("${this} ::::: queryInfos after query find >>>> ")
@ -573,21 +591,19 @@ internal class LauncherHome : Fragment() {
binding.smsList.visibility = View.INVISIBLE
binding.infoList.visibility = View.INVISIBLE
binding.notiList.visibility = View.INVISIBLE
if (binding.missedCalls.isSelected) {
if (recentCalls.size > 0) {
try {
callList.clear()
callList.addAll(recentCalls)
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
} catch (e : Exception) {
}
var dateParam = beforeDay(Date(),7).toString()
if (binding.missedCalls.isSelected) {
WorkersDb.getRealm().apply {
val result = query<RecentCall>().query("callDayTime >= $0", dateParam).sort("callDayTime", Sort.DESCENDING).find()
callList.clear()
callList.addAll(copyFromRealm(result))
binding.missedCalls.text = "최근 통화 [${callList.size}]"
binding.mainList.visibility = View.VISIBLE
mMissedCallsAdapter.updateData(callList)
binding.recentSms.isSelected = false
binding.otherCheck.isSelected = false
binding.notice.isSelected = false
}
} else if(binding.recentSms.isSelected){
if (smsList.size > 0) {

View File

@ -0,0 +1,19 @@
package rasel.lunar.launcher.model
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.PrimaryKey
class AppInfo : RealmObject {
var appName : String? = null
var appNameChosung : String? = null
var koreanName : String? = null
var alphaCho : String? = null
@PrimaryKey
var pkgName : String? = null
var clickCount : Int = 0
var lastUseDate : Long = 0L
var category : String? = null
}

View File

@ -103,6 +103,9 @@ class Arca : RssDataInterface {
override fun category(): RssDataType {
return RssDataType.Arca
}
override fun getCho(): String? {
return JamoUtils.split(title!!).joinToString("")
}
}
@ -169,6 +172,9 @@ open class DcInside : RssDataInterface {
return RssDataType.DcInside
}
override fun getCho(): String? {
return JamoUtils.split(title!!).joinToString("")
}
}
@ -205,7 +211,7 @@ class RssData : RealmObject, RssDataInterface {
}
else -> title ?: ""
}.apply {
chosung = JamoUtils.split(this).joinToString { "" }
chosung = JamoUtils.split(this).joinToString("")
}
}
@ -240,6 +246,9 @@ class RssData : RealmObject, RssDataInterface {
return mRssDataType!!
}
override fun getCho(): String? {
return chosung
}
}
@ -319,6 +328,9 @@ open class Dotax(var pageLink : String,
override fun category(): RssDataType {
return RssDataType.Dotax
}
override fun getCho(): String? {
return JamoUtils.split(title!!).joinToString("")
}
}
data class FmKorea(var apageLink : String,
@ -341,6 +353,7 @@ fun RssDataInterface.getRssData() : RssData {
originPage = this@getRssData.originPage()
thumbnail = this@getRssData.thumbnailUrl()
pubDate = this@getRssData.pubDate()
chosung = this@getRssData.getCho()
category = this@getRssData.category().name
}
}

View File

@ -2,6 +2,7 @@ package rasel.lunar.launcher.model
import rasel.lunar.launcher.todos.Image
import rasel.lunar.launcher.todos.Source
import rasel.lunar.launcher.utils.JamoUtils
class Child {
@ -275,7 +276,9 @@ class Data : RssDataInterface {
RssDataType.REDDIT_nsfw
} else RssDataType.REDDIT
}
override fun getCho(): String? {
return JamoUtils.split(title!!).joinToString("")
}
}
class Gif {

View File

@ -51,6 +51,6 @@ interface RssDataInterface {
fun description() : String
fun pubDate() : Long
fun category() : RssDataType
fun getCho() : String?
}

View File

@ -1,5 +1,7 @@
package rasel.lunar.launcher.model
import rasel.lunar.launcher.utils.JamoUtils
open class RssItem : RssDataInterface {
var model : String = ""
var title : String = ""
@ -51,6 +53,10 @@ open class RssItem : RssDataInterface {
}
fun isValid() = (((pageLink.length ?:0) > 0) && ((title.length ?:0) > 0)&& ((image.length ?:0) > 0))
override fun getCho(): String? {
return JamoUtils.split(title!!).joinToString("")
}
}
class MostItem : RssItem , RssDataInterface {
@ -81,5 +87,7 @@ class MostItem : RssItem , RssDataInterface {
return RssDataType.Most
}
override fun getCho(): String? {
return JamoUtils.split(title!!).joinToString("")
}
}

View File

@ -1,5 +1,7 @@
package rasel.lunar.launcher.model
import rasel.lunar.launcher.utils.JamoUtils
class RssTagItem : RssDataInterface {
var link : String = ""
var tagTitle = ""
@ -38,4 +40,7 @@ class RssTagItem : RssDataInterface {
}catch (e : Exception) {}
}
}
override fun getCho(): String? {
return JamoUtils.split(tagTitle!!).joinToString("")
}
}

View File

@ -1,6 +1,7 @@
package rasel.lunar.launcher.model
import org.json.JSONObject
import rasel.lunar.launcher.utils.JamoUtils
import rasel.lunar.launcher.utils.afterDay
import rasel.lunar.launcher.utils.beforeDay
import java.util.Date
@ -1644,6 +1645,9 @@ open class VideoRenderer : RssDataInterface {
override fun category(): RssDataType {
return RssDataType.YOUTUBE
}
override fun getCho(): String? {
return JamoUtils.split(title()).joinToString("")
}
}
class ViewCountText {

View File

@ -7,6 +7,7 @@ import org.xmlpull.v1.XmlPullParserException
import rasel.lunar.launcher.model.RssDataInterface
import rasel.lunar.launcher.model.RssDataType
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.JamoUtils
import rasel.lunar.launcher.utils.beforeDay
import java.io.IOException
import java.io.InputStream
@ -211,4 +212,7 @@ class RssFeed : RssDataInterface {
override fun category(): RssDataType {
return RssDataType.NewsFeed
}
override fun getCho(): String? {
return JamoUtils.split(title()).joinToString("")
}
}

View File

@ -34,6 +34,7 @@ import com.squareup.picasso.Picasso
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.ListItemWithBinding
import rasel.lunar.launcher.model.RssData
import rasel.lunar.launcher.model.RssDataInterface
import rasel.lunar.launcher.model.RssDataType
import rasel.lunar.launcher.utils.BLog
@ -147,7 +148,6 @@ internal class RssItemAdapter (
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RssTag, position: Int) {
val rssData = rssDataItemLis[position]
if (rssData.pubDate() > 1000L) {
holder.view.date.text = dateFormat.format(Date(rssData.pubDate()))
} else {

View File

@ -5,6 +5,7 @@ import rasel.lunar.launcher.model.RssDataInterface
import rasel.lunar.launcher.model.RssDataType
import rasel.lunar.launcher.model.YTBImage
import rasel.lunar.launcher.model.YTBSource
import rasel.lunar.launcher.utils.JamoUtils
import rasel.lunar.launcher.utils.afterDay
import rasel.lunar.launcher.utils.beforeDay
import java.util.Date
@ -1648,6 +1649,10 @@ open class VideoRenderer : RssDataInterface {
override fun category(): RssDataType {
return RssDataType.YOUTUBE
}
override fun getCho(): String? {
return JamoUtils.split(title()).joinToString("")
}
}
class ViewCountText {

View File

@ -0,0 +1,45 @@
package rasel.lunar.launcher.utils
object AlphabetToChosungMap {
val map = hashMapOf<String,String>(
Pair("a","o"),
Pair("b",""),
Pair("c","ㅋㅅ"),
Pair("d",""),
Pair("e","o"),
Pair("f",""),
Pair("g","ㄱㅈ"),
Pair("h",""),
Pair("i","o"),
Pair("j",""),
Pair("k",""),
Pair("l",""),
Pair("m",""),
Pair("n",""),
Pair("o","o"),
Pair("p",""),
Pair("q",""),
Pair("r",""),
Pair("s",""),
Pair("t",""),
Pair("u","o"),
Pair("v",""),
Pair("w","o"),
Pair("x","ㅋㅅㅈ"),
Pair("y",""),
Pair("z",""),
Pair("10","ㅅㅌ"),
Pair("0","ㅇㅈ"),
Pair("9","ㄱㄴ"),
Pair("8","ㅍㅇ"),
Pair("7","ㅊㅅ"),
Pair("6","ㅇㅅ"),
Pair("5","ㅇㅍ"),
Pair("4","ㅅㅍ"),
Pair("3","ㅅㅆ"),
Pair("2","ㅇㅌ"),
Pair("1",""),
)
fun getCho(string : String) = string.split("").filter { it.length > 0 && map.containsKey(it.toLowerCase()) }.map { map.get(it) }.joinToString("")
}

View File

@ -0,0 +1,238 @@
package rasel.lunar.launcher.utils
import java.util.Scanner
import java.util.regex.Matcher
object EnToKo {
var ignoreChars: String = "`1234567890-=[]\\;',./~!@#$%^&*()_+{}|:\"<>? "
/** * 영어를 한글로... */
fun engToKor(eng: String): String {
val sb = StringBuffer()
var initialCode = 0
var medialCode = 0
var finalCode = 0
var tempMedialCode: Int
var tempFinalCode: Int
var i = 0
while (i < eng.length) {
// 숫자특수문자 처리
if (ignoreChars.indexOf(eng.substring(i, i + 1)) > -1) {
sb.append(eng.substring(i, i + 1))
i++
continue
}
// 초성코드 추출
initialCode = getCode(CodeType.chosung, eng.substring(i, i + 1))
i++
// 다음문자로
// 중성코드 추출
tempMedialCode = getDoubleMedial(i, eng)
// 두 자로 이루어진 중성코드 추출
if (tempMedialCode != -1) {
medialCode = tempMedialCode
i += 2
} else {
// 없다면,
medialCode = getSingleMedial(i, eng)
// 한 자로 이루어진 중성코드 추출
i++
}
// 종성코드 추출
tempFinalCode = getDoubleFinal(i, eng)
// 두 자로 이루어진 종성코드 추출
if (tempFinalCode != -1) {
finalCode = tempFinalCode
// 그 다음의 중성 문자에 대한 코드를 추출한다.
tempMedialCode = getSingleMedial(i + 2, eng)
if (tempMedialCode != -1) {
// 코드 값이 있을 경우
finalCode = getSingleFinal(i, eng)
// 종성 코드 값을 저장한다.
} else {
i++
}
} else {
// 코드 값이 없을 경우 ,
tempMedialCode = getSingleMedial(i + 1, eng)
// 그 다음의 중성 문자에 대한 코드 추출.
if (tempMedialCode != -1) {
// 그 다음에 중성 문자가 존재할 경우,
finalCode = 0 // 종성 문자는 없음.
i--
} else {
finalCode = getSingleFinal(i, eng)
// 종성 문자 추출
if (finalCode == -1) {
finalCode = 0
i--
// 초성,중성 + 숫자,특수문자,
//기호가 나오는 경우 index를 줄임.
}
}
}
// 추출한 초성 문자 코드,
//중성 문자 코드, 종성 문자 코드를 합한 후 변환하여 스트링버퍼에 넘김
sb.append((0xAC00 + initialCode + medialCode + finalCode).toChar())
i++
}
return sb.toString()
}
/** * 해당 문자에 따른 코드를 추출한다. * * @param type * 초성 : chosung, 중성 : jungsung, 종성 : jongsung 구분 * @param char 해당 문자 */
private fun getCode(type: CodeType, c: String): Int {
// 초성
val init = "rRseEfaqQtTdwWczxvg"
// 중성
val mid = arrayOf(
"k",
"o",
"i",
"O",
"j",
"p",
"u",
"P",
"h",
"hk",
"ho",
"hl",
"y",
"n",
"nj",
"np",
"nl",
"b",
"m",
"ml",
"l"
)
// 종성
val fin = arrayOf(
"r",
"R",
"rt",
"s",
"sw",
"sg",
"e",
"f",
"fr",
"fa",
"fq",
"ft",
"fx",
"fv",
"fg",
"a",
"q",
"qt",
"t",
"T",
"d",
"w",
"c",
"z",
"x",
"v",
"g"
)
when (type) {
CodeType.chosung -> {
val index = init.indexOf(c)
if (index != -1) {
return index * 21 * 28
}
}
CodeType.jungsung -> {
var i = 0
while (i < mid.size) {
if (mid[i] == c) {
return i * 28
}
i++
}
}
CodeType.jongsung -> {
var i = 0
while (i < fin.size) {
if (fin[i] == c) {
return i + 1
}
i++
}
}
else -> println("잘못된 타입 입니다")
}
return -1
}
// 한 자로 된 중성값을 리턴한다
// 인덱스를 벗어낫다면 -1을 리턴
private fun getSingleMedial(i: Int, eng: String): Int {
return if ((i + 1) <= eng.length) {
getCode(CodeType.jungsung, eng.substring(i, i + 1))
} else {
-1
}
}
// 두 자로 된 중성을 체크하고, 있다면 값을 리턴한다.
// 없으면 리턴값은 -1
private fun getDoubleMedial(i: Int, eng: String): Int {
val result: Int
if ((i + 2) > eng.length) {
return -1
} else {
result = getCode(CodeType.jungsung, eng.substring(i, i + 2))
return if (result != -1) {
result
} else {
-1
}
}
}
// 한 자로된 종성값을 리턴한다
// 인덱스를 벗어낫다면 -1을 리턴
private fun getSingleFinal(i: Int, eng: String): Int {
return if ((i + 1) <= eng.length) {
getCode(CodeType.jongsung, eng.substring(i, i + 1))
} else {
-1
}
}
// 두 자로된 종성을 체크하고, 있다면 값을 리턴한다.
// 없으면 리턴값은 -1
private fun getDoubleFinal(i: Int, eng: String): Int {
return if ((i + 2) > eng.length) {
-1
} else {
getCode(CodeType.jongsung, eng.substring(i, i + 2))
}
}
// 코드타입 - 초성, 중성, 종성
internal enum class CodeType {
chosung, jungsung, jongsung
}
}

View File

@ -17,7 +17,8 @@ object JamoUtils {
"", "", "", "", "", "",
)
fun split(target: String): List<String> {
fun split(target: String?): List<String> {
if (target.isNullOrEmpty()) return arrayListOf()
return target.split("")
.filter(String::isNotEmpty)
.map(JamoUtils::splitOne)

View File

@ -0,0 +1,63 @@
package rasel.lunar.launcher.workers
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.os.Build
import androidx.work.WorkerParameters
import io.realm.kotlin.ext.query
import rasel.lunar.launcher.BuildConfig
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.apps.AppDrawer.Companion.appName
import rasel.lunar.launcher.apps.AppDrawer.Companion.getCategory
import rasel.lunar.launcher.apps.normalize
import rasel.lunar.launcher.model.AppInfo
import rasel.lunar.launcher.utils.AlphabetToChosungMap
import rasel.lunar.launcher.utils.JamoUtils
class AppInfoGetter : BaseGetter {
companion object {
val TAG = "AppInfoGetter"
}
constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) {
}
override fun realWork(): Result {
try {
var packageManager = lActivity?.packageManager
var packageInfoList: MutableList<ResolveInfo> = mutableListOf()
packageInfoList = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager?.queryIntentActivities(
Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER),
PackageManager.ResolveInfoFlags.of(0)
)
} else {
(packageManager?.queryIntentActivities(
Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER), 0
))
})?.apply {
removeIf { it.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID) }
forEach {
val result = WorkersDb.getRealm().query<AppInfo>().query("pkgName == $0",it.activityInfo.packageName).find()
if (result.size < 1) {
val info = AppInfo()
info.appName = normalize(appName(it))
info.pkgName = it.activityInfo.packageName
info.category = getCategory(it.activityInfo.applicationInfo.category)
info.alphaCho = AlphabetToChosungMap.getCho(info.appName!!)
info.appNameChosung = JamoUtils.split(info.appName).joinToString("")
WorkersDb.update(info)
} else{
val info = WorkersDb.getRealm().copyFromRealm(result.first())
info.alphaCho = AlphabetToChosungMap.getCho(info.appName!!)
info.appNameChosung = JamoUtils.split(info.appName).joinToString("")
WorkersDb.update(info)
}
}
}!!
} catch (e : Exception) {e.printStackTrace()}
return Result.success()
}
}

View File

@ -19,12 +19,12 @@ class ClienGetter : BaseGetter {
}
fun parseClien(div_clien : org.jsoup.nodes.Element) {
BLog.LOGE("div_clien >>>> ${div_clien}")
BLog.LOGE("div_clien >>>> ${div_clien.getElementsByClass("subject_fixed").getT()}")
BLog.LOGE("div_clien >>>> ${div_clien.getElementsByClass("shortname fixed").getT()}")
BLog.LOGE("div_clien >>>> ${div_clien.getElementsByClass("list_subject").getHref()}")
BLog.LOGE("div_clien >>>> ${div_clien.getElementsByClass("timestamp").getT()}")
// BLog.LOGE("div_clien >>>> ${div_clien}")
//
// BLog.LOGE("div_clien >>>> ${div_clien.getElementsByClass("subject_fixed").getT()}")
// BLog.LOGE("div_clien >>>> ${div_clien.getElementsByClass("shortname fixed").getT()}")
// BLog.LOGE("div_clien >>>> ${div_clien.getElementsByClass("list_subject").getHref()}")
// BLog.LOGE("div_clien >>>> ${div_clien.getElementsByClass("timestamp").getT()}")
val title = div_clien.getElementsByClass("subject_fixed").getT()
val desc = div_clien.getElementsByClass("shortname fixed").getT()

View File

@ -0,0 +1,61 @@
package rasel.lunar.launcher.workers
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.os.Build
import android.provider.ContactsContract
import android.util.Log
import androidx.work.WorkerParameters
import io.realm.kotlin.ext.query
import rasel.lunar.launcher.BuildConfig
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.apps.AppDrawer.Companion.appName
import rasel.lunar.launcher.apps.AppDrawer.Companion.getCategory
import rasel.lunar.launcher.apps.SimpleContact
import rasel.lunar.launcher.apps.normalize
import rasel.lunar.launcher.model.AppInfo
import rasel.lunar.launcher.utils.AlphabetToChosungMap
class ContactInfoGetter : BaseGetter {
companion object {
val TAG = "ContactInfoGetter"
}
constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) {
}
override fun realWork(): Result {
val phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI
val projection = arrayOf(
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
)
try {
val cursor = lActivity?.contentResolver?.query(phoneUri, projection, null, null, null)
if (cursor != null) {
while (cursor.moveToNext()) {
val idx =cursor.getColumnIndex(projection[0])
val nameIndex = cursor.getColumnIndex(projection[1])
val numberIndex = cursor.getColumnIndex(projection[2])
var contactId = cursor.getString(idx)
val name = cursor.getString(nameIndex)
var number = cursor.getString(numberIndex)
number = number.replace("-", "")
if (name?.length ?: 0 > 0 && number?.length ?: 0 > 0) {
if (WorkersDb.getRealm().query<SimpleContact>("id == $0", contactId).find().size == 0) {
WorkersDb.update(SimpleContact(contactId,name,number))
}
}
}
}
// 데이터 계열은 반드시 닫아줘야 한다.
cursor?.close()
} catch ( e : Exception) {
e.printStackTrace()
}
return Result.success()
}
}

View File

@ -5,30 +5,44 @@ import android.content.Context
import android.provider.CallLog
import androidx.work.WorkerParameters
import com.google.gson.Gson
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query
import io.realm.kotlin.types.RealmObject
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.home.LauncherHome.Companion.recentCalls
import rasel.lunar.launcher.apps.SimpleContact
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.beforeDay
import rasel.lunar.launcher.utils.getContactId
import java.text.SimpleDateFormat
import java.util.Date
class RecentCall {
constructor(count: Int, name: String?, number: String, type: Int, typeString: String, date : String) {
class RecentCall : RealmObject {
constructor(count: Int, name: String?, number: String, type: Int, typeString: String, date : String, callDayTime : Long, duration : Long) {
this.count = count
this.name = name ?: "unknown"
this.number = number
this.type = type
this.typeString = typeString
this.date = date
this.uniqK = number.plus("_").plus(callDayTime)
this.callDayTime = callDayTime
this.duration = duration
}
constructor()
var callDayTime = 0L
var uniqK : String? = ""
var count : Int = 1
var name : String = "how"
var number : String = ""
var type : Int = 0
var typeString : String = ""
var date : String = ""
var duration = 0L
fun toJson() : String {
return Gson().toJson(this)
@ -37,14 +51,17 @@ class RecentCall {
}
class RecentCallGetter : BaseGetter {
companion object{
val TAG = "RecentCallGetter"
val dateFormat = SimpleDateFormat("yyy/MM/dd-HH:mm:ss")
}
constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) {
}
@SuppressLint("RestrictedApi")
override fun realWork(): Result {
var dateParam = beforeDay(Date(),7).toString()
var dateParam = beforeDay(Date(),30).toString()
var managedCursor = lActivity?.contentResolver?.query(
CallLog.Calls.CONTENT_URI, arrayOf(
CallLog.Calls.NUMBER,
@ -62,12 +79,11 @@ class RecentCallGetter : BaseGetter {
val date = managedCursor.getColumnIndex(CallLog.Calls.DATE)
val duration = managedCursor.getColumnIndex(CallLog.Calls.DURATION)
val name = managedCursor.getColumnIndex(CallLog.Calls.CACHED_NAME)
recentCalls.clear()
while (managedCursor.moveToNext()) {
val phNumber = managedCursor.getString(number) // mobile number
val callType = managedCursor.getString(type) // call type
val callDate = managedCursor.getString(date) // call date
val callDayTime: Date = Date(callDate.toLong())
val callDayTime = callDate.toLong()
val callDuration = managedCursor.getString(duration)
val callerName = managedCursor.getString(name)
@ -82,21 +98,40 @@ class RecentCallGetter : BaseGetter {
CallLog.Calls.BLOCKED_TYPE -> { dir = "BLOCKED_TYPE" }
CallLog.Calls.ANSWERED_EXTERNALLY_TYPE -> { dir = "ANSWERED_EXTERNALLY_TYPE" }
}
recentCalls.add(RecentCall(
val call = RecentCall(
1,
callerName,
phNumber,
dircode,
dir,
SimpleDateFormat("yyy/MM/dd-HH:mm:ss").format(callDayTime)
))
dateFormat.format(Date(callDayTime)),
callDayTime,
callDuration.toLong()
)
call.uniqK?.let {
BLog.LOGE("${TAG} call.uniqK? >>> ${call.uniqK}")
WorkersDb.getRealm().writeBlocking {
if(query<RecentCall>().query("uniqK == $0", it).find().count() < 1) {
this.copyToRealm(call, UpdatePolicy.ALL)
var cId = getContactId(lActivity!!.contentResolver, call.number)
if (cId!=null && cId.length > 0) {
val result = query<SimpleContact>().query("id == $0", cId).find()
if(result.size > 0){
var contact = result.first()
contact.touchCount = contact.touchCount + 1
contact.lastedTouchDateTime = Math.max(contact.lastedTouchDateTime, callDayTime)
BLog.LOGE("${TAG} updatetouch info >>>> ${contact.touchCount}")
}
}
}
BLog.LOGE("${TAG} updatetouch info >>>> BE ")
}
BLog.LOGE("${TAG} updatetouch info >>>> E")
}
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
managedCursor.close()
}

View File

@ -1,19 +1,23 @@
package rasel.lunar.launcher.workers
import com.google.gson.Gson
import io.realm.kotlin.Realm
import io.realm.kotlin.RealmConfiguration
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.types.BaseRealmObject
import io.realm.kotlin.types.TypedRealmObject
import rasel.lunar.launcher.apps.SimpleContact
import rasel.lunar.launcher.model.AppInfo
import rasel.lunar.launcher.model.NotificationItem
import rasel.lunar.launcher.model.RssData
import rasel.lunar.launcher.model.RssDataInterface
import rasel.lunar.launcher.model.getRssData
import rasel.lunar.launcher.utils.BLog
import kotlin.reflect.KClass
object WorkersDb {
val clazz : Set<KClass<out BaseRealmObject>> = setOf(RssData::class, NotificationItem::class)
val clazz : Set<KClass<out BaseRealmObject>> = setOf(RssData::class, NotificationItem::class, AppInfo::class,SimpleContact::class, RecentCall::class)
val schemaVersion : Long = 0L
private var pRealm : Realm? = null
@ -76,7 +80,7 @@ object WorkersDb {
getRealm().apply {
this.writeBlocking {
try {
this.copyToRealm(data, UpdatePolicy.ERROR)
this.copyToRealm(data, UpdatePolicy.ALL)
} catch (e : Exception) {
}
@ -84,5 +88,38 @@ object WorkersDb {
}
}
fun update(info: AppInfo) {
getRealm().apply {
this.writeBlocking {
try {
this.copyToRealm(info, UpdatePolicy.ALL)
} catch (e : Exception) {
}
}
}
}
fun update(contact: SimpleContact) {
getRealm().apply {
this.writeBlocking {
try {
this.copyToRealm(contact, UpdatePolicy.ALL)
} catch (e : Exception) {
}
}
}
}
fun insertCall(contact: RecentCall) {
getRealm().apply {
this.writeBlocking {
try {
this.copyToRealm(contact, UpdatePolicy.ALL)
} catch (e : Exception) {
}
}
}
}
}