Compare commits

...

10 Commits

Author SHA1 Message Date
405b8c8fed ... 2025-07-16 12:56:56 +09:00
3d65f30516 .. 2025-07-15 11:22:07 +09:00
b17d4a0411 ... 2025-03-27 11:50:45 +09:00
a297e76da0 ... 2025-01-23 17:56:52 +09:00
eb51ed944a dd 2025-01-23 17:18:41 +09:00
d00c97e7d7 ...... 2024-12-24 18:12:54 +09:00
2be0549b73 ... 2024-12-22 16:35:41 +09:00
1169b159e8 ... 2024-12-20 18:06:54 +09:00
4d8b9b728b .... 2024-12-17 18:12:08 +09:00
10ac465aba /.. 2024-12-06 18:28:08 +09:00
65 changed files with 5211 additions and 3004 deletions

View File

@ -17,6 +17,7 @@ android {
targetSdk = 34 targetSdk = 34
versionCode = 38 versionCode = 38
versionName = "2.8.2" versionName = "2.8.2"
multiDexEnabled = true
} }
buildTypes { buildTypes {
@ -64,12 +65,17 @@ android {
buildFeatures { buildFeatures {
viewBinding = true viewBinding = true
dataBinding = true dataBinding = true
buildConfig = true
resValues = true
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
} }
packagingOptions.resources.excludes.add("META-INF/*")
packagingOptions.resources.excludes.add("mozilla/*")
packagingOptions.resources.excludes.add("META-INF/*/*")
kotlinOptions { kotlinOptions {
jvmTarget = "1.8" jvmTarget = "1.8"
@ -85,7 +91,7 @@ dependencies {
implementation ("androidx.core:core-splashscreen:1.0.1") implementation ("androidx.core:core-splashscreen:1.0.1")
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7") implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
implementation ("com.google.android.material:material:1.12.0") implementation ("com.google.android.material:material:1.12.0")
implementation ("com.ibm.icu:icu4j:68.1")
implementation (kotlin("stdlib", version = kotlinVersion)) implementation (kotlin("stdlib", version = kotlinVersion))
implementation ("com.github.cachapa:ExpandableLayout:2.9.2") implementation ("com.github.cachapa:ExpandableLayout:2.9.2")
implementation ("com.squareup.picasso:picasso:2.71828") implementation ("com.squareup.picasso:picasso:2.71828")
@ -105,7 +111,16 @@ dependencies {
implementation("com.github.delight-im:Android-AdvancedWebView:v3.2.1") implementation("com.github.delight-im:Android-AdvancedWebView:v3.2.1")
implementation(project(":library")) implementation(project(":library"))
implementation(project(":utils")) implementation(project(":utils"))
// implementation("org.mozilla.geckoview:geckoview:139.0.20250523173407")
// https://mvnrepository.com/artifact/org.mozilla.geckoview/geckoview
implementation("org.mozilla.geckoview:geckoview:139.0.20250523173407")
// implementation("org.opencv:opencv-android:4.11.0")
implementation ("androidx.media:media:1.7.0") implementation ("androidx.media:media:1.7.0")
// implementation(project(":sdk"))
// implementation ("me.everything:providers-android:1.0.1") // implementation ("me.everything:providers-android:1.0.1")
// implementation ("me.everything:providers-core:1.0.1") // implementation ("me.everything:providers-core:1.0.1")
// implementation ("androidx.window:window:1.0.0") // implementation ("androidx.window:window:1.0.0")

View File

@ -78,12 +78,12 @@
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
> >
<!-- android:excludeFromRecents="true"-->
<activity <activity
android:name=".LauncherActivity" android:name=".LauncherActivity"
android:theme="@style/Theme.LunarLauncher.Starting" android:theme="@style/Theme.LunarLauncher.Starting"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:excludeFromRecents="true"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|screenLayout|layoutDirection" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|screenLayout|layoutDirection"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:exported="true"> android:exported="true">
@ -93,9 +93,9 @@
<data android:mimeType="*/*"/> <data android:mimeType="*/*"/>
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.HOME" /> <action android:name="android.intent.action.MAIN"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
@ -109,6 +109,11 @@
<action android:name="android.intent.action.APPLICATION_PREFERENCES" /> <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
</intent-filter> </intent-filter>
</activity> </activity>
<!-- <activity-->
<!-- android:name=".PhotoFilter"-->
<!-- android:label="@string/lunar_settings"-->
<!-- android:exported="true">-->
<!-- </activity>-->
<activity <activity
android:name=".feeds.Feeds" android:name=".feeds.Feeds"
android:label="@string/lunar_settings" android:label="@string/lunar_settings"
@ -193,9 +198,20 @@
android:configChanges="keyboardHidden|orientation|screenSize" android:configChanges="keyboardHidden|orientation|screenSize"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:launchMode="singleTask" android:launchMode="singleTask"
android:exported="true"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:theme="@style/FinestWebViewTheme.Fullscreen" > android:theme="@style/FinestWebViewTheme.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:mimeType="text/html"/>
<data android:mimeType="text/plain"/>
<data android:mimeType="text/xml"/>
<data android:mimeType="application/xhtml+xml"/>
<data android:mimeType="application/vnd.wap.xhtml+xml"/>
</intent-filter>
</activity> </activity>
<provider <provider

View File

@ -45,6 +45,7 @@ import android.telephony.TelephonyManager
import android.view.KeyEvent import android.view.KeyEvent
import android.view.KeyEvent.ACTION_UP import android.view.KeyEvent.ACTION_UP
import android.view.KeyEvent.KEYCODE_BUTTON_A import android.view.KeyEvent.KEYCODE_BUTTON_A
import android.view.KeyEvent.KEYCODE_BUTTON_B
import android.view.KeyEvent.KEYCODE_BUTTON_SELECT import android.view.KeyEvent.KEYCODE_BUTTON_SELECT
import android.view.KeyEvent.KEYCODE_BUTTON_START import android.view.KeyEvent.KEYCODE_BUTTON_START
import android.view.KeyEvent.KEYCODE_BUTTON_X import android.view.KeyEvent.KEYCODE_BUTTON_X
@ -75,7 +76,6 @@ import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
import bums.lunatic.launcher.apps.AppDrawer import bums.lunatic.launcher.apps.AppDrawer
import bums.lunatic.launcher.common.CommonActivity import bums.lunatic.launcher.common.CommonActivity
import bums.lunatic.launcher.databinding.LauncherActivityBinding import bums.lunatic.launcher.databinding.LauncherActivityBinding
import bums.lunatic.launcher.feeds.Feeds
import bums.lunatic.launcher.feeds.WidgetHost import bums.lunatic.launcher.feeds.WidgetHost
import bums.lunatic.launcher.helpers.BluetoothManager import bums.lunatic.launcher.helpers.BluetoothManager
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_APPLICATION_THEME import bums.lunatic.launcher.helpers.Constants.Companion.KEY_APPLICATION_THEME
@ -122,6 +122,7 @@ import bums.lunatic.launcher.workers.YoutubeGetter.Companion.YT_WORK_TAG
import com.google.android.material.color.DynamicColors import com.google.android.material.color.DynamicColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import io.realm.kotlin.ext.query import io.realm.kotlin.ext.query
import io.realm.kotlin.query.Sort
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -143,7 +144,6 @@ internal class LauncherActivity : CommonActivity() {
companion object { companion object {
private var mWorkManager: WorkManager? = null private var mWorkManager: WorkManager? = null
var isOpendFold = false var isOpendFold = false
val qDayPeriod = 60L * 8L val qDayPeriod = 60L * 8L
@ -152,37 +152,30 @@ internal class LauncherActivity : CommonActivity() {
@JvmStatic var appWidgetHost: WidgetHost? = null @JvmStatic var appWidgetHost: WidgetHost? = null
fun refreshDeviceData() fun refreshDeviceData()
{ {
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(SMS_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
SMS_WORK_TAG,
ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<RecentSmsGetter>(PrefLong.longTimePeriod.get(), TimeUnit.MINUTES)
.addTag(SMS_WORK_TAG)
.build())
}, 500, TimeUnit.MILLISECONDS)
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(RecentCallGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
RecentCallGetter.TAG,
ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<RecentCallGetter>(PrefLong.longTimePeriod.get(), TimeUnit.MINUTES)
.addTag(RecentCallGetter.TAG)
.build())
}, 500, TimeUnit.MILLISECONDS)
var delay = 3L mWorkManager?.cancelAllWorkByTag(SMS_WORK_TAG)
Executors.newSingleThreadScheduledExecutor().schedule({ mWorkManager?.enqueueUniquePeriodicWork(
mWorkManager?.cancelAllWorkByTag(ContactInfoGetter.TAG) SMS_WORK_TAG,
mWorkManager?.enqueueUniquePeriodicWork( ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
ContactInfoGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, PeriodicWorkRequestBuilder<RecentSmsGetter>(PrefLong.longTimePeriod.get(), TimeUnit.MINUTES)
PeriodicWorkRequestBuilder<ContactInfoGetter>(12, TimeUnit.HOURS) .addTag(SMS_WORK_TAG)
.addTag(ContactInfoGetter.TAG) .build())
.build()) mWorkManager?.cancelAllWorkByTag(RecentCallGetter.TAG)
}, delay, TimeUnit.SECONDS) mWorkManager?.enqueueUniquePeriodicWork(
Executors.newSingleThreadScheduledExecutor().schedule({ RecentCallGetter.TAG,
mWorkManager?.enqueue(OneTimeWorkRequest.from(AppInfoGetter::class.java)) ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
}, 5, TimeUnit.SECONDS) PeriodicWorkRequestBuilder<RecentCallGetter>(PrefLong.longTimePeriod.get(), TimeUnit.MINUTES)
.addTag(RecentCallGetter.TAG)
.build())
mWorkManager?.cancelAllWorkByTag(ContactInfoGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
ContactInfoGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<ContactInfoGetter>(12, TimeUnit.HOURS)
.addTag(ContactInfoGetter.TAG)
.build())
mWorkManager?.enqueue(OneTimeWorkRequest.from(AppInfoGetter::class.java))
} }
@ -201,109 +194,75 @@ internal class LauncherActivity : CommonActivity() {
val defaultDelay = 10L val defaultDelay = 10L
fun refreshFeeds() { fun refreshFeeds() {
var delay = defaultDelay mWorkManager?.cancelAllWork()
Executors.newSingleThreadScheduledExecutor().schedule({ mWorkManager?.cancelAllWorkByTag(RuliWebGetter.TAG)
mWorkManager?.cancelAllWorkByTag(FEDDS_WORK_TAG) mWorkManager?.enqueueUniquePeriodicWork(
mWorkManager?.enqueueUniquePeriodicWork( RuliWebGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
FEDDS_WORK_TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, PeriodicWorkRequestBuilder<RuliWebGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
PeriodicWorkRequestBuilder<NewsFeedsGetter>(PrefLong.shortTimePeriod.get(), TimeUnit.MINUTES) .addTag(RuliWebGetter.TAG)
.addTag(FEDDS_WORK_TAG) .build())
.build())
}, delay, TimeUnit.SECONDS)
delay += defaultDelay
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(YT_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
YT_WORK_TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<YoutubeGetter>(PrefLong.longTimePeriod.get(), TimeUnit.MINUTES)
.addTag(YT_WORK_TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay += defaultDelay
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(REDDIT_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
REDDIT_WORK_TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<RedditGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(REDDIT_WORK_TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay += defaultDelay
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(COMIC_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
COMIC_WORK_TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<FmKoreaGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(COMIC_WORK_TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay += defaultDelay
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(COMIC2_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
COMIC2_WORK_TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<DotaxGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(COMIC2_WORK_TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay += defaultDelay
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(ClienGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
ClienGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<ClienGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(ClienGetter.TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay += defaultDelay
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(DCGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
DCGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<DCGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(DCGetter.TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay += defaultDelay
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(RuliWebGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
RuliWebGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<RuliWebGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(RuliWebGetter.TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay += defaultDelay
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(TheQooGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
TheQooGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<TheQooGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(TheQooGetter.TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay += defaultDelay
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(ArcaGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
ArcaGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<ArcaGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(ArcaGetter.TAG)
.build())
}, delay, TimeUnit.SECONDS)
delay += defaultDelay
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(LocationGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
LocationGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<LocationGetter>(PrefLong.locationTimePeriod.get(), TimeUnit.MINUTES)
.addTag(LocationGetter.TAG)
.build())
}, delay, TimeUnit.SECONDS)
mWorkManager?.cancelAllWorkByTag(FEDDS_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
FEDDS_WORK_TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<NewsFeedsGetter>(PrefLong.shortTimePeriod.get(), TimeUnit.MINUTES)
.addTag(FEDDS_WORK_TAG)
.build())
mWorkManager?.cancelAllWorkByTag(YT_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
YT_WORK_TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<YoutubeGetter>(PrefLong.longTimePeriod.get(), TimeUnit.MINUTES)
.addTag(YT_WORK_TAG)
.build())
mWorkManager?.cancelAllWorkByTag(REDDIT_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
REDDIT_WORK_TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<RedditGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(REDDIT_WORK_TAG)
.build())
mWorkManager?.cancelAllWorkByTag(COMIC_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
COMIC_WORK_TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<FmKoreaGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(COMIC_WORK_TAG)
.build())
mWorkManager?.cancelAllWorkByTag(COMIC2_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(
COMIC2_WORK_TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<DotaxGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(COMIC2_WORK_TAG)
.build())
mWorkManager?.cancelAllWorkByTag(ClienGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
ClienGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<ClienGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(ClienGetter.TAG)
.build())
mWorkManager?.cancelAllWorkByTag(DCGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
DCGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<DCGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(DCGetter.TAG)
.build())
mWorkManager?.cancelAllWorkByTag(TheQooGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
TheQooGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<TheQooGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(TheQooGetter.TAG)
.build())
mWorkManager?.cancelAllWorkByTag(ArcaGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
ArcaGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<ArcaGetter>(PrefLong.midTimePeriod.get(), TimeUnit.MINUTES)
.addTag(ArcaGetter.TAG)
.build())
mWorkManager?.cancelAllWorkByTag(LocationGetter.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
LocationGetter.TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<LocationGetter>(PrefLong.locationTimePeriod.get(), TimeUnit.MINUTES)
.addTag(LocationGetter.TAG)
.build())
} }
@ -331,6 +290,7 @@ internal class LauncherActivity : CommonActivity() {
var onExit = false var onExit = false
var lastAction = MotionEvent.ACTION_HOVER_EXIT var lastAction = MotionEvent.ACTION_HOVER_EXIT
override fun dispatchKeyEvent(ev: KeyEvent): Boolean { override fun dispatchKeyEvent(ev: KeyEvent): Boolean {
Blog.LOGE("dispatch ev?.device?.name >>> ${ev?.device?.name}") Blog.LOGE("dispatch ev?.device?.name >>> ${ev?.device?.name}")
if (ev?.device?.name?.contains("SM-031N Mouse") == true) { if (ev?.device?.name?.contains("SM-031N Mouse") == true) {
@ -339,6 +299,7 @@ internal class LauncherActivity : CommonActivity() {
Blog.LOGE("dispatch dispatchKeyEvent>>> ${ev}") Blog.LOGE("dispatch dispatchKeyEvent>>> ${ev}")
when(ev.keyCode) { when(ev.keyCode) {
KEYCODE_BUTTON_Y->{ KEYCODE_BUTTON_Y->{
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
String(Base64.getMimeDecoder().decode("aHR0cHM6Ly9qYXZtb3N0LnRvL2xhdGVzdC11cGRhdGVzCg==".toByteArray())).getJ().let { doc -> FeedParseManager.parse(doc){Blog.LOGE(it)} } String(Base64.getMimeDecoder().decode("aHR0cHM6Ly9qYXZtb3N0LnRvL2xhdGVzdC11cGRhdGVzCg==".toByteArray())).getJ().let { doc -> FeedParseManager.parse(doc){Blog.LOGE(it)} }
} }
@ -350,17 +311,7 @@ internal class LauncherActivity : CommonActivity() {
} }
} }
KEYCODE_BUTTON_X->{ KEYCODE_BUTTON_X->{
WorkersDb.getRealm().apply {
writeBlocking {
var ddd = copyFromRealm(WorkersDb.getRssQuery("", RssDataType.getAdts(),false).limit(100).find()).map { it.originPage() }
var origin = ddd.first()
RssViewBuilder(lActivity!!)
.setRssList(arrayListOf<String>().apply { this.addAll(ddd) })
.setRssId(origin)
.showIconClose(true).showIconBack(false).showProgressBar(true).backPressToClose(false).webViewMixedContentMode(1)
.show(origin)
}
}
} }
KEYCODE_BUTTON_A->{ KEYCODE_BUTTON_A->{
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
@ -375,6 +326,13 @@ internal class LauncherActivity : CommonActivity() {
} }
} }
} }
KEYCODE_BUTTON_B->{
// RssViewBuilder(lActivity!!)
// .setRssId("https://jav.guru")
// .webViewJavaScriptEnabled(true)
// .showIconClose(true).showIconBack(false).showProgressBar(true).backPressToClose(false).webViewMixedContentMode(1)
// .show("https://jav.guru")
}
KEYCODE_DPAD_DOWN->{ KEYCODE_DPAD_DOWN->{
} }
@ -382,7 +340,7 @@ internal class LauncherActivity : CommonActivity() {
} }
KEYCODE_BUTTON_START->{ KEYCODE_BUTTON_START->{
onClickCenterButton() onClickCenterButton()
} }
KEYCODE_BUTTON_SELECT->{ KEYCODE_BUTTON_SELECT->{
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
@ -413,16 +371,29 @@ internal class LauncherActivity : CommonActivity() {
fun onClickCenterButton() { fun onClickCenterButton() {
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
writeBlocking { writeBlocking {
var ddd = copyFromRealm(WorkersDb.getRssQuery("", RssDataType.getExcAdt(),false).limit(100).query("read == $0", 0).query("vote != $0", true).find()).map { it.originPage() } delete(
query<RssData>()
.query("pubDate < $0",
bums.lunatic.launcher.utils.beforeDay(28)
)
.query("vote != $0", true).apply {
Blog.LOGE("onClickCenterButton DELETE >> ${this.description()}")
}.find()
)
var ddd = copyFromRealm(WorkersDb.getRssQuery("", RssDataType.getExcAdt(),false).limit(100).query("read == $0", 0).query("vote != $0", true).apply {
Blog.LOGE("onClickCenterButton SELECT >> ${this.description()}")
}.find()).map { it.originPage() }
var origin = ddd.first() var origin = ddd.first()
var jjjj = hashSetOf<String>()
jjjj.addAll(ddd)
RssViewBuilder(lActivity!!) RssViewBuilder(lActivity!!)
.setRssList(arrayListOf<String>().apply { .setRssList(arrayListOf<String>().apply {
var jjjj = hashSetOf<String>() this.addAll(jjjj)})
jjjj.addAll(ddd)
this.addAll(jjjj) })
.setRssId(origin) .setRssId(origin)
// .webViewDesktopMode(true)
.showIconClose(true).showIconBack(false).showProgressBar(true).backPressToClose(false).webViewMixedContentMode(1) .showIconClose(true).showIconBack(false).showProgressBar(true).backPressToClose(false).webViewMixedContentMode(1)
.show(origin) .show(origin)
} }
@ -574,6 +545,7 @@ internal class LauncherActivity : CommonActivity() {
@SuppressLint("NewApi", "MissingPermission") @SuppressLint("NewApi", "MissingPermission")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen() installSplashScreen()
mWorkManager = WorkManager.getInstance(this) mWorkManager = WorkManager.getInstance(this)
DynamicColors.applyToActivityIfAvailable(this) DynamicColors.applyToActivityIfAvailable(this)
lActivity = this lActivity = this
@ -1065,9 +1037,9 @@ internal class LauncherActivity : CommonActivity() {
// } // }
// } // }
fun switchFeeds() { // fun switchFeeds() {
startActivity(Intent(this,Feeds::class.java)) // startActivity(Intent(this,Feeds::class.java))
} // }
// inner class MyJavaScriptInterface(val webView: WebView) { // inner class MyJavaScriptInterface(val webView: WebView) {
// @JavascriptInterface // @JavascriptInterface
@ -1191,9 +1163,7 @@ fun openReddit(schemeString : String) {
var uri = schemeString.toUri() var uri = schemeString.toUri()
val gmmIntentUri = Uri.parse(schemeString) val gmmIntentUri = Uri.parse(schemeString)
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
if (uri != null && uri.host?.contains("facebook") == true) { if(schemeString.contains("reddit")) {
} else {
mapIntent.setPackage("com.reddit.frontpage") mapIntent.setPackage("com.reddit.frontpage")
} }
lActivity?.startActivity(mapIntent) lActivity?.startActivity(mapIntent)

View File

@ -0,0 +1,108 @@
//package bums.lunatic.launcher
//
//import bums.lunatic.launcher.common.CommonActivity
//import android.Manifest
//import android.app.Activity
//import android.content.Intent
//import android.content.pm.PackageManager
//import android.graphics.Bitmap
//import android.net.Uri
//import android.os.Build
//import android.os.Bundle
//import android.provider.MediaStore
//import android.widget.Button
//import android.widget.ImageView
//import androidx.activity.result.ActivityResultLauncher
//import androidx.activity.result.contract.ActivityResultContracts
//import androidx.annotation.RequiresApi
//import androidx.appcompat.app.AppCompatActivity
//import androidx.core.app.ActivityCompat
//import androidx.core.content.ContextCompat
//import bums.lunatic.launcher.utils.Blog
//
//
//class PhotoFilter : CommonActivity() {
//// private lateinit var originalImageView: ImageView
//// private lateinit var filteredImageView: ImageView
//// private lateinit var selectImageButton: Button
//// private val PICK_IMAGE_REQUEST = 1
//// private val PERMISSION_REQUEST_CODE = 200
////
//// init {
////
//// }
////
//// override fun onCreate(savedInstanceState: Bundle?) {
//// super.onCreate(savedInstanceState)
//// setContentView(R.layout.photo_filter)
////
//// originalImageView = findViewById(R.id.originalImageView)
//// filteredImageView = findViewById(R.id.filteredImageView)
//// selectImageButton = findViewById(R.id.selectImageButton)
////
//// selectImageButton.setOnClickListener {
//// Blog.LOGE("imagePickerLauncher checkPermission() ${checkPermission()}")
//// if (checkPermission()) {
//// openGallery()
//// } else {
//// requestPermission()
//// }
//// }
////
//// imagePickerLauncher = registerForActivityResult(
//// ActivityResultContracts.GetContent(),
//// {result ->
//// Blog.LOGE("imagePickerLauncher result ${result}")
//// if (result != null) {
//// // Handle the selected image
//// FilePathUri = result;
//// try {
//// var bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), FilePathUri)
//// Blog.LOGE("imagePickerLauncher result ${result} 2")
//// originalImageView.setImageBitmap(bitmap)
//// Blog.LOGE("imagePickerLauncher result ${result} 3")
//// val filteredBitmap = applyCartoonFilter(bitmap)
//// Blog.LOGE("imagePickerLauncher result ${result} 4")
//// filteredImageView.setImageBitmap(filteredBitmap)
//// } catch (e : Exception ) {
//// e.printStackTrace();
//// }
//// }
//// }
//// );
//// }
////
//// var FilePathUri : Uri? = null
////
//// private var imagePickerLauncher : ActivityResultLauncher<String>? = null
////
////
//// private fun openGallery() {
////// val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
////// startActivityForResult(intent, PICK_IMAGE_REQUEST)
////
//// imagePickerLauncher?.launch("image/*");
//// Blog.LOGE("imagePickerLauncher ")
////
//// }
////
////
//// @RequiresApi(Build.VERSION_CODES.TIRAMISU)
//// private fun checkPermission(): Boolean {
//// return ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED
//// }
////
//// @RequiresApi(Build.VERSION_CODES.TIRAMISU)
//// private fun requestPermission() {
//// ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_MEDIA_IMAGES), PERMISSION_REQUEST_CODE)
//// }
////
//// override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
//// super.onRequestPermissionsResult(requestCode, permissions, grantResults)
//// if (requestCode == PERMISSION_REQUEST_CODE) {
//// if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//// openGallery()
//// }
//// }
//// }
//}

View File

@ -35,6 +35,8 @@ import android.view.inputmethod.InputMethodManager
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import bums.lunatic.launcher.BuildConfig import bums.lunatic.launcher.BuildConfig
import bums.lunatic.launcher.LauncherActivity
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
import bums.lunatic.launcher.common.CommonActivity import bums.lunatic.launcher.common.CommonActivity
import bums.lunatic.launcher.common.letTrue import bums.lunatic.launcher.common.letTrue
import bums.lunatic.launcher.databinding.AppDrawerBinding import bums.lunatic.launcher.databinding.AppDrawerBinding
@ -44,6 +46,7 @@ import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_APP_NAMES
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
import bums.lunatic.launcher.helpers.PrefBoolean import bums.lunatic.launcher.helpers.PrefBoolean
import bums.lunatic.launcher.helpers.PrefLong import bums.lunatic.launcher.helpers.PrefLong
import bums.lunatic.launcher.helpers.PrefString
import bums.lunatic.launcher.model.AppInfo import bums.lunatic.launcher.model.AppInfo
import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.Blog
import bums.lunatic.launcher.utils.JamoUtils import bums.lunatic.launcher.utils.JamoUtils
@ -66,7 +69,7 @@ internal class AppDrawer : CommonActivity() {
private var isKeyboardShowing: Boolean = false private var isKeyboardShowing: Boolean = false
companion object { companion object {
lateinit var packageManager: PackageManager
private var appsAdapter: AppsAdapter? = null private var appsAdapter: AppsAdapter? = null
private var contactAdapter : ContactAdapter? = null private var contactAdapter : ContactAdapter? = null
private var packageList = mutableListOf<AppInfo>() private var packageList = mutableListOf<AppInfo>()
@ -74,34 +77,14 @@ internal class AppDrawer : CommonActivity() {
@JvmStatic var appNamesPrefs: SharedPreferences? = null @JvmStatic var appNamesPrefs: SharedPreferences? = null
fun appName(resolver: ResolveInfo): String {
return resolver.loadLabel(packageManager).toString().apply {
appNamesPrefs?.edit()?.putString(resolver.activityInfo.packageName, this)?.apply()
}
}
fun getCategory(category : Int) : String {
return when(category) {
ApplicationInfo.CATEGORY_UNDEFINED -> "UNDEFINED"
ApplicationInfo.CATEGORY_GAME -> "GAME"
ApplicationInfo.CATEGORY_AUDIO -> "AUDIO"
ApplicationInfo.CATEGORY_VIDEO -> "VIDEO"
ApplicationInfo.CATEGORY_IMAGE -> "IMAGE"
ApplicationInfo.CATEGORY_SOCIAL -> "SOCIAL"
ApplicationInfo.CATEGORY_NEWS -> "NEWS"
ApplicationInfo.CATEGORY_MAPS -> "MAPS"
ApplicationInfo.CATEGORY_PRODUCTIVITY -> "PRODUCTIVITY"
ApplicationInfo.CATEGORY_ACCESSIBILITY -> "ACCESSIBILITY"
else -> {"UNKNOWN"}
}
}
} }
fun getInputText() = binding.searchInput.text.toString() fun getInputText() = binding.searchInput.text.toString()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// setStyle(STYLE_NO_TITLE, R.style.FilterFullScreenDialog) // setStyle(STYLE_NO_TITLE, R.style.FilterFullScreenDialog)
// packageManager = lActivity?.packageManager!! // packageManager
// } // }
// override fun onAttach(context: Context) { // override fun onAttach(context: Context) {
@ -118,7 +101,7 @@ internal class AppDrawer : CommonActivity() {
appNamesPrefs = this.getSharedPreferences(PREFS_APP_NAMES, 0) appNamesPrefs = this.getSharedPreferences(PREFS_APP_NAMES, 0)
layoutType = settingsPrefs!!.getInt(KEY_APPS_LAYOUT, 0) layoutType = settingsPrefs!!.getInt(KEY_APPS_LAYOUT, 0)
appsAdapter = AppsAdapter(layoutType, packageManager!!, supportFragmentManager, binding.appsCount) appsAdapter = AppsAdapter(packageManager!!, supportFragmentManager, binding.appsCount)
contactAdapter = ContactAdapter(packageManager!!, supportFragmentManager) contactAdapter = ContactAdapter(packageManager!!, supportFragmentManager)
binding.appsCount.visibility = if (settingsPrefs!!.getBoolean(KEY_APPS_COUNT, true)) VISIBLE else GONE binding.appsCount.visibility = if (settingsPrefs!!.getBoolean(KEY_APPS_COUNT, true)) VISIBLE else GONE
@ -158,7 +141,7 @@ internal class AppDrawer : CommonActivity() {
sendMsg() sendMsg()
} }
binding.runTelegram.setOnClickListener { binding.runTelegram.setOnClickListener {
sendMsg("tg://msg?text=${getInputText()}&to=","org.telegram.messenger") sendMsg("tg://msg?text=${getInputText()}&to=${PrefString.telegramSendTarget.get()}","org.telegram.messenger")
} }
binding.runKatalk.setOnClickListener { binding.runKatalk.setOnClickListener {
sendMsg(pkg = "com.kakao.talk") sendMsg(pkg = "com.kakao.talk")
@ -179,6 +162,8 @@ internal class AppDrawer : CommonActivity() {
false false
} }
} }
var packageManager = lActivity?.packageManager
binding.searchInput.setOnLongClickListener { binding.searchInput.setOnLongClickListener {
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
var newQ = query<AppInfo>() var newQ = query<AppInfo>()
@ -187,10 +172,18 @@ internal class AppDrawer : CommonActivity() {
if(it.size > 0) { if(it.size > 0) {
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
packageList.clear() packageList.clear()
packageList.addAll(copyFromRealm(it)) writeBlocking {
binding.appsList.post { if (packageList.size > 0) { it.filter {
appsAdapter?.updateData(packageList) var installed = isPackageInstalled(it.pkgName ?: "fffffffail", packageManager!!)
} } // it.isInstalled = installed
installed
}.let { result ->
packageList.addAll(copyFromRealm(result))
binding.appsList.post { if (result.size > 0) {
appsAdapter?.updateData(packageList)
}}
}
}
} }
} }
} }
@ -219,6 +212,14 @@ internal class AppDrawer : CommonActivity() {
} }
// return binding.root // return binding.root
} }
fun isPackageInstalled( packageName : String, packageManager : PackageManager?) : Boolean{
try {
packageManager!!.getPackageInfo(packageName, 0)
return true;
} catch ( e : Exception) {
return false;
}
}
fun sendMsg(scheme : String? = null , pkg : String? = null) { fun sendMsg(scheme : String? = null , pkg : String? = null) {
var postIntent : Intent? = null var postIntent : Intent? = null
@ -336,10 +337,18 @@ internal class AppDrawer : CommonActivity() {
if(it.size > 0) { if(it.size > 0) {
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
packageList.clear() packageList.clear()
packageList.addAll(copyFromRealm(it)) writeBlocking {
binding.appsList.post { if (packageList.size > 0) { it.filter {
appsAdapter?.updateData(packageList) var installed = isPackageInstalled(it.pkgName ?: "fffffffail", packageManager!!)
} } // it.isInstalled = installed
installed
}.let { result ->
packageList.addAll(copyFromRealm(result))
binding.appsList.post { if (result.size > 0) {
appsAdapter?.updateData(packageList)
}}
}
}
} }
} }
} }
@ -496,9 +505,3 @@ internal class AppDrawer : CommonActivity() {
} }
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

@ -41,10 +41,9 @@ import kotlinx.coroutines.async
internal class AppsAdapter( internal class AppsAdapter(
private val layoutType: Int,
private val packageManager: PackageManager, private val packageManager: PackageManager,
private val fragmentManager: FragmentManager, private val fragmentManager: FragmentManager,
private val appsCount: TextView) : RecyclerView.Adapter<AppsAdapter.AppsViewHolder>() { private val appsCount: TextView?) : RecyclerView.Adapter<AppsAdapter.AppsViewHolder>() {
private var oldList = mutableListOf<AppInfo>() private var oldList = mutableListOf<AppInfo>()
// private var appGravity: Int = Gravity.CENTER // private var appGravity: Int = Gravity.CENTER
@ -125,7 +124,7 @@ internal class AppsAdapter(
oldList.clear() oldList.clear()
oldList.addAll(newList) oldList.addAll(newList)
newList.size.let { newList.size.let {
appsCount.text = it.toString() appsCount?.text = it.toString()
appsSize = it appsSize = it
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -134,7 +134,7 @@ class BluetoothManager {
//블루투스 상태(켜짐 / 꺼짐 / 지원 불가 기기) //블루투스 상태(켜짐 / 꺼짐 / 지원 불가 기기)
fun blueToothState(): String { fun blueToothState(): String {
if (blueToothAdapter != null) { if (blueToothAdapter != null) {
if (blueToothAdapter!!.isEnabled) { if (blueToothAdapter?.isEnabled == true) {
return BLUETOOTH_STATE.ENABLED.statestr return BLUETOOTH_STATE.ENABLED.statestr
} else { } else {
return BLUETOOTH_STATE.DISABLED.statestr return BLUETOOTH_STATE.DISABLED.statestr
@ -167,7 +167,6 @@ class BluetoothManager {
val action = intent!!.action val action = intent!!.action
if (context == null) return if (context == null) return
if (ActivityCompat.checkSelfPermission(context!!, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) return if (ActivityCompat.checkSelfPermission(context!!, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) return
val device: BluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)!!
getPairedDevices() getPairedDevices()
} }
} }

View File

@ -2,6 +2,7 @@ package bums.lunatic.launcher.helpers
import android.content.SharedPreferences import android.content.SharedPreferences
import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.model.RssDataType
import bums.lunatic.launcher.utils.Blog
import kr.lunaticbum.utils.preferences.PrefJsonConvert import kr.lunaticbum.utils.preferences.PrefJsonConvert
import kr.lunaticbum.utils.preferences.PrefKey import kr.lunaticbum.utils.preferences.PrefKey
import kr.lunaticbum.utils.preferences.PreferencesHelper import kr.lunaticbum.utils.preferences.PreferencesHelper
@ -30,7 +31,13 @@ enum class PrefLong(val def : Long) : PrefKey<Long> {
midTimePeriod(30L), midTimePeriod(30L),
maxQueryCount(18L); maxQueryCount(18L);
override fun set(value : Long) { PrefHelper.putLong(this.name, value) } override fun set(value : Long) { PrefHelper.putLong(this.name, value) }
override fun get(def : Long?) : Long = PrefHelper.getLong(this.name, def as? Long ?: this.def) ?: 0L override fun get(def : Long?) : Long {
val value = PrefHelper.getLong(this.name, def ?: this.def) ?: this.def
// Blog.LOGE("$name : $value")
return value
}
override fun getKey() = this.name override fun getKey() = this.name
} }
@ -97,7 +104,7 @@ object PrefHelper : PreferencesHelper() {
fun getBoolean(key: String, def: Boolean) = get(getBooleanPrefix().plus(key), def) fun getBoolean(key: String, def: Boolean) = get(getBooleanPrefix().plus(key), def)
fun putBoolean(key: String, value: Boolean) = put(getBooleanPrefix().plus(key), value) fun putBoolean(key: String, value: Boolean) = put(getBooleanPrefix().plus(key), value)
fun getLong(key: String, def: Long) = get(getLongPrefix().plus(key), def) fun getLong(key: String, def: Long) = get(getLongPrefix().plus(key), def)
fun putLong(key: String, value: Long) = put(getBooleanPrefix().plus(key), value) fun putLong(key: String, value: Long) = put(getLongPrefix().plus(key), value)
fun getString(key: String, def: String) = get(getStringPrefix().plus(key), def) fun getString(key: String, def: String) = get(getStringPrefix().plus(key), def)
fun putString(key: String, value: String) = put(getStringPrefix().plus(key), value) fun putString(key: String, value: String) = put(getStringPrefix().plus(key), value)

View File

@ -0,0 +1,473 @@
package bums.lunatic.launcher.home
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.AttributeSet
import android.util.Log
import android.view.KeyEvent
import android.view.KeyEvent.ACTION_UP
import android.view.KeyEvent.KEYCODE_BUTTON_A
import android.view.KeyEvent.KEYCODE_BUTTON_B
import android.view.KeyEvent.KEYCODE_BUTTON_SELECT
import android.view.KeyEvent.KEYCODE_BUTTON_START
import android.view.KeyEvent.KEYCODE_BUTTON_X
import android.view.KeyEvent.KEYCODE_BUTTON_Y
import android.view.KeyEvent.KEYCODE_DPAD_DOWN
import android.view.KeyEvent.KEYCODE_DPAD_UP
import bums.lunatic.launcher.utils.Blog
import com.google.gson.Gson
import org.json.JSONObject
import org.mozilla.gecko.util.ThreadUtils
import org.mozilla.geckoview.ExperimentDelegate
import org.mozilla.geckoview.GeckoResult
import org.mozilla.geckoview.GeckoRuntime
import org.mozilla.geckoview.GeckoRuntimeSettings
import org.mozilla.geckoview.GeckoSession
import org.mozilla.geckoview.GeckoView
import org.mozilla.geckoview.MediaSession
import org.mozilla.geckoview.WebExtension
import org.mozilla.geckoview.WebExtension.MessageDelegate
import org.mozilla.geckoview.WebExtension.PortDelegate
import org.mozilla.geckoview.WebExtensionController.AddonManagerDelegate
import org.mozilla.geckoview.WebRequestError
class GeckoWeb : GeckoView {
constructor(context: Context?) : super(context) {
initWithContext(context)
}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
initWithContext(context)
}
fun loadUrl(url: String) {
Blog.LOGE("url >>>> ${url}")
if (url.split("//").size > 1) {
url.replace("//","/").replace("https:/","https://").let {
Blog.LOGE("url >> ${url} , it >>> ${it}")
this.session?.loadUri(url)
}
} else {
this.session?.loadUri(url)
}
currentRetryCount = 0;
}
val handle = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
if (msg.what == 0) {
(msg.obj as? ReaderConfig)?.let {
}
}
}
}
var lastedUrl: String? = null
var canGoBack: Boolean? = null
var mPort: WebExtension.Port? = null
object WebExtensionInfo {
val mPortNam = "browser"
val extPath = "resource://android/assets/extensions/my_extension/"
val extId = "messaging@booktoki468.com"
}
var mExtension: WebExtension? = null
var mSession: GeckoSession? = null
val addonManagerDelegate = object : AddonManagerDelegate {
override fun onReady(extension: WebExtension) {
Blog.LOGE("onReady ${extension.id} from WebExtension")
mExtension = extension
}
override fun onEnabling(extension: WebExtension) {
Blog.LOGE("onEnabling ${extension.id} from WebExtension")
}
override fun onEnabled(extension: WebExtension) {
Blog.LOGE("onEnabled ${extension.id} from WebExtension")
mExtension = extension
}
}
private fun initWithContext(context: Context?) {
context?.let { context ->
initGeckoRuntime(context)
mSession = GeckoSession()
mSession?.contentDelegate = contentDelegate
mSession?.progressDelegate = progressDelegate
mSession?.navigationDelegate = navigationDelegate
sRuntime?.apply {
webExtensionController.setAddonManagerDelegate(addonManagerDelegate)
webExtensionController.ensureBuiltIn(WebExtensionInfo.extPath, WebExtensionInfo.extId)
.accept( // Register message delegate for background script
{ extension: WebExtension? ->
ThreadUtils.runOnUiThread(Runnable { mSession?.let{session-> extension?.let { session.webExtensionController.setMessageDelegate(it,messageDelegate,WebExtensionInfo.mPortNam) }} })
},
{ e: Throwable? -> Log.e("MessageDelegate", "Error registering WebExtension", e) })
mSession?.mediaDelegate = mediaDelegate
mSession?.mediaSessionDelegate = mediaSessionDelegate
mSession?.open(sRuntime!!)
}.let {
this.setSession(mSession!!)
this.loadUrl("https://booktoki468.com") // Or any other URL...
}
}
}
val mediaDelegate = object : GeckoSession.MediaDelegate {
override fun onRecordingStatusChanged(
session: GeckoSession,
devices: Array<out GeckoSession.MediaDelegate.RecordingDevice?>
) {
super.onRecordingStatusChanged(session, devices)
}
}
val mediaSessionDelegate = object : MediaSession.Delegate {
override fun onActivated(
session: GeckoSession,
mediaSession: MediaSession
) {
Blog.LOGE("onActivated")
super.onActivated(session, mediaSession)
}
override fun onDeactivated(
session: GeckoSession,
mediaSession: MediaSession
) {
Blog.LOGE("onDeactivated")
super.onDeactivated(session, mediaSession)
}
override fun onMetadata(
session: GeckoSession,
mediaSession: MediaSession,
meta: MediaSession.Metadata
) {
Blog.LOGE("onMetadata ${Gson().toJson(meta)}")
super.onMetadata(session, mediaSession, meta)
}
override fun onFeatures(
session: GeckoSession,
mediaSession: MediaSession,
features: Long
) {
Blog.LOGE("onFeatures $features")
super.onFeatures(session, mediaSession, features)
}
override fun onPlay(
session: GeckoSession,
mediaSession: MediaSession
) {
Blog.LOGE("onPlay")
super.onPlay(session, mediaSession)
}
override fun onPause(
session: GeckoSession,
mediaSession: MediaSession
) {
Blog.LOGE("onPause")
super.onPause(session, mediaSession)
}
override fun onStop(
session: GeckoSession,
mediaSession: MediaSession
) {
Blog.LOGE("onStop")
super.onStop(session, mediaSession)
}
override fun onPositionState(
session: GeckoSession,
mediaSession: MediaSession,
state: MediaSession.PositionState
) {
Blog.LOGE("onPositionState $state")
super.onPositionState(session, mediaSession, state)
}
override fun onFullscreen(
session: GeckoSession,
mediaSession: MediaSession,
enabled: Boolean,
meta: MediaSession.ElementMetadata?
) {
Blog.LOGE("onFullscreen $Boolean ${Gson().toJson(meta)}")
super.onFullscreen(session, mediaSession, enabled, meta)
}
}
private fun initGeckoRuntime(context : Context) {
if (sRuntime == null) {
try {
val settings: GeckoRuntimeSettings =
GeckoRuntimeSettings.Builder().extensionsProcessEnabled(true)
.extensionsWebAPIEnabled(true)
.experimentDelegate(experimentDelegate)
.remoteDebuggingEnabled(true).build()
sRuntime = GeckoRuntime.create(context, settings)
} catch (e: Exception) {
}
}
}
val experimentDelegate = object : ExperimentDelegate {
override fun onGetExperimentFeature(feature: String): GeckoResult<JSONObject?> {
Blog.LOGE("onGetExperimentFeature $feature")
return super.onGetExperimentFeature(feature)
}
override fun onRecordExposureEvent(feature: String): GeckoResult<Void?> {
Blog.LOGE("onRecordExposureEvent $feature")
return super.onRecordExposureEvent(feature)
}
override fun onRecordExperimentExposureEvent(
feature: String,
slug: String
): GeckoResult<Void?> {
Blog.LOGE("onRecordExperimentExposureEvent $feature , $slug")
return super.onRecordExperimentExposureEvent(feature, slug)
}
override fun onRecordMalformedConfigurationEvent(
feature: String,
part: String
): GeckoResult<Void?> {
Blog.LOGE("onRecordMalformedConfigurationEvent $feature , $part")
return super.onRecordMalformedConfigurationEvent(feature, part)
}
}
val contentDelegate = object : GeckoSession.ContentDelegate {
override fun onTitleChange(
session: GeckoSession,
title: String?
) {
Blog.LOGE("onTitleChange $title")
super.onTitleChange(session, title)
}
override fun onCrash(session: GeckoSession) {
Blog.LOGE("onCrash")
super.onCrash(session)
}
override fun onPaintStatusReset(session: GeckoSession) {
Blog.LOGE("onPaintStatusReset")
super.onPaintStatusReset(session)
}
override fun onFirstContentfulPaint(session: GeckoSession) {
Blog.LOGE("onFirstContentfulPaint")
super.onFirstContentfulPaint(session)
}
}
val progressDelegate = object : GeckoSession.ProgressDelegate {
override fun onSecurityChange(
session: GeckoSession,
securityInfo: GeckoSession.ProgressDelegate.SecurityInformation
) {
Blog.LOGE("onSecurityChange $securityInfo from WebExtension")
super.onSecurityChange(session, securityInfo)
}
override fun onSessionStateChange(
session: GeckoSession,
sessionState: GeckoSession.SessionState
) {
Blog.LOGE("onSessionStateChange $sessionState from WebExtension")
super.onSessionStateChange(session, sessionState)
}
override fun onPageStart(session: GeckoSession, url: String) {
super.onPageStart(session, url)
}
override fun onPageStop(session: GeckoSession, success: Boolean) {
Blog.LOGE("onPageStop $success from WebExtension")
super.onPageStop(session, success)
if (success && mPort != null) {
if (mPort == null) {
// No extension registered yet, let's ignore this message
return
}
}
}
}
val navigationDelegate = object : GeckoSession.NavigationDelegate {
override fun onLoadError(
session: GeckoSession,
uri: String?,
error: WebRequestError
): GeckoResult<String>? {
error.printStackTrace()
Blog.LOGE("onLoadError >>> ${uri} ::>> ${error.category} , ${error.code}")
if (error.code == WebRequestError.ERROR_NET_RESET) {
}
return super.onLoadError(session, uri, error)
}
override fun onNewSession(
session: GeckoSession,
uri: String
): GeckoResult<GeckoSession>? {
Blog.LOGE("GeckoView", "onNewSession: $session from WebExtension")
return super.onNewSession(session, uri)
}
override fun onLocationChange(
session: GeckoSession,
url: String?,
perms: MutableList<GeckoSession.PermissionDelegate.ContentPermission>,
hasUserGesture: Boolean
) {
// url이 현재 로드된 주소입니다.
Blog.LOGE("GeckoView", "현재 주소: $url")
Blog.LOGE("GeckoView", "현재 session: $session")
url?.let { url ->
if (url.split("//").size > 1) {
url.replace("//", "/").replace("https:/", "https://").let {
Blog.LOGE("url >> ${url} , it >>> ${it}")
lastedUrl = url
}
} else {
lastedUrl = url
}
}
}
override fun onCanGoBack(session: GeckoSession, canGoBack: Boolean) {
super.onCanGoBack(session, canGoBack)
this@GeckoWeb.canGoBack = canGoBack
if (canGoBack) {
}
}
}
val portDelegate: PortDelegate =
object : PortDelegate {
override fun onPortMessage(
message: Any, port: WebExtension.Port
) {
Blog.LOGE("PortDelegate", "Received message from extension: $message")
}
override fun onDisconnect(port: WebExtension.Port) {
// This port is not usable anymore.
if (port === mPort) {
mPort = null
}
}
}
val messageDelegate: MessageDelegate =
object : MessageDelegate {
override fun onConnect(port: WebExtension.Port) {
mPort = port
mPort!!.setDelegate(portDelegate)
}
override fun onMessage(
nativeApp: String,
message: Any,
sender: WebExtension.MessageSender
): GeckoResult<in Any>? {
Blog.LOGE(
"messageDelegate",
"onMessage from WebExtension: ${nativeApp} , $message , ${sender.webExtension.id}"
)
return super.onMessage(nativeApp, message, sender)
}
}
fun onStart() {
}
fun onResume() {
}
fun onDestroy() {
sRuntime = null
}
override fun dispatchKeyEvent(ev: KeyEvent): Boolean {
Blog.LOGE("dispatch ev?.device?.name >>> ${ev?.device?.name}")
if (ev?.device?.name?.contains("SM-031N Mouse") == true) {
when (ev.action) {
ACTION_UP -> {
Blog.LOGE("dispatch dispatchKeyEvent>>> ${ev}")
when (ev.keyCode) {
KEYCODE_BUTTON_Y -> {
}
KEYCODE_BUTTON_X -> {
}
KEYCODE_BUTTON_A -> {
}
KEYCODE_BUTTON_B -> {
}
KEYCODE_DPAD_DOWN -> {
}
KEYCODE_DPAD_UP -> {
}
KEYCODE_BUTTON_START -> {
}
KEYCODE_BUTTON_SELECT -> {
}
else -> {}
}
}
else -> {}
}
return true
}
return super.dispatchKeyEvent(ev)
}
companion object {
private const val TAG = "DualScreenStatus"
var sRuntime: GeckoRuntime? = null
var currentRetryCount = 0
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,250 @@
package bums.lunatic.launcher.home
import android.content.Context
import android.content.Intent
import android.os.Environment
import android.webkit.CookieManager
import androidx.core.content.FileProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kr.lunaticbum.awesomewebview.helpers.DownPicUtil
import kr.lunaticbum.awesomewebview.helpers.DownPicUtil.DownFinishListener
import kr.lunaticbum.utils.log.LogUtil
import org.jsoup.Jsoup
import org.jsoup.UnsupportedMimeTypeException
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import java.net.URL
import java.text.SimpleDateFormat
import java.util.Date
val defaultTime = 200L
class OfflineContents(val context: Context, val host : String, val cookie: String, val agent: String, val current: String, val newPath: String, val value: String, val autoCheck : Boolean, val mediaUrls : ArrayList<String>) {
val targetFile : File
val filePath = "index.html"
val path = File(
Environment.getExternalStorageDirectory(),
"bums"
)
val newFolder = File(path, newPath).apply { mkdirs() }
val newFile : File
var htmlString : StringBuffer
val urlPathMap : HashMap<String,String> = hashMapOf()
var reqCount = 0
var endOfLooPCheck = false
val lDownFinishListener = object : DownFinishListener {
override fun onDownFinish(url: String, path: String) {
LogUtil.e("Url >> ${url} path >> ${path}")
urlPathMap.put(url, path)
reqCount -= 1
if (reqCount == 0 && endOfLooPCheck) {
enofLoop()
}
}
override fun onError() {
reqCount -= 1
if (reqCount == 0 && endOfLooPCheck) {
enofLoop()
}
}
}
init {
targetFile = File(newFolder, filePath)
newFile = File(
path,
newPath.plus(SimpleDateFormat("yyyMMdd").format(Date())).plus(".html")
)
htmlString= trimHtnl(value, host)
}
var onItEndof = false
fun enofLoop() {
if (onItEndof) return
onItEndof = true
LogUtil.e("on it enofLoop")
urlPathMap.forEach { t, u ->
val file = File(u)
var contentsUriString = FileProvider.getUriForFile(
context,
"${context.packageName}.fileprovider",
file
).toString()
var targetString = t
var targetIdx = htmlString.indexOf(targetString)
if (targetIdx > 0) {
htmlString?.replace(
targetIdx,
targetIdx.plus(targetString.length),
contentsUriString
)
}
targetString = t.replace("&", "&amp;")
targetIdx = htmlString.indexOf(targetString)
if (targetIdx > 0) {
htmlString?.replace(
targetIdx,
targetIdx.plus(targetString.length),
contentsUriString
)
}
}
if (autoCheck) {
LogUtil.e("on it enofLoop autoCheck ${autoCheck}")
moveFile()
context.startActivity(Intent(context,RssViewerActivity::class.java).apply {
action = Intent.ACTION_VIEW
data = FileProvider.getUriForFile(
context,
"${context.packageName}.fileprovider",
newFile
)
})
} else {
moveFile()
}
}
fun moveFile() {
indexSave(htmlString, targetFile, host)
targetFile.copyTo(newFile)
if (targetFile.parentFile.isDirectory) {
targetFile.parentFile.listFiles().forEach {
it.delete()
}
targetFile.parentFile.delete()
}
targetFile.delete()
}
fun excute() {
CoroutineScope(Dispatchers.IO).launch {
LogUtil.e("onHtml value >> ${value}")
mediaUrls.forEach { url ->
var downPic = false
try {
LogUtil.e("try Jsoup.parse ${url}")
Jsoup.parse(URL(url), defaultTime.times(4).toInt()).let {
try {
LogUtil.e("onit Jsoup.parse ${it.title()}")
if (it.select("svg").size > 0) {
try {
downPic(url, agent, current!!, cookie!!, lDownFinishListener)
reqCount += 1
} catch (e : Exception) {
e.printStackTrace()
}
} else {
it.getElementsByTag("video")?.forEach {
it.attribute("src").value?.let {
var url = if (it.startsWith("http")) {
it
} else {
"https:".plus(it)
}
try {
downMp4(url, agent, current!!, cookie!!, lDownFinishListener)
reqCount += 1
} catch (e : Exception) {
e.printStackTrace()
}
}
}
}
} catch (e: UnsupportedMimeTypeException) {
LogUtil.e("e.message3 ${e.message}")
} catch (e: Exception) {
LogUtil.e("e.message4 ${e.message}")
}
}
} catch (e: UnsupportedMimeTypeException) {
LogUtil.e("e.message ${e.message}")
LogUtil.e("e.message ${e.localizedMessage}")
if (e.message?.contains("Must be text") == true) {
downPic = true
}
} catch (e: Exception) {
if (url.contains("dcimg") == true) {
downPic = true
}
LogUtil.e("e.message2 ${e.message}")
} finally {
if (downPic) {
try {
downPic(url, agent, current!!, cookie!!, lDownFinishListener)
reqCount += 1
} catch (e : Exception) {
e.printStackTrace()
}
}
}
delay(defaultTime)
}
LogUtil.e("END OF LOOP ${reqCount}")
endOfLooPCheck = true
delay(defaultTime.times(4))
if (reqCount <= 0) {
enofLoop()
}
}
}
fun indexSave(htmlString:StringBuffer, targetFile :File, host: String) {
BufferedWriter(FileWriter(targetFile)).use { writer ->
trimHtnl(htmlString.toString(), host)?.let { result ->
writer.write(result.toString())
}
}
}
fun trimHtnl(target : String, host : String) : StringBuffer {
var result = target.replace("\\\"","\"").replace("\\n\\t\\t\\t","").replace("\\n\\t\\t","").replace("\\n\\t","").replace("\\t", "").replace("\\n", "").replace("\"\"\"","").replace("href=\"//","href=\"https://").replace("src=\"//","src=\"https://").replace("url(\"//","url(\"https://").replace("url(&quot;//","url(&quot;https://")
if (host?.contains("clien") == true) {
result = result.replace("href=\"/service","href=\"https://m.clien.net/service").replace("href=\"\\&quot;/service","href=\"\\&quot;https://m.clien.net/service")
}
return StringBuffer(result)
}
fun downMp4(url : String, agent : String, current : String,cookie : String, listner :DownFinishListener) {
LogUtil.e("try imageFile down ${url}")
val path = File(
Environment.getExternalStorageDirectory(),
"bums"
)
DownPicUtil.downMp4(
File(
path,"private_mp4"
).path,
url,
agent,
current,
cookie,
listner
)
}
fun downPic( url : String, agent : String, current : String,cookie : String, listner :DownFinishListener) {
LogUtil.e("try imageFile down ${url}")
val cookieManager =
CookieManager.getInstance()
val cookie =
cookieManager.getCookie(current)
val path = File(
Environment.getExternalStorageDirectory(),
"bums"
)
DownPicUtil.downPic(
File(path, "private_img").path,
url,
agent,
current,
cookie,
listner)
}
}

View File

@ -1,8 +1,16 @@
package bums.lunatic.launcher.home package bums.lunatic.launcher.home
import android.app.Activity import android.content.ClipData
import android.content.ClipboardManager
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.print.PDFPrint
import android.provider.AlarmClock
import android.util.Base64
import android.view.HapticFeedbackConstants
import android.view.KeyEvent import android.view.KeyEvent
import android.view.KeyEvent.ACTION_UP import android.view.KeyEvent.ACTION_UP
import android.view.KeyEvent.KEYCODE_BUTTON_A import android.view.KeyEvent.KEYCODE_BUTTON_A
@ -18,21 +26,52 @@ import android.view.KeyEvent.KEYCODE_DPAD_UP
import android.view.MotionEvent import android.view.MotionEvent
import android.view.MotionEvent.ACTION_MOVE import android.view.MotionEvent.ACTION_MOVE
import android.view.View import android.view.View
import android.webkit.CookieManager
import android.webkit.CookieSyncManager
import android.webkit.JavascriptInterface
import android.webkit.ValueCallback
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.core.view.postDelayed
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
import bums.lunatic.launcher.behavior.Behavior
import bums.lunatic.launcher.helpers.Constants.Companion.BOTTOM_SHEET_TAG
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_LOCK_METHOD
import bums.lunatic.launcher.helpers.UniUtils.Companion.expandNotificationPanel
import bums.lunatic.launcher.helpers.UniUtils.Companion.lockMethod
import bums.lunatic.launcher.model.CiliMagnet
import bums.lunatic.launcher.model.RssData import bums.lunatic.launcher.model.RssData
import bums.lunatic.launcher.qaccess.QuickAccess
import bums.lunatic.launcher.settings.SettingsActivity
import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.Blog
import bums.lunatic.launcher.utils.SimpleFingerGestures
import bums.lunatic.launcher.workers.WorkersDb import bums.lunatic.launcher.workers.WorkersDb
import com.google.gson.Gson
import io.realm.kotlin.UpdatePolicy import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query import io.realm.kotlin.ext.query
import io.realm.kotlin.ext.realmListOf
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kr.lunaticbum.awesomewebview.AwesomeWebView import kr.lunaticbum.awesomewebview.AwesomeWebView
import kr.lunaticbum.awesomewebview.AwesomeWebView.Builder
import kr.lunaticbum.awesomewebview.AwesomeWebViewActivity import kr.lunaticbum.awesomewebview.AwesomeWebViewActivity
import kr.lunaticbum.awesomewebview.listeners.BroadCastManager import kr.lunaticbum.awesomewebview.listeners.BroadCastManager
import kr.lunaticbum.awesomewebview.objects.CustomMenu
import kr.lunaticbum.utils.content.ContextUtil import kr.lunaticbum.utils.content.ContextUtil
import kr.lunaticbum.utils.log.LogUtil import kr.lunaticbum.utils.log.LogUtil
import org.jsoup.Jsoup
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.net.URLEncoder
import java.nio.charset.Charset
import java.security.MessageDigest
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.text.Charsets.UTF_8
class RssViewBuilder(context: Context) : AwesomeWebView.Builder(context) { class RssViewBuilder(context: Context) : AwesomeWebView.Builder(context) {
var rssId : String = "" var rssId : String = ""
@ -61,27 +100,142 @@ class RssViewBuilder(context: Context) : AwesomeWebView.Builder(context) {
ContextUtil.startActivity(intent) ContextUtil.startActivity(intent)
} }
} }
class RssViewerActivity : AwesomeWebViewActivity(), View.OnGenericMotionListener { class RssViewerActivity : AwesomeWebViewActivity(), View.OnGenericMotionListener , View.OnTouchListener {
var actionButtonPressX = 0f var actionButtonPressX = 0f
var actionButtonPressY = 0f var actionButtonPressY = 0f
var rssId : String = "" var rssId : String = ""
var currentIdx = 0 // var currentIdx = 0
var double = false var double = false
var rssList: MutableList<String> = ArrayList() var rssList: MutableList<String> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
LogUtil.e("intent >>>> ${intent}")
if (intent.action.equals(Intent.ACTION_VIEW)) {
intent.data.toString()?.let {
loadWithIntent = true
load(it)
}
} else {
loadWithIntent = false
}
webView?.setOnTouchListener(this)
}
private var startX = 0f
private var startY = 0f
private var startTime = 0L
// 임계값(앱에 맞게 조정)
private val swipeThreshold = 150 // 스와이프 최소 거리(px)
private val swipeTime = 300 // 스와이프 최대 시간(ms)
private val clickThreshold = 30 // 클릭으로 인정할 최대 이동 거리(px)
override fun onTouch(v: View?, event: MotionEvent): Boolean {
if(event.device.name.equals("JX-12",true)) {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
startX = event.x
startY = event.y
startTime = System.currentTimeMillis()
return true
}
MotionEvent.ACTION_UP -> {
val endX = event.x
val endY = event.y
val endTime = System.currentTimeMillis()
val dx = endX - startX
val dy = endY - startY
val duration = endTime - startTime
// 클릭: 거의 움직이지 않고 짧은 시간
if (Math.abs(dx) < clickThreshold && Math.abs(dy) < clickThreshold && duration < 250) {
onClick() // View의 기본 클릭 호출
return true
}
// 좌우 스와이프: 수평 이동이 크고, 빠르게
if (Math.abs(dx) > swipeThreshold && Math.abs(dx) > Math.abs(dy) && duration < swipeTime) {
if (dx > 0) {
onSwipeRight()
} else {
onSwipeLeft()
}
return true
}
Blog.LOGE("dy >>> $dy")
// 상하 스크롤: 수직 이동이 더 크고, 일정 거리 이상
// if (Math.abs(dy) > swipeThreshold && Math.abs(dy) > Math.abs(dx)) {
// if (dy > 0) {
// onScrollDown()
// } else {
// onScrollUp()
// }
// return true
// }
}
else -> return super.onTouchEvent(event)
}
}
return super.onTouchEvent(event)
}
private fun onClick() {
Blog.LOGE("onClick")
finish()
}
// 아래 메서드에 원하는 동작 구현
private fun onSwipeLeft() {
Blog.LOGE("onSwipeLeft")
vote()
}
private fun onSwipeRight() {
Blog.LOGE("onSwipeRight")
doNextPage()
}
private fun onScrollUp() {
Blog.LOGE("onScrollUp")
webView?.let {
it.scrollBy(0, (it.contentHeight / 100).coerceAtLeast(200) * -1)
}
}
private fun onScrollDown() {
Blog.LOGE("onScrollDown")
webView?.let {
it.scrollBy(0, (it.contentHeight / 100).coerceAtLeast(200) * 1)
}
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
webView?.setOnGenericMotionListener(this) webView?.setOnGenericMotionListener(this)
} }
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
if (intent?.action?.equals(Intent.ACTION_VIEW) == true) {
intent?.data?.toString()?.let {
loadWithIntent = true
load(it)
}
} else {}
}
var lasteventTime = 0L var lasteventTime = 0L
override fun onGenericMotion(p0: View?, ev: MotionEvent?): Boolean { override fun onGenericMotion(p0: View?, ev: MotionEvent?): Boolean {
if (ev?.device?.name?.contains("SM-031N Mouse") == true) { if (ev?.device?.name?.contains("SM-031N Mouse") == true) {
if(ev.action == ACTION_MOVE && ev.x != ev.y) { if(ev.action == ACTION_MOVE && ev.x != ev.y) {
val correctTime = (ev.eventTime - lasteventTime) > 2 val correctTime = (ev.eventTime - lasteventTime) > 2
if (correctTime) { if (correctTime) {
Blog.LOGE("onGenericMotionEvent webviews ${p0} ev?.device?.name >>> ${ev?.device?.name} >> ${ev}") // Blog.LOGE("onGenericMotionEvent webviews ${p0} ev?.device?.name >>> ${ev?.device?.name} >> ${ev}")
if (ev.x <= -1.0f) { if (ev.x <= -1.0f) {
leftClick() leftClick()
} else if (ev.x >= 1.0f) { } else if (ev.x >= 1.0f) {
@ -100,19 +254,22 @@ class RssViewerActivity : AwesomeWebViewActivity(), View.OnGenericMotionListene
} }
return false return false
} }
private var lastX = 0f
private var lastY = 0f
private var onDown = false
override fun onGenericMotionEvent(ev: MotionEvent?): Boolean { override fun onGenericMotionEvent(ev: MotionEvent?): Boolean {
if (ev?.device?.name?.contains("SM-031N Mouse") == true) { if (ev?.device?.name?.contains("SM-031N Mouse") == true) {
Blog.LOGE("onGenericMotionEvent ev?.device?.name >>> ${ev?.device?.name} >> ${ev}") // Blog.LOGE("onGenericMotionEvent ev?.device?.name >>> ${ev?.device?.name} >> ${ev}")
return true return true
} }
return super.onGenericMotionEvent(ev) return super.onGenericMotionEvent(ev)
} }
override fun dispatchKeyEvent(ev: KeyEvent): Boolean { override fun dispatchKeyEvent(ev: KeyEvent): Boolean {
Blog.LOGE("dispatch ev?.device?.name >>> ${ev?.device?.name}") // Blog.LOGE("dispatch ev?.device?.name >>> ${ev?.device?.name}")
if (ev?.device?.name?.contains("SM-031N Mouse") == true) { if (ev?.device?.name?.contains("SM-031N Mouse") == true) {
Blog.LOGE("onGenericMotionEvent ev?.device?.name >>> ${ev?.device?.name} >> ${ev}") // Blog.LOGE("onGenericMotionEvent ev?.device?.name >>> ${ev?.device?.name} >> ${ev}")
when(ev.action) { when(ev.action) {
ACTION_UP -> { ACTION_UP -> {
when(ev.keyCode) { when(ev.keyCode) {
@ -155,25 +312,34 @@ class RssViewerActivity : AwesomeWebViewActivity(), View.OnGenericMotionListene
} }
fun vote(){ fun vote(){
Blog.LOGE("Arrow Center Click") if (!loadWithIntent) {
WorkersDb.getRealm().apply {
writeBlocking { Blog.LOGE("Arrow Center Click")
val result = query<RssData>().query("originPage == $0", rssId).find() WorkersDb.getRealm().apply {
if(result.size > 0) { writeBlocking {
result.forEach { it.vote = true } val result = query<RssData>().query("originPage == $0", rssId).find()
if (result.size > 0) {
result.forEach { it.vote = true }
}
} }
} }
doNextPage()
// webView?.evaluateJavascript("document.documentElement.outerHTML",
// object : ValueCallback<String> {
// override fun onReceiveValue(value: String?) {
// val html = value?.replace("\\u003C", "<")
// onHtml(html, false)
// }
// })
} else {
finish()
} }
rssList.remove(rssId) }
if (currentIdx < rssList.size - 1) {
currentIdx += 1 fun doNextPage() {
rssId = rssList.get(currentIdx) rssList.removeAll { it.equals(rssId) }
Blog.LOGE("Arrow Right Click ${currentIdx} ${rssId}") if (rssList.size > 0) {
load(rssId) rssId = rssList.removeAt(0)
} else if (currentIdx > 0) {
currentIdx -= 1
rssId = rssList.get(currentIdx)
Blog.LOGE("Arrow Left Click ${currentIdx} ${rssId}")
load(rssId) load(rssId)
} else { } else {
Toast.makeText(this, "없어 끄자", Toast.LENGTH_LONG).show() Toast.makeText(this, "없어 끄자", Toast.LENGTH_LONG).show()
@ -181,71 +347,68 @@ class RssViewerActivity : AwesomeWebViewActivity(), View.OnGenericMotionListene
} }
registCancelSearch() registCancelSearch()
} }
fun hideRss() { fun hideRss() {
Blog.LOGE("make no show") if (!loadWithIntent) {
WorkersDb.getRealm().apply { Blog.LOGE("make no show")
writeBlocking { WorkersDb.getRealm().apply {
val result = writeBlocking {
query<RssData>().query("originPage == $0", rssId) val result =
.find() query<RssData>().query("originPage == $0", rssId)
if (result.size > 0) { .find()
result.forEach { it.read += 5 } if (result.size > 0) {
result.forEach { it.read += 5 }
}
} }
} }
} doNextPage()
rssList.remove(rssId)
if (currentIdx < rssList.size - 1) {
currentIdx += 1
rssId = rssList.get(currentIdx)
Blog.LOGE("Arrow Right Click ${currentIdx} ${rssId}")
load(rssId)
registCancelSearch()
} else if (currentIdx > 0) {
currentIdx -= 1
rssId = rssList.get(currentIdx)
Blog.LOGE("Arrow Left Click ${currentIdx} ${rssId}")
load(rssId)
registCancelSearch()
} else { } else {
finish() finish()
} }
} }
fun rightClick() { fun rightClick() {
if (currentIdx < rssList.size - 1) { doNextPage()
currentIdx += 1
rssId = rssList.removeAt(currentIdx)
Blog.LOGE("Arrow Right Click ${currentIdx} ${rssId}")
load(rssId)
registCancelSearch()
} else {
Toast.makeText(this, "없어 끄자", Toast.LENGTH_LONG).show()
fast()
}
} }
fun leftClick() { fun leftClick() {
if (currentIdx > 0) { hideRss()
currentIdx -= 1
rssId = rssList.removeAt(currentIdx)
Blog.LOGE("Arrow Left Click ${currentIdx} ${rssId}")
load(rssId)
registCancelSearch()
} else {
Toast.makeText(this, "없어 끄자", Toast.LENGTH_LONG).show()
fast()
}
Blog.LOGE("Arrow Left Click")
} }
fun getUnit() = ((webView?.height ?: 0) * 0.4).toInt() fun getUnit() = ((webView?.height ?: 0) * 0.4).toInt()
fun scrollDown() { fun scrollDown() {
Blog.LOGE("Arrow Down Click") try {
registCancelSearch() Blog.LOGE("Arrow Down Click")
webView?.scrollTo(webView?.scrollX ?: 0, (webView?.scrollY ?: 0) + getUnit()) registCancelSearch()
runOnUiThread {
webView?.scrollTo(webView?.scrollX?: 0,(webView?.scrollY?: 0) + getUnit())
}
} catch (e : Exception) {
e.printStackTrace()
}
} }
override var pdfListner : PDFPrint.OnPDFPrintListener? = object : PDFPrint.OnPDFPrintListener {
override fun onSuccess(file: File?) {
LogUtil.e("file.absolutePath >>> ${file?.absolutePath}")
Toast.makeText(
applicationContext,
resources.getString(
stringResPhotoSavedTo
) + file?.absolutePath,
Toast.LENGTH_LONG
).apply {
}.show()
}
override fun onError(exception: Exception?) {
}
}
// val tika: Tika = Tika()
override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean { override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
if (ev?.device?.name?.contains("BLE-M3") == true) { if (ev?.device?.name?.contains("BLE-M3") == true) {
Blog.LOGE("keyEvent >>>>> dispatchGenericMotionEvent ${ev}") Blog.LOGE("keyEvent >>>>> dispatchGenericMotionEvent ${ev}")
@ -317,25 +480,33 @@ class RssViewerActivity : AwesomeWebViewActivity(), View.OnGenericMotionListene
Blog.LOGE("Arrow Up Click") Blog.LOGE("Arrow Up Click")
registCancelSearch() registCancelSearch()
} }
protected fun load(newUrl: String) { protected fun load(newUrl: String) {
newUrl.toUri().host?.let { newUrl?.let { it ->
val splits = it.replace("http://","").replace("https://","").split(".") var url = if(it.startsWith("http://")) {
when(splits.size) { "https://${it.replace("http://","")}"
1-> host = splits[0] } else it
2-> host = splits[0] // LogUtil.e("newUrl >>> ${url}")
3-> host = splits[1] url.toUri().host?.let {
4-> host = splits[2] val splits = it.replace("http://","").replace("https://","").split(".")
else -> { when(splits.size) {
host = null 1-> host = splits[0]
2-> host = splits[0]
3-> host = splits[1]
4-> host = splits[2]
else -> {
host = null
}
} }
} }
if (extraHeaders == null) {
webView!!.loadUrl(url)
} else {
webView!!.loadUrl(url, extraHeaders!!)
}
registCancelSearch()
} }
if (extraHeaders == null) {
webView!!.loadUrl(newUrl!!)
} else {
webView!!.loadUrl(newUrl!!, extraHeaders!!)
}
registCancelSearch()
} }
override fun initializeOptions() { override fun initializeOptions() {
@ -347,29 +518,405 @@ class RssViewerActivity : AwesomeWebViewActivity(), View.OnGenericMotionListene
builder?.rssList?.let { this.rssList.addAll(it) } builder?.rssList?.let { this.rssList.addAll(it) }
Blog.LOGE("this.rssList >>>> ${this.rssList}") Blog.LOGE("this.rssList >>>> ${this.rssList}")
this.rssList.forEachIndexed { index, s -> }
if (s.equals(rssId)) {
currentIdx = index override fun bindViews() {
return@forEachIndexed} super.bindViews()
if (this.rssId.contains(".guru")|| this.rssId.contains("bookto")) {
webView?.clearCache(true)
Blog.LOGE("this.webView >>>> ${this.rssId}")
Blog.LOGE("this.webView >>>> ${this.webView}")
if (this.rssId.contains(".guru")) webView?.alpha = 0.2f
webView?.addJavascriptInterface(gji, "GJI")
} }
} }
override fun webviewOnPageFinished() {
double = false fun ByteArray.toHex() = joinToString(separator = "") { byte -> "%02x".format(byte) }
if(hasYoutubePlayer) {
LogUtil.e("hasYoutubePlayer >>> ${hasYoutubePlayer}") fun hashString(str: String, algorithm: String): ByteArray =
MessageDigest.getInstance(algorithm).digest(str.toByteArray(UTF_8))
fun getBase64ImageData(fileName : String) : String {
val inputStream: InputStream =
FileInputStream(fileName) // You can get an inputStream using any I/O API
val bytes: ByteArray
val buffer = ByteArray(8192)
var bytesRead: Int
val output = ByteArrayOutputStream()
try {
while ((inputStream.read(buffer).also { bytesRead = it }) != -1) {
output.write(buffer, 0, bytesRead)
}
} catch (e: IOException) {
e.printStackTrace()
} }
WorkersDb.getRealm().apply {
writeBlocking { bytes = output.toByteArray()
val result = return Base64.encodeToString(bytes, Base64.DEFAULT)
query<RssData>().query("originPage == $0", rssId) }
.find()
if (result.size == 1) {
result.first().read += 1
} else {
result.forEach { it.read += 1 } fun run(value : String, autoCheck : Boolean) {
webView!!.setOnScrollChangeListener(null)
var mediaUrls = arrayListOf<String>()
mediaUrls.addAll(this.mediaUrls)
CookieSyncManager.createInstance(applicationContext)
CookieSyncManager.getInstance().sync()
val cookieManager =
CookieManager.getInstance()
val cookie =
cookieManager.getCookie(webView!!.url)
val agent = webView!!.settings.userAgentString
val current = webView!!.url
val newPath = hashString(current!!, "MD5").toHex()
Executors.newSingleThreadScheduledExecutor().schedule({
OfflineContents(this@RssViewerActivity, host!!,cookie,agent,current,newPath,value,autoCheck,mediaUrls).excute()
}, defaultTime, TimeUnit.MILLISECONDS)
runOnUiThread {
hideBlock()
if (!autoCheck) {
doNextPage()
}
}
}
override fun onTrimMemory(level: Int) {
LogUtil.e("onTrimMemory >>> ${level} current ${url} current ${webView?.url ?: ""}")
super.onTrimMemory(level)
}
fun showDi(code : String, items : ArrayList<String>, links : ArrayList<String>) {
runOnUiThread {
registCancelSearch()
hideBlock()
val builder = AlertDialog.Builder(this@RssViewerActivity)
builder.setTitle("code : ${code}")
builder?.setItems(
items.toTypedArray()
) { dialog, which ->
LogUtil.e("hitTestResult.extra >>> ${dialog} ,${which}")
links?.get(which)?.let { link ->
(this.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager)?.let { mng ->
Blog.LOGE("link >>> ${link}")
mng.clearPrimaryClip()
mng.addPrimaryClipChangedListener {
mng.primaryClip?.getItemAt(0)?.text?.let {
if (it.length > 0 && it.startsWith("magnet:?xt=urn:")) {
Blog.LOGE("magnet >>>> $it")
try {
val launchIntent =
packageManager.getLaunchIntentForPackage("com.pikcloud.pikpak")
launchIntent?.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
startActivity(launchIntent)
}catch (e:Exception) {e.printStackTrace()}
}
}
}
mng.setPrimaryClip(ClipData.newPlainText("",link))
}
}
}
val dialog = builder?.create()
dialog?.show()
}
}
val gji = GJInterface(this)
inner class GJInterface(val context: Context) {
@JavascriptInterface
fun onResult(result : String?) {
registCancelSearch()
result.toString()?.replace("\\u003C","<")?.replace("\\&quot;","")?.let {
if (rssId.contains("guru")) {
Jsoup.parse(it)?.let { guru ->
Blog.LOGE("guru >>> ${guru.title()} ")
guru.getElementsByClass("row")?.forEach { row ->
row.getElementsByClass("grid1").first().getElementsByTag("a")?.first()
?.attr("title")?.let { title ->
Blog.LOGE("row >>> ${title.split("]")?.first()?.replace("[", "")}")
}
}
}
} else if(rssId.contains("book")){
Jsoup.parse(it)?.let { book ->
Blog.LOGE("book.title() >>> ${book.title()}")
}
} }
} }
} }
registCancelSearch()
@JavascriptInterface
fun onCode(code : String) {
Blog.LOGE("onCode ${code}")
registCancelSearch()
CoroutineScope(Dispatchers.IO).launch {
var temp = arrayListOf<CiliMagnet>()
Jsoup.connect("https://cili.site/search?q=${URLEncoder.encode(code, Charset.defaultCharset().name())}").get().let { cili ->
cili.getElementsByTag("tr").forEach { cili_tr ->
CiliMagnet().let { ciliMgn ->
ciliMgn.link = if(cili_tr.getElementsByTag("a").size > 0)cili_tr.getElementsByTag("a").get(0).attr("href") else ""
ciliMgn.title = if(cili_tr.getElementsByTag("p").size > 0)cili_tr.getElementsByTag("p").text() else ""
ciliMgn.size = if(cili_tr.getElementsByClass("td-size").size > 0)cili_tr.getElementsByClass("td-size").text() else ""
Blog.LOGE("ciliMgn.size >>>> ${ciliMgn.size}")
Blog.LOGE("ciliMgn.size >>>> ${ciliMgn.title}")
if(ciliMgn.isValid() && temp.size < 8 ) {
try {
Jsoup.connect(ciliMgn.getMagnetPageLink()).get()
.let { mgn_Page ->
if (mgn_Page.getElementsByClass("input-group magnet-box").size > 0) {
mgn_Page.getElementsByClass("input-group magnet-box")
.get(0)?.let { magnet_box ->
magnet_box.getElementById(
"input-magnet"
)?.let { input_magnet ->
Blog.LOGE("input_magnet >>> ${input_magnet}")
ciliMgn.magnetLink =
input_magnet.attr("value")
.replace("&amp;", "&")
}
}
}
}.apply {
temp.add(ciliMgn)
}
}catch (e:Exception) {}
}
}
if(temp.size > 3) {
return@forEach
}
}.apply {
if (temp.size > 0) {
showDi(
code,
temp.map {
it.title.plus(" | ").plus(it.size).plus(" | ")
} as ArrayList<String>, temp.map {
it.magnetLink
} as ArrayList<String>)
}
}
}
}.start()
}
} }
}
override fun onHtml(value: String?, autoCheck : Boolean) {
vote()
// chechHandler.removeCallbacks(cancelSearch)
// if (loadWithIntent){
// return
// }
// showBlock()
//
// var count = (webView!!.contentHeight / (webView!!.height * 0.3).toInt())
// LogUtil.e("count >>>> ${count} webView!!.contentHeight >>>> ${webView!!.contentHeight} , webView!!.height >>>> ${webView!!.height} :: ${(webView!!.height * 0.3).toInt()}")
// chechHandler.postDelayed(pageDown, defaultTime)
// webView!!.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
// val measuredHeight: Int = v.measuredHeight
// LogUtil.e("OnScrollChange >>> ${scrollY} , ${oldScrollY}")
// if(measuredHeight + scrollY == webView!!.computeVerticalScrollRange()){
// chechHandler.removeCallbacks(scrollDown)
// chechHandler.removeCallbacks(pageDown)
// chechHandler.postDelayed({
// webView!!.evaluateJavascript("document.documentElement.outerHTML",object : ValueCallback<String> {
// override fun onReceiveValue(value: String?) {
// val html = value?.replace("\\u003C", "<")
// this@RssViewerActivity.run(html!!, autoCheck)
// }
// })
// },defaultTime.times(2))
// } else {
// chechHandler.removeCallbacks(cancelSearch)
// Blog.LOGE("onScrollChanged called PageDown")
//// chechHandler.removeCallbacks(scrollDown)
// if (switch) {
// chechHandler.removeCallbacks(pageDown)
// chechHandler.postDelayed(scrollDown, defaultTime)
// switch = false
// } else {
// switch = true
// chechHandler.removeCallbacks(scrollDown)
// chechHandler.postDelayed(pageDown, defaultTime)
// }
// }
//// else if (scrollY % 10 == 0 || oldScrollY % 10 == 0){
////// chechHandler.removeCallbacks(pageDown)
////// chechHandler.postDelayed(scrollDown, defaultTime)
//// }
// }
}
var switch = false
var scrollDown : Runnable = Runnable{
webView?.let {
var times = if (it.scrollY > 50) it.scrollY / 50 else 5
it.scrollTo(it.scrollX,times.plus(1).times(50))
}
}
var pageDown : Runnable = Runnable{
webView!!.pageDown(false)
}
var isFirst = true
override fun webviewOnPageFinished() {
if (rssId.contains(".guru")) {
registCancelSearch()
webView?.postDelayed(2000L,{
webView?.evaluateJavascript("try{GJI.log();}catch(e){console.log(e);}", {})
webView?.evaluateJavascript("try{GJI.onResult(document.documentElement.outerHTML);}catch(e){console.log(e);}", {})
webView?.evaluateJavascript("document.getElementsByClassName('banner-ad-wrapper')[0].remove()",{})
})
}
else if(rssId.contains("booktoki")) {
registCancelSearch()
webView?.postDelayed(2000L,{
})
}
else {
double = false
registCancelSearch()
if (hasYoutubePlayer) {
LogUtil.e("hasYoutubePlayer >>> ${hasYoutubePlayer}")
}
WorkersDb.getRealm().apply {
writeBlocking {
val result =
query<RssData>().query("originPage == $0", rssId)
.find()
// if (result.size == 1) {
// result.first().read += 1
// } else {
result.forEach { it.read += 1 }
// }
}
}
try {
val muted =
"try{" +
"var videos = document.getElementsByTagName('video');" +
"for (var i = 0; i < videos.length; i++) {" +
"videos[i].muted = true;" +
"}" +
"}catch(e){}"
webView?.evaluateJavascript(muted,{
Blog.LOGE("RESULT >> $it")
})
}catch (e : Exception) {e.printStackTrace()}
try {
val muted =
"try{" +
"var videos = document.getElementsByTagName('video');" +
"for (var i = 0; i < videos.length; i++) {" +
"videos[i].controlsList.remove('nodownload');"
"}" +
"}catch(e){}"
webView?.evaluateJavascript(muted,{
Blog.LOGE("RESULT >> $it")
})
}catch (e : Exception) {e.printStackTrace()}
webView?.postDelayed({
try {
val muted =
"try{" +
"var videos = document.getElementsByTagName('video');" +
"for (var i = 0; i < videos.length; i++) {" +
"videos[i].muted = true;" +
"}" +
"}catch(e){console.log(e);}"
webView?.evaluateJavascript(muted,{
Blog.LOGE("RESULT >> $it")
})
}catch (e : Exception) {e.printStackTrace()}
try {
val muted =
"try{" +
"var videos = document.getElementsByTagName('video');" +
"for (var i = 0; i < videos.length; i++) {" +
"videos[i].controlsList.remove('nodownload');"
"}" +
"}catch(e){console.log(e);}"
webView?.evaluateJavascript(muted,{
Blog.LOGE("RESULT >> $it")
})
}catch (e : Exception) {e.printStackTrace()}
},1000)
if (loadWithIntent) {
webView?.evaluateJavascript(
"try{document.querySelector('meta[name=viewport]').setAttribute('content','initial-scale=1.0')}catch(e){}",
null
)
webView?.evaluateJavascript(
"try{document.querySelector('meta[name=viewport]').setAttribute('content','initial-scale=1.0')}catch(e){}",
null
)
webView?.settings?.useWideViewPort = true
}
if (webView?.url?.contains("dcinside") == true) {
webView?.evaluateJavascript(
"try{document.querySelector('#div_adnmore_area').hidden = true;}catch(e){}",
null
)
} else if (webView?.url?.contains("fmkorea") == true) {
if (loadWithIntent) {
} else {
webView?.postDelayed({
webView?.evaluateJavascript(
"try{document.querySelector('.m_rd_nav_side').hidden = true;}catch(e){}",
null
)
webView?.evaluateJavascript(
"try{document.querySelector('[class*='bd bd_mobile ']').remove();}catch(e){}",
null
)
}, 500L)
}
}
}
}
inner class BookHelper {
@JavascriptInterface
fun sendValueFromHtml(string: String) {
Jsoup.parse(string)?.let { html ->
val toon_intro = html.getElementsByClass("toon_index")?.first()
val view_padding = html.select("#bo_v_con")
if (toon_intro != null) {
}else if (view_padding.size > 0){
//
} else {
Blog.LOGE("finishedUrl >>> ${rssId} :::: ${html.title()}")
}
}
}
}
}

View File

@ -4,8 +4,7 @@ import android.util.Xml
import bums.lunatic.launcher.model.NewsData import bums.lunatic.launcher.model.NewsData
import bums.lunatic.launcher.model.RssDataInterface import bums.lunatic.launcher.model.RssDataInterface
import bums.lunatic.launcher.model.others.Reddit import bums.lunatic.launcher.model.others.Reddit
import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.beforeOneDay
import bums.lunatic.launcher.utils.beforeDay
import com.google.gson.Gson import com.google.gson.Gson
import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException import org.xmlpull.v1.XmlPullParserException
@ -14,14 +13,13 @@ import java.io.InputStream
import java.io.InputStreamReader import java.io.InputStreamReader
import java.net.URL import java.net.URL
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 parseDateFormat2: SimpleDateFormat = SimpleDateFormat("E, dd MM yyyy HH:mm:ss ZZ", Locale.ENGLISH) var parseDateFormat2: SimpleDateFormat = SimpleDateFormat("E, dd MM yyyy HH:mm:ss ZZ", Locale.ENGLISH)
var limitDateTime = beforeDay(Date(),3) var limitDateTime = beforeOneDay()
fun getFeeds(url : String) : List<RssDataInterface> { fun getFeeds(url : String) : List<RssDataInterface> {
var returnList = mutableListOf<RssDataInterface>() var returnList = mutableListOf<RssDataInterface>()
try { try {
@ -34,7 +32,7 @@ object RssFeedsParser {
fun getReddit(url : String, nsfw : Boolean): List<RssDataInterface> { fun getReddit(url : String, nsfw : Boolean): List<RssDataInterface> {
var returnList = mutableListOf<RssDataInterface>() var returnList = mutableListOf<RssDataInterface>()
var dateTime = beforeDay(Date(),3) var dateTime = beforeOneDay()
try { try {
var mReddit = Gson().fromJson(InputStreamReader(getInputStream(url)!!), Reddit::class.java) var mReddit = Gson().fromJson(InputStreamReader(getInputStream(url)!!), Reddit::class.java)
mReddit.data?.children?.forEach { mReddit.data?.children?.forEach {

View File

@ -48,7 +48,6 @@ class WeatherHourlyAdapter(private val dataSet: ArrayList<Hour>): RecyclerView.A
override fun getItemCount(): Int = dataSet.size override fun getItemCount(): Int = dataSet.size
fun update(li: Collection<Hour>) { fun update(li: Collection<Hour>) {
Blog.LOGE("${this.javaClass.simpleName} update")
li.toList() li.toList()
this.dataSet.clear() this.dataSet.clear()
this.dataSet.addAll(li) this.dataSet.addAll(li)

View File

@ -4,43 +4,6 @@ import bums.lunatic.launcher.beforeDay
import bums.lunatic.launcher.utils.JamoUtils import bums.lunatic.launcher.utils.JamoUtils
import java.util.Date import java.util.Date
class MissD : RssDataInterface {
var link : String? = null
var title : String? = null
var thumb : String? = null
var desc : String? = null
override fun title(): String {
return title ?: ""
}
override fun thumbnailUrl(): String {
return thumb ?: ""
}
override fun originPage(): String {
return link ?: ""
}
override fun description(): String {
return desc ?: ""
}
override fun pubDate(): Long {
return beforeDay(Date())
}
override fun category(): RssDataType {
return RssDataType.GURU
}
override fun getCho(): String? {
return JamoUtils.split(title!!).joinToString("")
}
}
class MostItem : JGuru , RssDataInterface { class MostItem : JGuru , RssDataInterface {

View File

@ -17,4 +17,5 @@ class AppInfo : RealmObject {
var lastUseDate : Long = 0L var lastUseDate : Long = 0L
var category : String? = null var category : String? = null
var currentInstalled : Boolean = false var currentInstalled : Boolean = false
var isInstalled : Boolean = false
} }

View File

@ -2,7 +2,7 @@ package bums.lunatic.launcher.model
import bums.lunatic.launcher.utils.JamoUtils import bums.lunatic.launcher.utils.JamoUtils
import bums.lunatic.launcher.utils.afterDay import bums.lunatic.launcher.utils.afterDay
import bums.lunatic.launcher.utils.beforeDay import bums.lunatic.launcher.utils.beforeDayBy
import io.realm.kotlin.types.RealmObject import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.Ignore import io.realm.kotlin.types.annotations.Ignore
import io.realm.kotlin.types.annotations.PrimaryKey import io.realm.kotlin.types.annotations.PrimaryKey
@ -179,7 +179,7 @@ open class DcInside : RssDataInterface {
dateTiemL = cal.timeInMillis dateTiemL = cal.timeInMillis
dateTiemL dateTiemL
} else { } else {
0L Date().time
} }
} else { } else {
return dateTiemL return dateTiemL
@ -232,7 +232,7 @@ class RssData : RealmObject, RssDataInterface {
} }
else -> title ?: "" else -> title ?: ""
}.apply { }.apply {
chosung = JamoUtils.split(this).joinToString("") chosung = JamoUtils.split(title).joinToString("")
} }
} }
@ -308,15 +308,15 @@ open class Dotax(var pageLink : String,
before = dayString.toInt() before = dayString.toInt()
if (dateDesc.contains("")) { if (dateDesc.contains("")) {
before = 365 * before before = 365 * before
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before) dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
} else if (dateDesc.contains("")) { } else if (dateDesc.contains("")) {
before = 30 * before before = 30 * before
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before) dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
} else if (dateDesc.contains("")) { } else if (dateDesc.contains("")) {
before = 7 * before before = 7 * before
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before) dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
} else if (dateDesc.contains("")) { } else if (dateDesc.contains("")) {
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before) dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
} else if (dateDesc.contains("시간")) { } else if (dateDesc.contains("시간")) {
dateTime = dateTime =
if (isBefore) dateTime.minus(before.times(1000L * 60L * 60L)) else dateTime.plus( if (isBefore) dateTime.minus(before.times(1000L * 60L * 60L)) else dateTime.plus(

View File

@ -0,0 +1,40 @@
package bums.lunatic.launcher.model
import com.ibm.icu.util.ChineseCalendar
import io.realm.kotlin.types.RealmObject
import java.util.Calendar
import java.util.Date
class UserActionModel: RealmObject {
var actionType: String = ""
// var timestamp: Date = Realm()
var weekOfYear : Int = 0
var weekOfMonth : Int = 0
var dayOfWeek : Int = 0
var dayOfYear : Int = 0
var dayOfMonth : Int = 0
var hourOfDay : Int = 0
var month: Int = 0
var lunMonth : Int = 0
var lunDayOFMonth : Int = 0
var lunDayOfYear : Int = 0
init {
// val cal = Calendar.getInstance()
// cal.time = timestamp
// weekOfYear = cal.get(Calendar.WEEK_OF_YEAR)
// weekOfMonth = cal.get(Calendar.WEEK_OF_MONTH)
// dayOfWeek = cal.get(Calendar.DAY_OF_WEEK)
// hourOfDay = cal.get(Calendar.HOUR_OF_DAY)
// month = cal.get(Calendar.MONTH)
// dayOfYear = cal.get(Calendar.DAY_OF_YEAR)
// dayOfMonth = cal.get(Calendar.DAY_OF_MONTH)
// var cinCal = ChineseCalendar()
// cinCal.time = timestamp
// lunMonth = cinCal.get(ChineseCalendar.MONTH)
// lunDayOFMonth = cinCal.get(ChineseCalendar.DAY_OF_MONTH)
// lunDayOfYear = cinCal.get(ChineseCalendar.DAY_OF_YEAR)
}
}

View File

@ -4,7 +4,7 @@ import bums.lunatic.launcher.model.RssDataInterface
import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.model.RssDataType
import bums.lunatic.launcher.utils.JamoUtils import bums.lunatic.launcher.utils.JamoUtils
import bums.lunatic.launcher.utils.afterDay import bums.lunatic.launcher.utils.afterDay
import bums.lunatic.launcher.utils.beforeDay import bums.lunatic.launcher.utils.beforeDayBy
import org.json.JSONObject import org.json.JSONObject
import java.util.Date import java.util.Date
@ -1621,15 +1621,15 @@ open class VideoRenderer : RssDataInterface {
before = dayString.toInt() before = dayString.toInt()
if (dateDesc.contains("")) { if (dateDesc.contains("")) {
before = 365 * before before = 365 * before
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before) dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
} else if (dateDesc.contains("")) { } else if (dateDesc.contains("")) {
before = 30 * before before = 30 * before
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before) dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
} else if (dateDesc.contains("")) { } else if (dateDesc.contains("")) {
before = 7 * before before = 7 * before
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before) dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
} else if (dateDesc.contains("")) { } else if (dateDesc.contains("")) {
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before) dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
} else if (dateDesc.contains("시간")) { } else if (dateDesc.contains("시간")) {
dateTime = if (isBefore)dateTime.minus(before.times(1000L * 60L * 60L)) else dateTime.plus(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("")) {

View File

@ -47,38 +47,43 @@ class NLService : NotificationListenerService() {
// sbn.notification.extras.keySet().forEach { // sbn.notification.extras.keySet().forEach {
// BLog.LOGE("NLService********** keySet >> ${it} ${sbn.notification.extras.get(it)}") // BLog.LOGE("NLService********** keySet >> ${it} ${sbn.notification.extras.get(it)}")
// } // }
if (sbn.id != 0 && (sbn.packageName.contains(".") || sbn.packageName.contains("android")) && sbn.packageName.length > 0) { try {
NotificationItem().apply { if (sbn.id != 0 && (sbn.packageName.contains(".") || sbn.packageName.contains("android")) && sbn.packageName.length > 0) {
notiId = sbn.id NotificationItem().apply {
pkgName = sbn.packageName notiId = sbn.id
title = sbn.notification?.extras?.getString("android.title") ?: "" pkgName = sbn.packageName
subtext = sbn.notification?.extras?.getString("android.subText") ?: "" title = sbn.notification?.extras?.getString("android.title") ?: ""
selfDisplayName = sbn.notification?.extras?.getString("android.selfDisplayName") ?: "" subtext = sbn.notification?.extras?.getString("android.subText") ?: ""
tikerMsg = sbn.notification?.tickerText?.toString() ?: "" selfDisplayName = sbn.notification?.extras?.getString("android.selfDisplayName") ?: ""
postTime = sbn.postTime tikerMsg = sbn.notification?.tickerText?.toString() ?: ""
var uniq = title ?: subtext ?: selfDisplayName ?: tikerMsg ?: "" postTime = sbn.postTime
uniq_id = "${sbn.id}_${sbn.packageName}_${if (uniq.length > 3) uniq.substring(0,3) else uniq}" var uniq = title ?: subtext ?: selfDisplayName ?: tikerMsg ?: ""
uniq_id = "${sbn.id}_${sbn.packageName}_${if (uniq.length > 3) uniq.substring(0,3) else uniq}"
// BLog.LOGE("NLService********** enqueue TelegramBotGetter ${true == "bumssavor".equals(title)}") // BLog.LOGE("NLService********** enqueue TelegramBotGetter ${true == "bumssavor".equals(title)}")
// BLog.LOGE("NLService********** enqueue TelegramBotGetter ${(true == "org.telegram.messenger".equals(pkgName))}") // BLog.LOGE("NLService********** enqueue TelegramBotGetter ${(true == "org.telegram.messenger".equals(pkgName))}")
// BLog.LOGE("NLService********** enqueue TelegramBotGetter ${sbn.notification?.extras?.getString("android.text")?.startsWith("/") == true}") // BLog.LOGE("NLService********** enqueue TelegramBotGetter ${sbn.notification?.extras?.getString("android.text")?.startsWith("/") == true}")
}.apply { }.apply {
if (skips.contains(pkgName)) { if (skips.contains(pkgName)) {
} else { } else {
WorkersDb.insertNoti(this) // WorkersDb.insertNoti(this)
// BLog.LOGE("NLService********** onNotificationPosted ${Gson().toJson(this)}") // BLog.LOGE("NLService********** onNotificationPosted ${Gson().toJson(this)}")
}
} }
} }
} catch (e : Exception) {
e.printStackTrace()
} }
try {
if (sbn.packageName.contains("youtube")) { if (sbn.packageName.contains("youtube")) {
val m = getSystemService<MediaSessionManager>()!! val m = getSystemService<MediaSessionManager>()!!
val component = ComponentName(this, NLService::class.java) val component = ComponentName(this, NLService::class.java)
val sessions = m.getActiveSessions(component) val sessions = m.getActiveSessions(component)
sessions.forEach { session -> sessions.forEach { session ->
WorkersDb.getRealm().writeBlocking { WorkersDb.getRealm().writeBlocking {
Blog.LOGE("session.playbackState >>> ${session.playbackState}") // Blog.LOGE("session.playbackState >>> ${session.playbackState}")
if (session.playbackState != null) { if (session.playbackState != null) {
if (session.playbackState?.isActive == true && session.playbackState?.state?.equals( if (session.playbackState?.isActive == true && session.playbackState?.state?.equals(
STATE_PLAYING STATE_PLAYING
@ -111,6 +116,8 @@ class NLService : NotificationListenerService() {
} }
} }
}}catch (e : Exception) {
e.printStackTrace()
} }
// val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE") // val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
// i.putExtra("notification_event", "onNotificationPosted :" + sbn.packageName + "\n") // i.putExtra("notification_event", "onNotificationPosted :" + sbn.packageName + "\n")
@ -118,19 +125,19 @@ class NLService : NotificationListenerService() {
} }
override fun onNotificationRemoved(sbn: StatusBarNotification) { override fun onNotificationRemoved(sbn: StatusBarNotification) {
// BLog.LOGE("NLService********** onNOtificationRemoved") //// BLog.LOGE("NLService********** onNOtificationRemoved")
// BLog.LOGE("NLService ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName) //// BLog.LOGE("NLService ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName)
var uniq_id = "${sbn.id}_${sbn.packageName}" // var uniq_id = "${sbn.id}_${sbn.packageName}"
try { // try {
WorkersDb.getRealm()?.apply { // WorkersDb.getRealm()?.apply {
this.writeBlocking { // this.writeBlocking {
// delete(query<NotificationItem>().query("pkgName == $0", sbn.packageName).find()) //// delete(query<NotificationItem>().query("pkgName == $0", sbn.packageName).find())
} // }
} // }
}catch (e : Exception){e.printStackTrace()} // }catch (e : Exception){e.printStackTrace()}
// val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE") //// val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
// i.putExtra("notification_event", "onNotificationRemoved :" + sbn.packageName + "\n") //// i.putExtra("notification_event", "onNotificationRemoved :" + sbn.packageName + "\n")
// sendBroadcast(i) //// sendBroadcast(i)
} }
internal inner class NLServiceReceiver : BroadcastReceiver() { internal inner class NLServiceReceiver : BroadcastReceiver() {

View File

@ -30,6 +30,7 @@ import bums.lunatic.launcher.databinding.SettingsAppsBinding
import bums.lunatic.launcher.helpers.PrefBoolean import bums.lunatic.launcher.helpers.PrefBoolean
import bums.lunatic.launcher.helpers.PrefHelper import bums.lunatic.launcher.helpers.PrefHelper
import bums.lunatic.launcher.helpers.PrefLong import bums.lunatic.launcher.helpers.PrefLong
import bums.lunatic.launcher.utils.Blog
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
@ -132,16 +133,19 @@ internal class Apps : BottomSheetDialogFragment() {
settingsChanged = true settingsChanged = true
PrefLong.shortTimePeriod.set(value.toLong()) PrefLong.shortTimePeriod.set(value.toLong())
binding.shortTimeTitle.text = getString(R.string.shortTimeTitle) +" [${value.toInt()}분 마다]" binding.shortTimeTitle.text = getString(R.string.shortTimeTitle) +" [${value.toInt()}분 마다]"
Blog.LOGE("binding.shortTimeTitle.text >>> ${binding.shortTimeTitle.text}")
}) })
binding.middleTime.addOnChangeListener(Slider.OnChangeListener { _, value, _ -> binding.middleTime.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
settingsChanged = true settingsChanged = true
PrefLong.midTimePeriod.set(value.toLong()) PrefLong.midTimePeriod.set(value.toLong())
binding.middleTimeTitle.text = getString(R.string.middleTimeTitle) +" [${value.toInt()}분 마다]" binding.middleTimeTitle.text = getString(R.string.middleTimeTitle) +" [${value.toInt()}분 마다]"
Blog.LOGE("binding.shortTimeTitle.text >>> ${binding.middleTimeTitle.text}")
}) })
binding.longTime.addOnChangeListener(Slider.OnChangeListener { _, value, _ -> binding.longTime.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
settingsChanged = true settingsChanged = true
PrefLong.longTimePeriod.set(value.toLong()) PrefLong.longTimePeriod.set(value.toLong())
binding.longTimeTitle.text = getString(R.string.longTimeTitle) +" [${value.toInt()}]분 마다]" binding.longTimeTitle.text = getString(R.string.longTimeTitle) +" [${value.toInt()}]분 마다]"
Blog.LOGE("binding.shortTimeTitle.text >>> ${binding.longTimeTitle.text}")
}) })
binding.locationDistance.addOnChangeListener(Slider.OnChangeListener { _, value, _ -> binding.locationDistance.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->

View File

@ -0,0 +1,99 @@
package bums.lunatic.launcher.utils
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.io.UnsupportedEncodingException
import java.util.zip.DeflaterOutputStream
import java.util.zip.InflaterInputStream
import kotlin.math.floor
object CompressStringUtil {
val charsetName: String = "UTF-8"
/**
* String 객체를 압축하여 String 으로 리턴한다.
* @param string
* @return
*/
@Synchronized
fun compressString(string: String): String? {
return byteToString(compress(string))
}
/**
* 압축된 스트링을 복귀시켜서 String 으로 리턴한다.
* @param compressed
* @return
*/
@Synchronized
fun decompressString(compressed: String?): String {
return decompress(hexToByteArray(compressed))
}
private fun byteToString(bytes: ByteArray?): String? {
val sb = StringBuilder()
try {
for (b in bytes!!) {
sb.append(String.format("%02X", b))
}
} catch (e: Exception) {
e.printStackTrace()
return null
}
return sb.toString()
}
private fun compress(text: String): ByteArray? {
val baos = ByteArrayOutputStream()
try {
val out: OutputStream = DeflaterOutputStream(baos)
out.write(text.toByteArray(charset(charsetName)))
out.close()
} catch (e: UnsupportedEncodingException) {
e.printStackTrace()
return null
} catch (e: IOException) {
e.printStackTrace()
return null
}
return baos.toByteArray()
}
private fun decompress(bytes: ByteArray): String {
val `in`: InputStream = InflaterInputStream(ByteArrayInputStream(bytes))
val baos = ByteArrayOutputStream()
try {
val buffer = ByteArray(8192)
var len: Int
while ((`in`.read(buffer).also { len = it }) > 0) baos.write(buffer, 0, len)
return String(baos.toByteArray(), charset(charsetName))
} catch (e: IOException) {
e.printStackTrace()
throw AssertionError(e)
}
}
/**
* 16 문자열을 byte 배열로 변환한다.
*/
private fun hexToByteArray(hex: String?): ByteArray {
if (hex == null || hex.length % 2 != 0) {
return byteArrayOf()
}
val bytes = ByteArray(hex.length / 2)
var i = 0
while (i < hex.length) {
val value = hex.substring(i, i + 2).toInt(16).toByte()
bytes[floor((i / 2).toDouble()).toInt()] = value
i += 2
}
return bytes
}
}

View File

@ -15,7 +15,23 @@ fun before30Min(date: Date): Long {
return cal.timeInMillis return cal.timeInMillis
} }
fun beforeDay(date: Date?, day: Int): Long { fun beforeOneDay(): Long {
val cal: Calendar = Calendar.getInstance()
cal.setTime(Date())
// cal.add(Calendar.DAY_OF_YEAR, -1)
cal.add(Calendar.HOUR_OF_DAY, -4)
return cal.timeInMillis
}
fun beforeDay(day: Int): Long {
val cal: Calendar = Calendar.getInstance()
cal.setTime(Date())
cal.add(Calendar.DAY_OF_YEAR, Math.abs(day) * -1)
return cal.timeInMillis
}
fun beforeDayBy(date : Date, day: Int): Long {
val cal: Calendar = Calendar.getInstance() val cal: Calendar = Calendar.getInstance()
cal.setTime(date) cal.setTime(date)
cal.add(Calendar.DAY_OF_YEAR, Math.abs(day) * -1) cal.add(Calendar.DAY_OF_YEAR, Math.abs(day) * -1)

View File

@ -414,7 +414,6 @@ class GestureAnalyser @JvmOverloads constructor(
} }
} }
///https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w/getUpdates
class SimpleFingerGestures : OnTouchListener { class SimpleFingerGestures : OnTouchListener {
private var debug = BuildConfig.DEBUG private var debug = BuildConfig.DEBUG
@ -537,28 +536,28 @@ class SimpleFingerGestures : OnTouchListener {
1, 1,
mGt.gestureDuration, mGt.gestureDuration,
mGt.gestureDistance mGt.gestureDistance
) ).apply { consumeTouchEvents = this }
GestureAnalyser.SWIPE_1_DOWN -> onFingerGestureListener!!.onSwipeDown( GestureAnalyser.SWIPE_1_DOWN -> onFingerGestureListener!!.onSwipeDown(
targetView, targetView,
1, 1,
mGt.gestureDuration, mGt.gestureDuration,
mGt.gestureDistance mGt.gestureDistance
) ).apply { consumeTouchEvents = this }
GestureAnalyser.SWIPE_1_LEFT -> onFingerGestureListener!!.onSwipeLeft( GestureAnalyser.SWIPE_1_LEFT -> onFingerGestureListener!!.onSwipeLeft(
targetView, targetView,
1, 1,
mGt.gestureDuration, mGt.gestureDuration,
mGt.gestureDistance mGt.gestureDistance
) ).apply { consumeTouchEvents = this }
GestureAnalyser.SWIPE_1_RIGHT -> onFingerGestureListener!!.onSwipeRight( GestureAnalyser.SWIPE_1_RIGHT -> onFingerGestureListener!!.onSwipeRight(
targetView, targetView,
1, 1,
mGt.gestureDuration, mGt.gestureDuration,
mGt.gestureDistance mGt.gestureDistance
) ).apply { consumeTouchEvents = this }
GestureAnalyser.SWIPE_2_UP -> onFingerGestureListener!!.onSwipeUp( GestureAnalyser.SWIPE_2_UP -> onFingerGestureListener!!.onSwipeUp(
targetView, targetView,

View File

@ -2,19 +2,21 @@ package bums.lunatic.launcher.workers
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.ResolveInfo import android.content.pm.ResolveInfo
import android.os.Build import android.os.Build
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import bums.lunatic.launcher.BuildConfig import bums.lunatic.launcher.BuildConfig
import bums.lunatic.launcher.LauncherActivity
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
import bums.lunatic.launcher.apps.AppDrawer.Companion.appName import bums.lunatic.launcher.apps.AppDrawer.Companion.appNamesPrefs
import bums.lunatic.launcher.apps.AppDrawer.Companion.getCategory
import bums.lunatic.launcher.apps.normalize
import bums.lunatic.launcher.model.AppInfo import bums.lunatic.launcher.model.AppInfo
import bums.lunatic.launcher.utils.AlphabetToChosungMap import bums.lunatic.launcher.utils.AlphabetToChosungMap
import bums.lunatic.launcher.utils.JamoUtils import bums.lunatic.launcher.utils.JamoUtils
import io.realm.kotlin.ext.query import io.realm.kotlin.ext.query
import java.text.Normalizer
import java.util.regex.Pattern
class AppInfoGetter : BaseGetter { class AppInfoGetter : BaseGetter {
companion object { companion object {
@ -61,4 +63,32 @@ class AppInfoGetter : BaseGetter {
} catch (e : Exception) {e.printStackTrace()} } catch (e : Exception) {e.printStackTrace()}
return Result.success() return Result.success()
} }
}
fun appName(resolver: ResolveInfo): String {
return resolver.loadLabel(lActivity?.packageManager!!).toString().apply {
appNamesPrefs?.edit()?.putString(resolver.activityInfo.packageName, this)?.apply()
}
}
fun getCategory(category : Int) : String {
return when(category) {
ApplicationInfo.CATEGORY_UNDEFINED -> "UNDEFINED"
ApplicationInfo.CATEGORY_GAME -> "GAME"
ApplicationInfo.CATEGORY_AUDIO -> "AUDIO"
ApplicationInfo.CATEGORY_VIDEO -> "VIDEO"
ApplicationInfo.CATEGORY_IMAGE -> "IMAGE"
ApplicationInfo.CATEGORY_SOCIAL -> "SOCIAL"
ApplicationInfo.CATEGORY_NEWS -> "NEWS"
ApplicationInfo.CATEGORY_MAPS -> "MAPS"
ApplicationInfo.CATEGORY_PRODUCTIVITY -> "PRODUCTIVITY"
ApplicationInfo.CATEGORY_ACCESSIBILITY -> "ACCESSIBILITY"
else -> {"UNKNOWN"}
}
}
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

@ -7,15 +7,14 @@ import bums.lunatic.launcher.model.RssDataInterface
import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.model.RssDataType
import bums.lunatic.launcher.model.getRssData import bums.lunatic.launcher.model.getRssData
import bums.lunatic.launcher.model.getT import bums.lunatic.launcher.model.getT
import bums.lunatic.launcher.utils.beforeDay import bums.lunatic.launcher.utils.beforeOneDay
import bums.lunatic.launcher.workers.WorkersDb.blockKeyword //import bums.lunatic.launcher.workers.WorkersDb.blockKeyword
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.util.Date
class ArcaGetter : BaseGetter { class ArcaGetter : BaseGetter {
companion object { companion object {
val TAG = "DCGetter" val TAG = "ArcaGetter"
} }
constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) { constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) {
@ -74,7 +73,7 @@ class ArcaGetter : BaseGetter {
var tumbnail = aracaLi.getElementsByTag("img").attr("src") var tumbnail = aracaLi.getElementsByTag("img").attr("src")
var link = "https://arca.live".plus(if(aracaLi.getElementsByClass("title hybrid-title").size > 0) aracaLi.getElementsByClass("title hybrid-title").get(0).attr("href") else if(aracaLi.getElementsByTag("a").size > 0) aracaLi.getElementsByTag("a").get(0).attr("href") else "") var link = "https://arca.live".plus(if(aracaLi.getElementsByClass("title hybrid-title").size > 0) aracaLi.getElementsByClass("title hybrid-title").get(0).attr("href") else if(aracaLi.getElementsByTag("a").size > 0) aracaLi.getElementsByTag("a").get(0).attr("href") else "")
if (title.length > 0 && link.length > 20) { if (title.length > 0 && link.length > 20) {
if(blockKeyword.filter { desc.contains(it) }.size == 0) { // if(blockKeyword.filter { desc.contains(it) }.size == 0) {
Arca().apply { Arca().apply {
this.link = link this.link = link
this.title = title this.title = title
@ -87,11 +86,11 @@ class ArcaGetter : BaseGetter {
this.dateTiem = dateTime this.dateTiem = dateTime
}.apply { }.apply {
// BLog.LOGE("parseArcaLi >>>> ${this}") // BLog.LOGE("parseArcaLi >>>> ${this}")
if (this.pubDate() > beforeDay(Date(), 3)) { if (this.pubDate() > beforeOneDay()) {
tempArray.add(this) tempArray.add(this)
} }
} }
} // }
} }
return tempArray return tempArray
} }

View File

@ -0,0 +1,46 @@
package bums.lunatic.launcher.workers
import android.Manifest
import android.app.Service
import android.content.Intent
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioRecord
import android.media.MediaRecorder
import android.os.IBinder
import androidx.annotation.RequiresPermission
class AudioRecordService : Service() {
override fun onBind(intent: Intent?): IBinder? {
TODO("Not yet implemented")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
var sampleRate: Int = 44100 // 샘플링 레이트 (Hz)
var channelConfig: Int = AudioFormat.CHANNEL_IN_MONO // 채널 구성 (모노)
var audioFormat: Int = AudioFormat.ENCODING_PCM_16BIT // 오디오 포맷 (16비트 PCM)
var bufferSize: Int = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat)
var recorder: AudioRecord? = null
@RequiresPermission(Manifest.permission.RECORD_AUDIO)
fun startAudioRec() {
recorder = AudioRecord(
MediaRecorder.AudioSource.MIC,
sampleRate,
channelConfig,
audioFormat,
bufferSize
)
recorder?.registerAudioRecordingCallback({},object : AudioManager.AudioRecordingCallback() {
})
}
}

View File

@ -6,6 +6,7 @@ import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import bums.lunatic.launcher.model.RssData import bums.lunatic.launcher.model.RssData
import bums.lunatic.launcher.utils.beforeDay import bums.lunatic.launcher.utils.beforeDay
import bums.lunatic.launcher.utils.beforeOneDay
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
@ -22,9 +23,9 @@ open abstract class BaseGetter : Worker {
} }
val USAGT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15" val USAGT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15"
val now = Date()
val limitDateTime = beforeDay(now,3) val limitDateTime = beforeOneDay()
val commicsDateTime = beforeDay(now,1) val commicsDateTime = beforeDay(1)
val temp = arrayListOf<RssData>() val temp = arrayListOf<RssData>()
constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) { constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) {

View File

@ -33,6 +33,9 @@ class ClienGetter : BaseGetter {
Clien().let { c -> Clien().let { c ->
c.title = title c.title = title
c.link = "https://www.clien.net".plus(link) c.link = "https://www.clien.net".plus(link)
if (c.link?.contains("?") == true) {
try { c.link = c.link?.split("?")?.first() }catch (e : Exception) {}
}
c.desc = desc c.desc = desc
c.dateTiem = timeStamp c.dateTiem = timeStamp
if (c.pubDate() > limitDateTime) { if (c.pubDate() > limitDateTime) {

View File

@ -2,13 +2,17 @@ package bums.lunatic.launcher.workers
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import androidx.core.net.toUri
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import bums.lunatic.launcher.helpers.PrefHelper
import bums.lunatic.launcher.model.DcInside import bums.lunatic.launcher.model.DcInside
import bums.lunatic.launcher.model.RssData import bums.lunatic.launcher.model.RssData
import bums.lunatic.launcher.model.RssDataInterface import bums.lunatic.launcher.model.RssDataInterface
import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.model.RssDataType
import bums.lunatic.launcher.model.getRssData import bums.lunatic.launcher.model.getRssData
import bums.lunatic.launcher.utils.Blog
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.text.SimpleDateFormat
class DCGetter : BaseGetter { class DCGetter : BaseGetter {
companion object { companion object {
@ -20,6 +24,9 @@ class DCGetter : BaseGetter {
fun parseDcLi(dc_li : org.jsoup.nodes.Element) : ArrayList<RssDataInterface>{ fun parseDcLi(dc_li : org.jsoup.nodes.Element) : ArrayList<RssDataInterface>{
var temp = arrayListOf<RssDataInterface>() var temp = arrayListOf<RssDataInterface>()
if (dc_li.html().contains("<ul class=>") && dc_li.html().contains("con_list img")) { if (dc_li.html().contains("<ul class=>") && dc_li.html().contains("con_list img")) {
}
else if (dc_li.html().contains("<ul class=>") && dc_li.html().contains("con_list img")) {
dc_li.child(0).getElementsByTag("li").forEach { dc_li.child(0).getElementsByTag("li").forEach {
parseDcLi(it) parseDcLi(it)
} }
@ -64,31 +71,93 @@ class DCGetter : BaseGetter {
} }
return temp return temp
} }
val df = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
override fun realWork(): Result { override fun realWork(): Result {
// Blog.LOGE("${TAG} RssDataType.DCINSIDE.isOn >>>> ${PrefHelper.getBoolean(RssDataType.DCINSIDE.name,false)}")
RssDataType.DCINSIDE.isOn { RssDataType.DCINSIDE.isOn {
temp.clear() temp.clear()
// https://m.dcinside.com/board/singlebungle1472
var urls = arrayListOf(
"https://m.dcinside.com",
"https://m.dcinside.com/board/singlebungle1472",
"https://m.dcinside.com/board/programming",
"https://m.dcinside.com/board/cartoon",
"https://m.dcinside.com/board/reading",
"https://m.dcinside.com/board/hit",
"https://m.dcinside.com/board/dcbest"
)
try { try {
val testUrl2 = "https://www.dcinside.com/" urls.forEach { testUrl2 ->
Jsoup.connect(testUrl2) try {
.userAgent(USAGT) // Blog.LOGE("${TAG} ${testUrl2} ")
.get().let { dc -> Jsoup.connect(testUrl2)
// BLog.LOGE("test ${testUrl2} >> ${this}") .userAgent(USAGT)
dc.getElementsByTag("li").forEach { dc_li -> .get().let { dc ->
if (dc_li.html().contains("main_log") == true) { // Blog.LOGE("${TAG} ${testUrl2} >> ${this}")
parseDcLi(dc_li).apply { var tbody = dc.getElementsByTag("tbody")
this.forEach {
if (it.pubDate() > commicsDateTime) {
temp.add(it.getRssData()) if((tbody?.size ?: 0) == 1) {
var from = dc.getElementsByClass("page_head clear")?.first()?.getElementsByTag("a")?.first()?.text()
// Blog.LOGE("${TAG} ${from} ")
dc.getElementsByTag("tbody").first().children().forEach {
var title = it.getElementsByClass("gall_tit ub-word")?.first()?.text()
var date = it.getElementsByClass("gall_date")?.first()?.attr("title")
var link = it.getElementsByTag("a")?.first()?.attr("href")
if (link?.length ?: 0 > 10 && title?.length ?: 0 > 2 && date?.length ?: 0 > 1) {
// Blog.LOGE("${TAG} ${title} ")
// Blog.LOGE("${TAG} ${date} ${df.parse(date)}")
// Blog.LOGE("${TAG} ${link} ")
DcInside().apply {
"https://gall.dcinside.com".plus(
link?.replace(
"&amp;",
"&"
)
)?.toUri()?.apply {
link = "https://m.dcinside.com/board/".plus(getQueryParameter("id")).plus("/").plus(getQueryParameter("no"))
}
// this.link = "https://gall.dcinside.com".plus(
// link?.replace(
// "&amp;",
// "&"
// )
// )
this.link = link
// Blog.LOGE("${TAG} ${link} ")
// Blog.LOGE("${TAG} ${from} ")
this.title = title
this.desc = from
this.dateTiemL = df.parse(date).time
}.apply {
if (this.pubDate() > limitDateTime) {
temp.add(this.getRssData())
}
}
}
}
} else {
dc.getElementsByTag("li").forEach { dc_li ->
if (dc_li.html().contains("main_log") == true) {
parseDcLi(dc_li).apply {
this.forEach {
if (it.pubDate() > commicsDateTime) {
// Blog.LOGE("${TAG} ${it.title()}")
temp.add(it.getRssData())
}
}
}
} }
} }
} }
} }
} }catch (e :Exception){e.printStackTrace()}
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }

View File

@ -6,6 +6,7 @@ import androidx.work.WorkerParameters
import bums.lunatic.launcher.model.FmKorea import bums.lunatic.launcher.model.FmKorea
import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.model.RssDataType
import bums.lunatic.launcher.model.getRssData import bums.lunatic.launcher.model.getRssData
import bums.lunatic.launcher.utils.Blog
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.util.Date import java.util.Date
@ -17,47 +18,78 @@ class FmKoreaGetter : BaseGetter {
} }
fun extractDocumentSrl(url: String): String? {
val uri = java.net.URI(url)
val query = uri.query ?: return null // 쿼리 문자열이 없으면 null 반환
val params = query.split("&")
for (param in params) {
val parts = param.split("=")
if (parts.size == 2 && parts[0] == "document_srl") {
return "${uri.scheme}://${uri.host}${uri.path}?document_srl=${parts[1]}"
}
}
return null // document_srl 파라미터를 찾지 못하면 null 반환
}
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
override fun realWork(): Result { override fun realWork(): Result {
RssDataType.FMKORAE.isOn { RssDataType.FMKORAE.isOn {
val now = Date() val now = Date()
try { try {
val fmkoreaUrls = arrayListOf("https://www.fmkorea.com/best","https://www.fmkorea.com/best2") val fmkoreaUrls = arrayListOf("https://m.fmkorea.com","https://m.fmkorea.com/best","https://m.fmkorea.com/best2")
fmkoreaUrls.forEach { fmkoreaUrls.forEach {
Jsoup.connect(it).userAgent(USAGT).get().let { fmkorea -> try {
// BLog.LOGE("fmkorea >>> ${fmkorea.title()}") Jsoup.connect(it).userAgent(USAGT).timeout(5000).ignoreHttpErrors(true).get().let { fmkorea ->
fmkorea.getElementsByTag("li").forEach { fmkorea_li -> if (it.contains("guru")) {
if (fmkorea_li.getElementsByClass("title") // Blog.LOGE("GURU -> ${fmkorea}")
.text().length > 0 && fmkorea_li.getElementsByTag("a").size > 0 && fmkorea_li.getElementsByTag( } else {
"a" fmkorea.getElementsByTag("li").forEach { fmkorea_li ->
).get(0).attr("href").length > 0 if (fmkorea_li.getElementsByClass("title")
) { .text().length > 0 && fmkorea_li.getElementsByTag("a").size > 0 && fmkorea_li.getElementsByTag(
// BLog.LOGE("fmkorea_li >>> ${fmkorea_li}") "a"
val title = fmkorea_li.getElementsByClass("title").text() ).get(0).attr("href").length > 0
val tumb = "https://".plus(
fmkorea_li.getElementsByClass("thumb").attr("data-original")
)
val pageUrl = "https://www.fmkorea.com".plus(
fmkorea_li.getElementsByTag("a").get(0).attr("href")
)
val desc = fmkorea_li.getElementsByClass("category").text()
val date = fmkorea_li.getElementsByClass("regdate").text()
FmKorea(pageUrl, desc, date, title, tumb).apply {
if (desc?.contains("유머") == true || desc?.contains("음악") == true || desc?.contains(
"영화"
) == true ||
desc?.contains("TV") == true || desc?.contains("미스터리") == true || desc?.contains(
"역사"
) == true
) { ) {
if (this.pubDate() > commicsDateTime && tumb.length > 10) { val title = fmkorea_li.getElementsByClass("title").text()
temp.add(this.getRssData()) val tumb = "https://".plus(
fmkorea_li.getElementsByClass("thumb")
.attr("data-original")
)
var pageUrl = "https://www.fmkorea.com".plus(
fmkorea_li.getElementsByTag("a").get(0).attr("href")
)
try {
val originalUrl = pageUrl
val extractedUrl = extractDocumentSrl(originalUrl)
if (extractedUrl != null) {
pageUrl = extractedUrl
} else {
}
} catch (e: Exception) {}
val desc = fmkorea_li.getElementsByClass("category").text()
val date = fmkorea_li.getElementsByClass("regdate").text()
FmKorea(pageUrl, desc, date, title, tumb).apply {
if (desc?.contains("유머") == true || desc?.contains("음악") == true || desc?.contains(
"영화"
) == true ||
desc?.contains("TV") == true || desc?.contains("미스터리") == true || desc?.contains(
"역사"
) == true
) {
if (this.pubDate() > commicsDateTime && tumb.length > 10) {
temp.add(this.getRssData())
}
}
} }
} }
} }
} }
} }
}catch (e:Exception){
e.printStackTrace()
} }
} }
} catch (e: Exception) { } catch (e: Exception) {

View File

@ -152,6 +152,7 @@ class LocationUpdateService : Service(), LocationListener {
try{ try{
locationManager = applicationContext locationManager = applicationContext
.getSystemService(LOCATION_SERVICE) as LocationManager .getSystemService(LOCATION_SERVICE) as LocationManager
checkGPS = locationManager!! checkGPS = locationManager!!
.isProviderEnabled(LocationManager.GPS_PROVIDER) .isProviderEnabled(LocationManager.GPS_PROVIDER)
checkNetwork = locationManager!! checkNetwork = locationManager!!

View File

@ -24,10 +24,10 @@ class NewsFeedsGetter : BaseGetter {
feddsUrls.addAll(RssList.getFeedUrls()) feddsUrls.addAll(RssList.getFeedUrls())
for (url in feddsUrls) { for (url in feddsUrls) {
for (it in RssFeedsParser.getFeeds(url)) { try {
if (it.pubDate() >= limitDateTime) { for (it in RssFeedsParser.getFeeds(url)) { if (it.pubDate() >= limitDateTime) { try {temp.add(it.getRssData())}catch (e : Exception) {e.printStackTrace()} } }
temp.add(it.getRssData()) }catch (e : Exception) {
} e.printStackTrace()
} }
} }

View File

@ -45,7 +45,7 @@ class OpenWeatherGetter(context: Context, workerParams: WorkerParameters) : Base
} }
fun getWeather(latitude: Double, longitude: Double) { fun getWeather(latitude: Double, longitude: Double) {
Blog.LOGE("into getWeather") Blog.LOGE("into getWeather ${PrefString.weatherApiKey.get()}")
///saved weatherForcast ///saved weatherForcast
Retrofit.Builder() Retrofit.Builder()
.baseUrl(URI_WEATHERAPI) .baseUrl(URI_WEATHERAPI)

View File

@ -60,7 +60,7 @@ class RecentCallGetter : BaseGetter {
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
override fun realWork(): Result { override fun realWork(): Result {
var dateParam = beforeDay(Date(),dayRange).toString() var dateParam = beforeDay(dayRange).toString()
var managedCursor = lActivity?.contentResolver?.query( var managedCursor = lActivity?.contentResolver?.query(
CallLog.Calls.CONTENT_URI, arrayOf( CallLog.Calls.CONTENT_URI, arrayOf(
CallLog.Calls.NUMBER, CallLog.Calls.NUMBER,

View File

@ -22,7 +22,6 @@ import java.io.BufferedReader
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.io.InputStreamReader import java.io.InputStreamReader
import java.util.Date
class RecentSmsGetter : BaseGetter { class RecentSmsGetter : BaseGetter {
companion object { companion object {
@ -38,7 +37,7 @@ class RecentSmsGetter : BaseGetter {
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
override fun realWork(): Result { override fun realWork(): Result {
var dateParam = beforeDay(Date(),dayRange).toString() var dateParam = beforeDay(dayRange).toString()
val managedCursor = lActivity?.contentResolver?.query( val managedCursor = lActivity?.contentResolver?.query(
Telephony.Sms.CONTENT_URI, arrayOf( Telephony.Sms.CONTENT_URI, arrayOf(
Telephony.Sms.THREAD_ID, Telephony.Sms.THREAD_ID,
@ -340,7 +339,7 @@ internal class MmsQueryHelper(
fun convertData(cursor: Cursor?) { fun convertData(cursor: Cursor?) {
cursor ?: return cursor ?: return
val dateTime = beforeDay(Date(), dayRange) val dateTime = beforeDay(dayRange)
cursor.use { cursor.use {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do {

View File

@ -7,6 +7,7 @@ import androidx.work.WorkerParameters
import bums.lunatic.launcher.model.RssDataType import bums.lunatic.launcher.model.RssDataType
import bums.lunatic.launcher.model.RuliWeb import bums.lunatic.launcher.model.RuliWeb
import bums.lunatic.launcher.model.getRssData import bums.lunatic.launcher.model.getRssData
import bums.lunatic.launcher.utils.Blog
import org.jsoup.Jsoup import org.jsoup.Jsoup
class RuliWebGetter : BaseGetter { class RuliWebGetter : BaseGetter {
@ -26,7 +27,9 @@ class RuliWebGetter : BaseGetter {
var dateTimeTxt = "" var dateTimeTxt = ""
if(ruli_tr.getElementsByTag("a").size > tagIdx) { if(ruli_tr.getElementsByTag("a").size > tagIdx) {
pageLink = aTags.get(tagIdx).attr("href").replace("&amp;","&") pageLink = aTags.get(tagIdx).attr("href").replace("&amp;","&")
thumbnailUrl = aTags.get(tagIdx).attr("style").split("(")[1].replace(");","") if(aTags.get(tagIdx).attr("style").split("(").size > 1) {
thumbnailUrl = aTags.get(tagIdx).attr("style").split("(")[1].replace(");", "")
}
} }
tagIdx = 1 tagIdx = 1
if(ruli_tr.getElementsByTag("a").size > tagIdx) { title = aTags.get(tagIdx).text() } if(ruli_tr.getElementsByTag("a").size > tagIdx) { title = aTags.get(tagIdx).text() }
@ -37,11 +40,11 @@ class RuliWebGetter : BaseGetter {
var timeClass = ruli_tr.getElementsByClass("time") var timeClass = ruli_tr.getElementsByClass("time")
if(timeClass.size > 0) { dateTimeTxt = timeClass.get(0).text() } if(timeClass.size > 0) { dateTimeTxt = timeClass.get(0).text() }
// BLog.LOGE("pageLink >>>> $pageLink ") // Blog.LOGE(TAG.plus("pageLink >>>> $pageLink "))
// BLog.LOGE("thumbnailUrl >>>> $thumbnailUrl ") // Blog.LOGE(TAG.plus("thumbnailUrl >>>> $thumbnailUrl "))
// BLog.LOGE("title >>>> $title ") // Blog.LOGE(TAG.plus("title >>>> $title "))
// BLog.LOGE("desc >>>> $desc ") // Blog.LOGE(TAG.plus("desc >>>> $desc "))
// BLog.LOGE("dateTimeTxt >>>> $dateTimeTxt ") // Blog.LOGE(TAG.plus("dateTimeTxt >>>> $dateTimeTxt "))
if (title.length > 0 && pageLink.length > 0) { if (title.length > 0 && pageLink.length > 0) {
RuliWeb().let { ru -> RuliWeb().let { ru ->
ru.title = title ru.title = title
@ -62,10 +65,10 @@ class RuliWebGetter : BaseGetter {
try { try {
val testUrl2 = arrayListOf("https://bbs.ruliweb.com/best/humor_only","https://bbs.ruliweb.com/best/humor_only/now?m=humor_only&t=default&page=2") val testUrl2 = arrayListOf("https://bbs.ruliweb.com/best/humor_only","https://bbs.ruliweb.com/best/humor_only/now?m=humor_only&t=default&page=2")
testUrl2.forEach { url -> testUrl2.forEach { url ->
Jsoup.connect(url) Jsoup.connect(url).timeout(5000).ignoreHttpErrors(true)
.userAgent(USAGT) .userAgent(USAGT)
.get().let { ruli -> .get().let { ruli ->
// BLog.LOGE("test ${testUrl2} >> ${ruli.title()}") // Blog.LOGE(TAG.plus("test ${testUrl2} >> ${ruli.title()}"))
ruli.getElementsByTag("tr").forEach { ruli_tr -> ruli.getElementsByTag("tr").forEach { ruli_tr ->
parseRuli(ruli_tr) parseRuli(ruli_tr)
} }

View File

@ -33,6 +33,11 @@ class TheQooGetter : BaseGetter {
TheQoo().let { tq -> TheQoo().let { tq ->
tq.title = title tq.title = title
tq.link = "https://theqoo.net".plus(pageLink) tq.link = "https://theqoo.net".plus(pageLink)
if (tq.link?.contains("?") == true) {
try {
tq.link = tq.link?.split("?")?.first()
}catch (e:Exception){}
}
tq.dateTiem = dateTime tq.dateTiem = dateTime
tq.desc = desc tq.desc = desc
if (tq.pubDate() > limitDateTime) { if (tq.pubDate() > limitDateTime) {

View File

@ -24,18 +24,22 @@ import bums.lunatic.launcher.model.TelegramChat
import bums.lunatic.launcher.model.TelegramData import bums.lunatic.launcher.model.TelegramData
import bums.lunatic.launcher.model.TelegramFrom import bums.lunatic.launcher.model.TelegramFrom
import bums.lunatic.launcher.model.TelegramMessage import bums.lunatic.launcher.model.TelegramMessage
import bums.lunatic.launcher.model.UserActionModel
import bums.lunatic.launcher.model.WeatherForcast import bums.lunatic.launcher.model.WeatherForcast
import bums.lunatic.launcher.utils.Blog import bums.lunatic.launcher.utils.Blog
import bums.lunatic.launcher.utils.JamoUtils import bums.lunatic.launcher.utils.JamoUtils
import bums.lunatic.launcher.utils.beforeDay import bums.lunatic.launcher.utils.beforeDay
import bums.lunatic.launcher.utils.beforeOneDay
import io.realm.kotlin.Realm import io.realm.kotlin.Realm
import io.realm.kotlin.RealmConfiguration import io.realm.kotlin.RealmConfiguration
import io.realm.kotlin.UpdatePolicy import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query import io.realm.kotlin.ext.query
import io.realm.kotlin.migration.AutomaticSchemaMigration import io.realm.kotlin.migration.AutomaticSchemaMigration
import io.realm.kotlin.query.RealmQuery import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.Sort
import io.realm.kotlin.types.BaseRealmObject import io.realm.kotlin.types.BaseRealmObject
import io.realm.kotlin.types.TypedRealmObject import io.realm.kotlin.types.TypedRealmObject
import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.regex.Pattern import java.util.regex.Pattern
@ -49,13 +53,23 @@ class CustMigration : AutomaticSchemaMigration {
} }
object WorkersDb { object WorkersDb {
fun recommendApps() {
val cal = Calendar.getInstance()
cal.time = Date()
val weekOfYear = cal.get(Calendar.WEEK_OF_YEAR)
val weekOfMonth = cal.get(Calendar.WEEK_OF_MONTH)
val dayOfWeek = cal.get(Calendar.DAY_OF_WEEK)
getRealm().apply {
// this.query<UserActionModel>().query("weekOfYear == $0 OR weekOfMonth == $1 OR dayOfWeek == $2").limit()
}
}
val clazz : Set<KClass<out BaseRealmObject>> = setOf(RssData::class, NotificationItem::class, AppInfo::class,SimpleContact::class, RecentCall::class, RecentSms::class, CurrentPlayItem::class, val clazz : Set<KClass<out BaseRealmObject>> = setOf(RssData::class, NotificationItem::class, AppInfo::class,SimpleContact::class, RecentCall::class, RecentSms::class, CurrentPlayItem::class,
TelegramBotUpdate::class, TelegramData::class, TelegramMessage::class, TelegramChat::class, BotCommandEentitie::class, TelegramFrom::class, TelegramBotUpdate::class, TelegramData::class, TelegramMessage::class, TelegramChat::class, BotCommandEentitie::class, TelegramFrom::class,
WeatherForcast::class, Location::class, Current::class, Forecast::class, Condition::class, Forecastday::class, Day::class, Astro::class, Hour::class, WeatherForcast::class, Location::class, Current::class, Forecast::class, Condition::class, Forecastday::class, Day::class, Astro::class, Hour::class,
LocationLog::class LocationLog::class
) )
//,UserActionModel::class
val schemaVersion : Long = BuildConfig.BuildDateTime val schemaVersion : Long = BuildConfig.BuildDateTime
@ -78,7 +92,9 @@ object WorkersDb {
getRealm().apply { getRealm().apply {
this.writeBlocking { this.writeBlocking {
try { try {
this.copyToRealm(rssData, UpdatePolicy.ERROR) if (query<RssData>("originPage == $0", rssData.originPage).find().isEmpty()) {
this.copyToRealm(rssData, UpdatePolicy.ERROR)
}
} catch (e : Exception) { } catch (e : Exception) {
} }
@ -86,18 +102,25 @@ object WorkersDb {
} }
} }
val blockKeyword = arrayListOf<String>("붕괴 스타레일","붕괴 스타일","트릭컬 RE:VIVE","원신","메이플스토리","") // val blockKeyword = arrayListOf<String>("붕괴 스타레일","붕괴 스타일","트릭컬 RE:VIVE","원신","메이플스토리","")
fun insertBulkData(rssDatas: Collection<RssData>) { fun insertBulkData(rssDatas: Collection<RssData>) {
rssDatas.forEach { rssDatas.forEach {
try { try {
getRealm().writeBlocking { getRealm().writeBlocking {
try { try {
val catfillters = arrayListOf<RssDataType>(RssDataType.THEQOO,RssDataType.RULIWEB,RssDataType.ARCA,RssDataType.CLIEN,RssDataType.FMKORAE,RssDataType.DOTAX,RssDataType.DCINSIDE) rssDatas.forEach { t ->
if(catfillters.contains(it.category()) && query<RssData>("chosung == $0",it.chosung).find().size == 0) { if (query<RssData>("originPage == $0", t.originPage).find().isEmpty()) {
this.copyToRealm(it, UpdatePolicy.ERROR) // val catfillters = arrayListOf<RssDataType>(RssDataType.THEQOO,RssDataType.RULIWEB,RssDataType.ARCA,RssDataType.CLIEN,RssDataType.FMKORAE,RssDataType.DOTAX,RssDataType.DCINSIDE)
} else { // if(catfillters.contains(it.category()) && query<RssData>("chosung == $0",it.chosung).find().size == 0) {
this.copyToRealm(it, UpdatePolicy.ERROR) this.copyToRealm(t, UpdatePolicy.ERROR)
// } else if(!catfillters.contains(it.category())){
// this.copyToRealm(it, UpdatePolicy.ERROR)
// } else {
//
// }
}
} }
} catch (e : Exception) { } catch (e : Exception) {
} }
@ -195,13 +218,18 @@ object WorkersDb {
} }
} }
fun getVotedRss() = getRealm().query<RssData>().query("vote == $0", true).distinct("originPage").distinct("title") fun getVotedRss() = getRealm().query<RssData>().query("vote == $0", true).distinct("originPage", "title")
fun getDeleteQuery( ) : RealmQuery<RssData>{
var rQ = getRealm().query<RssData>()
rQ.query("pubDate > $0", beforeDay(14)).query("vote == $0", true)
return rQ
}
fun getRssQuery(keyword: String?, fun getRssQuery(keyword: String?,
category: Collection<String>? = arrayListOf(), category: Collection<String>? = arrayListOf(),
noLimit: Boolean = false) : RealmQuery<RssData>{ noLimit: Boolean = false) : RealmQuery<RssData>{
var rQ = getRealm().query<RssData>() var rQ = getRealm().query<RssData>().sort("pubDate", Sort.DESCENDING)
if (!noLimit) rQ.query("pubDate > $0", beforeDay(Date(), 3)) if (!noLimit) rQ.query("pubDate > $0", beforeOneDay())
keyword?.isNotEmpty()?.letTrue { keyword?.isNotEmpty()?.letTrue {
if (JamoUtils.CHOSUNG.contains(keyword.split("")[0])) { if (JamoUtils.CHOSUNG.contains(keyword.split("")[0])) {
rQ = rQ.query("title CONTAINS $0 OR chosung CONTAINS $1 ", keyword, keyword) rQ = rQ.query("title CONTAINS $0 OR chosung CONTAINS $1 ", keyword, keyword)
@ -230,7 +258,7 @@ object WorkersDb {
if (keyword?.length ?: 0 == 0 && category?.size ?: 0 == 0) { if (keyword?.length ?: 0 == 0 && category?.size ?: 0 == 0) {
rQ = rQ.query("read < $0", 3).query("vote != $0", true) rQ = rQ.query("read < $0", 3).query("vote != $0", true)
} }
return rQ.distinct("originPage").distinct("title") return rQ.distinct("originPage", "title")
} }
} }

View File

@ -7,12 +7,6 @@
android:id="@+id/mainFragmentsContainer" android:id="@+id/mainFragmentsContainer"
android:fitsSystemWindows="true"> android:fitsSystemWindows="true">
<WebView
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/searcher_01"
android:layout_width="match_parent"
android:alpha="0"
android:layout_height="match_parent"/>
<androidx.fragment.app.FragmentContainerView <androidx.fragment.app.FragmentContainerView
android:id="@+id/home" android:id="@+id/home"
@ -20,19 +14,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent"/>
<!-- <FrameLayout-->
<!-- android:id="@+id/feeds"-->
<!-- android:visibility="gone"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent" >-->
<!-- </FrameLayout>-->
<FrameLayout
android:visibility="gone"
android:id="@+id/app_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
</FrameLayout> </FrameLayout>

View File

@ -7,306 +7,23 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/batteryProgress" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_layout_margin"
android:indeterminate="false"
android:visibility="gone"
style="@style/normal"
android:text="빠떼뤼 ~> 0%"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<bums.lunatic.launcher.view.DateTimeView
android:layout_margin="@dimen/default_layout_margin" android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/infoList"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="match_parent"
android:background="@drawable/base_bg" android:overScrollMode="never"
android:text="this is init sentence"
android:id="@+id/time"
android:visibility="gone"
android:gravity="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/batteryProgress"
tools:ignore="MissingConstraints" />
<ImageView
android:id="@+id/next_play"
android:src="@drawable/play_song"
app:layout_constraintRight_toRightOf="@id/time"
app:layout_constraintTop_toTopOf="@id/time"
app:layout_constraintBottom_toBottomOf="@id/time"
android:layout_width="wrap_content"
android:adjustViewBounds="true"
android:layout_margin="@dimen/default_layout_margin"
android:layout_height="40dp"/>
<bums.lunatic.launcher.view.CircleImageView
app:layout_constraintLeft_toLeftOf="@id/time"
app:layout_constraintTop_toTopOf="@id/time"
app:layout_constraintBottom_toBottomOf="@id/time"
android:layout_margin="@dimen/default_layout_margin"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:background="@null"
android:layout_width="wrap_content"
app:civ_border_width="1dp"
app:civ_border_color="#000000"
app:civ_label="택시"
android:visibility="gone"
android:layout_height="0dp"
android:src="@drawable/kakaot"
android:id="@+id/alchol_katalkT"/>
<!-- <com.google.android.material.textview.MaterialTextView-->
<!-- android:id="@+id/weather"-->
<!-- app:layout_goneMarginBottom="0dp"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:gravity="center"-->
<!-- android:maxLines="1"-->
<!-- android:textIsSelectable="false"-->
<!-- app:layout_constraintLeft_toLeftOf="parent"-->
<!-- app:layout_constraintRight_toRightOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@+id/time"-->
<!-- />-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/current_music"
app:layout_constraintTop_toBottomOf="@id/time"
app:layout_constraintLeft_toLeftOf="parent"
android:background="@drawable/base_bg"
android:layout_margin="@dimen/default_layout_margin"
app:layout_goneMarginTop="0dp"
app:layout_goneMarginBottom="0dp"
android:padding="@dimen/default_padding" android:padding="@dimen/default_padding"
android:visibility="gone" android:scrollbars="none"
app:layout_constraintRight_toRightOf="parent" android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="60dp">
<bums.lunatic.launcher.view.CircleImageView
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/album_art"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:layout_width="wrap_content"
android:layout_height="50dp"/>
<TextView
android:layout_margin="@dimen/default_layout_margin"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="@id/album_art"
app:layout_constraintRight_toLeftOf="@id/next_btn"
android:gravity="left"
style="@style/small"
android:lines="1"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:layout_width="0dp"
android:id="@+id/artist"
android:layout_height="wrap_content"/>
<TextView
android:layout_margin="@dimen/default_layout_margin"
app:layout_constraintTop_toBottomOf="@id/artist"
android:id="@+id/title"
android:gravity="left"
style="@style/small"
android:lines="1"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
app:layout_constraintBottom_toBottomOf="@id/album_art"
app:layout_constraintLeft_toRightOf="@id/album_art"
app:layout_constraintRight_toLeftOf="@id/next_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
<ImageView
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/next_btn"
android:src="@drawable/next_song"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:layout_width="wrap_content"
android:layout_height="40dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<include
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/weathers"
layout="@layout/weather_book"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/current_music"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/summaryChoose"
android:layout_width="0dp"
android:gravity="center"
android:background="@drawable/base_bg" android:background="@drawable/base_bg"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
android:orientation="horizontal"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
android:layout_height="40dp" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toBottomOf="@+id/weathers" app:layout_constraintBottom_toBottomOf="parent"
> />
<TextView
style="@style/normal"
android:id="@+id/missedCalls"
android:gravity="center"
android:textColor="@color/tabs"
android:text="통화 목록"
android:background="@null"
android:checked="true"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
style="@style/normal"
android:id="@+id/otherCheck"
android:gravity="center"
android:background="@null"
android:text="글타래"
android:textColor="@color/tabs"
android:checked="false"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
style="@style/normal"
android:id="@+id/recentSms"
android:gravity="center"
android:background="@null"
android:text="문자 내역"
android:textColor="@color/tabs"
android:checked="false"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
style="@style/normal"
android:id="@+id/notice"
android:gravity="center"
android:background="@null"
android:text="알림"
android:textColor="@color/tabs"
android:checked="false"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/summaryChoose"
app:layout_constraintBottom_toTopOf="@id/functionLayer"
>
<androidx.recyclerview.widget.RecyclerView
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/mainList"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
android:padding="@dimen/default_padding"
android:visibility="gone"
android:background="@drawable/base_bg"
android:scrollbars="none"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
<androidx.recyclerview.widget.RecyclerView
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/smsList"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
android:padding="@dimen/default_padding"
android:scrollbars="none"
android:visibility="gone"
android:background="@drawable/base_bg"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
<androidx.recyclerview.widget.RecyclerView
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/infoList"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
android:padding="@dimen/default_padding"
android:scrollbars="none"
android:visibility="gone"
android:background="@drawable/base_bg"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
<androidx.recyclerview.widget.RecyclerView
android:layout_margin="@dimen/default_layout_margin"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:id="@+id/notiList"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
android:padding="@dimen/default_padding"
android:scrollbars="none"
android:visibility="gone"
android:background="@drawable/base_bg"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
</RelativeLayout>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/functionLayer"
android:layout_width="@dimen/zero"
android:layout_height="40dp"
android:layout_marginTop="@dimen/default_layout_margin"
android:layout_marginBottom="@dimen/default_layout_margin"
android:background="@drawable/base_bg"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" >
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,340 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="@android:color/transparent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/batteryProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_layout_margin"
android:indeterminate="false"
android:visibility="gone"
style="@style/normal"
android:text="빠떼뤼 ~> 0%"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<bums.lunatic.launcher.view.DateTimeView
android:layout_margin="@dimen/default_layout_margin"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@drawable/base_bg"
android:text="this is init sentence"
android:id="@+id/time"
android:visibility="gone"
android:gravity="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/batteryProgress"
tools:ignore="MissingConstraints" />
<ImageView
android:id="@+id/next_play"
android:src="@drawable/play_song"
app:layout_constraintRight_toRightOf="@id/time"
app:layout_constraintTop_toTopOf="@id/time"
app:layout_constraintBottom_toBottomOf="@id/time"
android:layout_width="wrap_content"
android:adjustViewBounds="true"
android:layout_margin="@dimen/default_layout_margin"
android:layout_height="40dp"/>
<bums.lunatic.launcher.view.CircleImageView
app:layout_constraintLeft_toLeftOf="@id/time"
app:layout_constraintTop_toTopOf="@id/time"
app:layout_constraintBottom_toBottomOf="@id/time"
android:layout_margin="@dimen/default_layout_margin"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:background="@null"
android:layout_width="wrap_content"
app:civ_border_width="1dp"
app:civ_border_color="#000000"
app:civ_label="택시"
android:visibility="gone"
android:layout_height="0dp"
android:src="@drawable/kakaot"
android:id="@+id/alchol_katalkT"/>
<!-- <com.google.android.material.textview.MaterialTextView-->
<!-- android:id="@+id/weather"-->
<!-- app:layout_goneMarginBottom="0dp"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:gravity="center"-->
<!-- android:maxLines="1"-->
<!-- android:textIsSelectable="false"-->
<!-- app:layout_constraintLeft_toLeftOf="parent"-->
<!-- app:layout_constraintRight_toRightOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@+id/time"-->
<!-- />-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/current_music"
app:layout_constraintTop_toBottomOf="@id/time"
app:layout_constraintLeft_toLeftOf="parent"
android:background="@drawable/base_bg"
android:layout_margin="@dimen/default_layout_margin"
app:layout_goneMarginTop="0dp"
app:layout_goneMarginBottom="0dp"
android:padding="@dimen/default_padding"
android:visibility="gone"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="match_parent"
android:layout_height="60dp">
<bums.lunatic.launcher.view.CircleImageView
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/album_art"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:layout_width="wrap_content"
android:layout_height="50dp"/>
<TextView
android:layout_margin="@dimen/default_layout_margin"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="@id/album_art"
app:layout_constraintRight_toLeftOf="@id/next_btn"
android:gravity="left"
style="@style/small"
android:lines="1"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:layout_width="0dp"
android:id="@+id/artist"
android:layout_height="wrap_content"/>
<TextView
android:layout_margin="@dimen/default_layout_margin"
app:layout_constraintTop_toBottomOf="@id/artist"
android:id="@+id/title"
android:gravity="left"
style="@style/small"
android:lines="1"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
app:layout_constraintBottom_toBottomOf="@id/album_art"
app:layout_constraintLeft_toRightOf="@id/album_art"
app:layout_constraintRight_toLeftOf="@id/next_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
<ImageView
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/next_btn"
android:src="@drawable/next_song"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:layout_width="wrap_content"
android:layout_height="40dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<include
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/weathers"
layout="@layout/weather_book"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/current_music"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/summaryChoose"
android:layout_width="0dp"
android:gravity="center"
android:background="@drawable/base_bg"
app:layout_constraintLeft_toLeftOf="parent"
android:orientation="horizontal"
app:layout_constraintRight_toRightOf="parent"
android:layout_height="40dp"
app:layout_constraintTop_toBottomOf="@+id/weathers"
>
<TextView
style="@style/normal"
android:id="@+id/missedCalls"
android:gravity="center"
android:textColor="@color/tabs"
android:text="통화 목록"
android:background="@null"
android:checked="true"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
style="@style/normal"
android:id="@+id/otherCheck"
android:gravity="center"
android:background="@null"
android:text="글타래"
android:textColor="@color/tabs"
android:checked="false"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
style="@style/normal"
android:id="@+id/favApps"
android:gravity="center"
android:background="@null"
android:text="앱스"
android:textColor="@color/tabs"
android:checked="false"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
style="@style/normal"
android:id="@+id/recentSms"
android:gravity="center"
android:background="@null"
android:text="문자 내역"
android:textColor="@color/tabs"
android:checked="false"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
style="@style/normal"
android:id="@+id/notice"
android:gravity="center"
android:background="@null"
android:text="알림"
android:textColor="@color/tabs"
android:checked="false"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/summaryChoose"
app:layout_constraintBottom_toTopOf="@id/functionLayer"
>
<androidx.recyclerview.widget.RecyclerView
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/mainList"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
android:padding="@dimen/default_padding"
android:visibility="gone"
android:background="@drawable/base_bg"
android:scrollbars="none"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
<androidx.recyclerview.widget.RecyclerView
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/smsList"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
android:padding="@dimen/default_padding"
android:scrollbars="none"
android:visibility="gone"
android:background="@drawable/base_bg"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
<androidx.recyclerview.widget.RecyclerView
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/infoList"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
android:padding="@dimen/default_padding"
android:scrollbars="none"
android:visibility="gone"
android:background="@drawable/base_bg"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
<androidx.recyclerview.widget.RecyclerView
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/appsList"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
android:padding="@dimen/default_padding"
app:spanCount="3"
android:scrollbars="none"
android:visibility="gone"
android:background="@drawable/base_bg"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
<androidx.recyclerview.widget.RecyclerView
android:layout_margin="@dimen/default_layout_margin"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:id="@+id/notiList"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
android:padding="@dimen/default_padding"
android:scrollbars="none"
android:visibility="gone"
android:background="@drawable/base_bg"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
</RelativeLayout>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_margin="@dimen/default_layout_margin"
android:id="@+id/functionLayer"
android:layout_width="@dimen/zero"
android:layout_height="40dp"
android:layout_marginTop="@dimen/default_layout_margin"
android:layout_marginBottom="@dimen/default_layout_margin"
android:background="@drawable/base_bg"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" >
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<Button
android:id="@+id/selectImageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="이미지 선택" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<ImageView
android:id="@+id/originalImageView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="fitCenter" />
<ImageView
android:id="@+id/filteredImageView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="fitCenter" />
</LinearLayout>
</LinearLayout>

View File

@ -9,9 +9,11 @@ buildscript {
} }
plugins { plugins {
id ("com.android.application") version "8.2.2" apply false id ("com.android.application") version "8.10.1" apply false
id ("com.android.library") version "8.2.2" apply false id ("com.android.library") version "8.10.1" apply false
id ("io.realm.kotlin") version "2.0.0" apply false id ("io.realm.kotlin") version "2.0.0" apply false
id("org.jetbrains.kotlin.android") version "2.0.0" apply false
} }
tasks.register<Delete>("clean") { tasks.register<Delete>("clean") {

View File

@ -22,6 +22,5 @@ android.useAndroidX=true
# resources declared in the library itself and none from the library's dependencies, # resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library # thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true android.nonTransitiveRClass=true
android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=true android.nonFinalResIds=true
android.enableJetifier=true android.enableJetifier=true

View File

@ -38,9 +38,11 @@ dependencies {
implementation( "com.github.bumptech.glide:glide:4.11.0") implementation( "com.github.bumptech.glide:glide:4.11.0")
annotationProcessor ("com.github.bumptech.glide:compiler:4.11.0") annotationProcessor ("com.github.bumptech.glide:compiler:4.11.0")
// implementation fileTree(dir: 'libs', include: ['*.jar']) // implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation ("com.airbnb.android:lottie:5.2.0")
implementation ("androidx.annotation:annotation:1.9.1") implementation ("androidx.annotation:annotation:1.9.1")
implementation ("androidx.appcompat:appcompat:1.7.0") implementation ("androidx.appcompat:appcompat:1.7.0")
implementation ("com.google.android.material:material:1.12.0") implementation ("com.google.android.material:material:1.12.0")
// implementation ("org.apache.tika:tika-parsers:1.24")
// implementation ("com.nineoldandroids:library:2.4.0") // implementation ("com.nineoldandroids:library:2.4.0")
implementation ("androidx.core:core-ktx:1.15.0") implementation ("androidx.core:core-ktx:1.15.0")
implementation(project(":utils")) implementation(project(":utils"))

View File

@ -11,6 +11,7 @@ import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.StateListDrawable import android.graphics.drawable.StateListDrawable
import android.net.MailTo import android.net.MailTo
import android.net.Uri import android.net.Uri
import android.net.http.SslError
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
@ -36,8 +37,10 @@ import android.webkit.CookieSyncManager
import android.webkit.DownloadListener import android.webkit.DownloadListener
import android.webkit.GeolocationPermissions import android.webkit.GeolocationPermissions
import android.webkit.PermissionRequest import android.webkit.PermissionRequest
import android.webkit.SslErrorHandler
import android.webkit.ValueCallback import android.webkit.ValueCallback
import android.webkit.WebChromeClient import android.webkit.WebChromeClient
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse import android.webkit.WebResourceResponse
import android.webkit.WebSettings import android.webkit.WebSettings
@ -58,9 +61,13 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.lifecycle.ReportFragment.Companion.reportFragment
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kr.lunaticbum.awesomewebview.databinding.AwesomeWebViewBinding import kr.lunaticbum.awesomewebview.databinding.AwesomeWebViewBinding
import kr.lunaticbum.awesomewebview.enums.Position import kr.lunaticbum.awesomewebview.enums.Position
import kr.lunaticbum.awesomewebview.helpers.BitmapHelper import kr.lunaticbum.awesomewebview.helpers.BitmapHelper
@ -91,10 +98,13 @@ import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import kotlin.math.abs import kotlin.math.abs
import kotlin.random.Random
open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener, open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
Handler.Callback { Handler.Callback {
var loadWithIntent : Boolean = false
var mediaUrls = arrayListOf<String>()
protected var key: Int = 0 protected var key: Int = 0
protected var rtl: Boolean = false protected var rtl: Boolean = false
@ -253,7 +263,7 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
// protected var back: AppCompatImageButton? = null // protected var back: AppCompatImageButton? = null
// protected var forward: AppCompatImageButton? = null // protected var forward: AppCompatImageButton? = null
// protected var more: AppCompatImageButton? = null // protected var more: AppCompatImageButton? = null
protected var webView: WebView? = null protected var webView: VideoEnabledWebView? = null
protected var webChromeClient: WebChromeClient? = null protected var webChromeClient: WebChromeClient? = null
protected var webViewClient: WebViewClient? = null protected var webViewClient: WebViewClient? = null
// protected var gradient: View? = null // protected var gradient: View? = null
@ -546,7 +556,7 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
protected fun bindViews() { open fun bindViews() {
binding.toolbarContent.close.setOnClickListener(this) binding.toolbarContent.close.setOnClickListener(this)
binding.toolbarContent.back.setOnClickListener(this) binding.toolbarContent.back.setOnClickListener(this)
binding.toolbarContent.forward.setOnClickListener(this) binding.toolbarContent.forward.setOnClickListener(this)
@ -572,7 +582,7 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
fun fast() { fun fast() {
chechHandler.removeCallbacks(cancelSearch) chechHandler.removeCallbacks(cancelSearch)
chechHandler.postDelayed(cancelSearch, 6000L) chechHandler.postDelayed(cancelSearch, 90000L)
} }
fun registCancelSearch() { fun registCancelSearch() {
@ -791,8 +801,21 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
webView!!.setOnLongClickListener(OnLongClickListener { webView!!.setOnLongClickListener(OnLongClickListener {
val hitTestResult = webView!!.hitTestResult val hitTestResult = webView!!.hitTestResult
// 如果是图片类型或者是带有图片链接的类型
if (hitTestResult.type == HitTestResult.IMAGE_TYPE || LogUtil.e("hitTestResult.type >>> ${hitTestResult.type}")
LogUtil.e("hitTestResult.extra >>> ${hitTestResult.extra}")
LogUtil.e("hitTestResult >>> ${mediaUrls.size}")
if(hitTestResult.type==0) {
webView?.evaluateJavascript("document.documentElement.outerHTML",
object : ValueCallback<String> {
override fun onReceiveValue(value: String?) {
val html = value?.replace("\\u003C", "<")
onHtml(html, true)
}
})
}
else if (hitTestResult.type == HitTestResult.IMAGE_TYPE ||
hitTestResult.type == HitTestResult.SRC_IMAGE_ANCHOR_TYPE hitTestResult.type == HitTestResult.SRC_IMAGE_ANCHOR_TYPE
) { ) {
if (!showMenuSavePhoto) { if (!showMenuSavePhoto) {
@ -804,68 +827,73 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
val items = arrayOf( val items = arrayOf(
resources.getString(stringResSavePhoto) resources.getString(stringResSavePhoto)
) )
val url = hitTestResult.extra
if (webView?.url?.contains(".guru") == true) {
url?.split("/")?.last()?.let { last ->
var code = if(last.contains("_") && last.split("_")?.first()?.length ?: 0 > 2) {
last.split("_").first()
} else if(last.contains("-") && last.split("-")?.first()?.length ?: 0 > 2) {
last.split("-").first()
} else {
last
}
LogUtil.e("hitTestResult code >>> ${code}")
webView?.evaluateJavascript("try{GJI.onCode('${code}');}catch(e){console.log(e);}", {})
}
showBlock()
return@OnLongClickListener false
}
builder?.setItems( builder?.setItems(
items items
) { dialog, which -> ) { dialog, which ->
PermissionHelper.CheckPermissions( LogUtil.e("hitTestResult.extra >>> ${dialog} ,${which}")
this@AwesomeWebViewActivity, val url = hitTestResult.extra
object : CheckPermissionListener {
override fun onAllGranted(sync: Boolean) {
val url = hitTestResult.extra
// 下载图片到本地
CookieSyncManager.createInstance(this@AwesomeWebViewActivity)
CookieSyncManager.getInstance().sync()
val cookieManager =
CookieManager.getInstance()
val cookie =
cookieManager.getCookie(webView!!.url)
DownPicUtil.downPic(
url,
webView!!.settings.userAgentString,
webView!!.url,
cookie,
object : DownFinishListener {
override fun onDownFinish(path: String) {
if (showToastPhotoSavedOrFailed) {
Toast.makeText(
this@AwesomeWebViewActivity,
resources.getString(
stringResPhotoSavedTo
) + path,
Toast.LENGTH_LONG
).show()
}
// 最后通知图库更新
applicationContext.sendBroadcast(
Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
Uri.parse("file://$path")
)
)
}
override fun onError() { CookieSyncManager.createInstance(applicationContext)
if (showToastPhotoSavedOrFailed) { CookieSyncManager.getInstance().sync()
Toast.makeText( val cookieManager =
this@AwesomeWebViewActivity, CookieManager.getInstance()
resources.getString( val cookie =
stringResPhotoSaveFailed cookieManager.getCookie(webView!!.url)
), DownPicUtil.downPic(
Toast.LENGTH_LONG File(Environment.getExternalStorageDirectory(),"bums").path,
).show() url,
} webView!!.settings.userAgentString,
} webView!!.url,
}) cookie,
object : DownFinishListener {
override fun onDownFinish(url : String ,path: String) {
if (showToastPhotoSavedOrFailed) {
Toast.makeText(
applicationContext,
resources.getString(
stringResPhotoSavedTo
) + path,
Toast.LENGTH_LONG
).show()
}
// 最后通知图库更新
applicationContext.sendBroadcast(
Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
Uri.parse("file://$path")
)
)
} }
override fun onPartlyGranted( override fun onError() {
permissionsDenied: List<String>, if (showToastPhotoSavedOrFailed) {
sync: Boolean Toast.makeText(
) { applicationContext,
resources.getString(
stringResPhotoSaveFailed
),
Toast.LENGTH_LONG
).show()
}
} }
}, })
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
} }
val dialog = builder?.create() val dialog = builder?.create()
dialog?.show() dialog?.show()
@ -874,27 +902,27 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
false false
}) })
webView!!.setOnTouchListener(object : OnTouchListener { // webView!!.setOnTouchListener(object : OnTouchListener {
private var xDown = 0f // private var xDown = 0f
private var yDown = 0f // private var yDown = 0f
private var timeDown: Long = 0 // private var timeDown: Long = 0
override fun onTouch(v: View, event: MotionEvent): Boolean { // override fun onTouch(v: View, event: MotionEvent): Boolean {
if (v === webView && event.action == MotionEvent.ACTION_DOWN) { // if (v === webView && event.action == MotionEvent.ACTION_DOWN) {
xDown = event.x // xDown = event.x
yDown = event.y // yDown = event.y
timeDown = System.currentTimeMillis() // timeDown = System.currentTimeMillis()
} else if (v === webView && event.action == MotionEvent.ACTION_UP) { // } else if (v === webView && event.action == MotionEvent.ACTION_UP) {
if (abs((xDown - event.x).toDouble()) < 50 && abs( // if (abs((xDown - event.x).toDouble()) < 50 && abs(
(yDown - event.y).toDouble() // (yDown - event.y).toDouble()
) < 50 && System.currentTimeMillis() - timeDown < 200 // ) < 50 && System.currentTimeMillis() - timeDown < 200
) { // ) {
// https://stackoverflow.com/a/5125620 // // https://stackoverflow.com/a/5125620
handler.sendEmptyMessageDelayed(MSG_CLICK_ON_WEBVIEW, 500) // handler.sendEmptyMessageDelayed(MSG_CLICK_ON_WEBVIEW, 500)
} // }
} // }
return false // return false
} // }
}) // })
val settings = webView!!.settings val settings = webView!!.settings
@ -1239,7 +1267,31 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
} }
} }
protected fun buildWebView(): WebView { open protected fun onHtml(value: String?, autoCheck : Boolean) {
}
protected fun showBlock() {
binding.blocking.visibility = View.VISIBLE
val ress = arrayListOf(R.raw.dlottie_001,R.raw.lt_lodaing_01,R.raw.dlottie_003,R.raw.lt_lodaing_02,R.raw.lt_lodaing_03,R.raw.dlottie_002)
var isEven = ((System.currentTimeMillis() % 2).toInt() == 0)
var firstSeed = Random(if(isEven)8739 else 7531)
var randomSeed_01 = Math.abs(firstSeed.nextInt()) % if(isEven) 879 else 56
var randomSeed_02 = Math.abs(firstSeed.nextInt()) % if(!isEven) 758 else 397
var randomSeed_03 = Math.abs(firstSeed.nextInt()) % if(!isEven) 353 else 49
var totalSeed = Math.abs((Math.abs(randomSeed_01) * Math.abs(randomSeed_02)) + Math.abs(randomSeed_03))
var randomResult = Math.abs(totalSeed % ress.size)
LogUtil.e("randomResult >>> randomSeed_01 {${randomSeed_01}} | randomSeed_02 {${randomSeed_02}} | randomSeed_03 {${randomSeed_03}} | resSize {${ress.size}} | ${randomResult}")
binding.lotti.setAnimation(ress[Math.abs(randomResult)])
binding.lotti.playAnimation()
}
protected fun hideBlock() {
binding.blocking.visibility = View.GONE
binding.lotti.pauseAnimation()
}
protected fun buildWebView(): VideoEnabledWebView {
return VideoEnabledWebView(this) return VideoEnabledWebView(this)
} }
@ -1405,6 +1457,8 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
} }
} }
open protected var pdfListner : PDFPrint.OnPDFPrintListener? = null
override fun onClick(v: View) { override fun onClick(v: View) {
val viewId = v.id val viewId = v.id
if (viewId == R.id.close) { if (viewId == R.id.close) {
@ -1443,16 +1497,23 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
if (path.exists() == false) { if (path.exists() == false) {
path.mkdirs() path.mkdirs()
} }
val file = File(path, fileName)
PDFPrint.generatePDFFromWebView(file,webView,object :PDFPrint.OnPDFPrintListener {
override fun onSuccess(file: File?) {
LogUtil.e("file.absolutePath >>> ${file?.absolutePath ?: "fail"}")
}
override fun onError(exception: java.lang.Exception?) { val file = File(path, fileName)
exception?.printStackTrace() PDFPrint.generatePDFFromWebView(
file,
webView,
pdfListner ?: object : PDFPrint.OnPDFPrintListener {
override fun onSuccess(file: File?) {
LogUtil.e("file.absolutePath >>> ${file?.absolutePath ?: "fail"}")
}
override fun onError(exception: java.lang.Exception?) {
LogUtil.e("generatePDFFromWebView >>> fail")
exception?.printStackTrace()
}
} }
}) )
hideMenu() hideMenu()
} else if (viewId == R.id.menuFind) { } else if (viewId == R.id.menuFind) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) webView!!.showFindDialog( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) webView!!.showFindDialog(
@ -1849,6 +1910,7 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
return File.createTempFile(new_name, if (isVideo) ".mp4" else ".jpg", sd_directory) return File.createTempFile(new_name, if (isVideo) ".mp4" else ".jpg", sd_directory)
} }
var hasYoutubePlayer = false var hasYoutubePlayer = false
open fun webviewOnPageFinished(){} open fun webviewOnPageFinished(){}
inner class MyWebViewClient : WebViewClient() { inner class MyWebViewClient : WebViewClient() {
@ -1856,38 +1918,62 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
view: WebView, view: WebView,
request: WebResourceRequest request: WebResourceRequest
): WebResourceResponse? { ): WebResourceResponse? {
if (host?.contains("booktoki") == true) {
return super.shouldInterceptRequest(view, request)
}
var skipResource = var skipResource =
(host != null) && ((request.url?.host?.contains(host!!) ?: true) == false) (host != null) && ((request.url?.host?.contains(host!!) ?: true) == false)
if (skipResource && request.url.toString().contains("gif")) { if (skipResource && request.url.toString().contains("gif")) {
LogUtil.e("shouldInterceptRequest request block gif resource >>> ${request.url.toString()}")
return WebResourceResponse( return WebResourceResponse(
"text/plain", "utf-8", "text/plain", "utf-8",
ByteArrayInputStream("".toByteArray()) ByteArrayInputStream("".toByteArray())
) )
} }
val url = request.url.toString() val url = request.url.toString()
if (url.contains("streamable.com") ||
url.contains("img-cdn.theqoo") ||
url.contains("embed/player/") ||
url.contains("dcinside.co.kr/viewimage") ||
url.contains("daumcdn.net/cafeattach") ||
url.toLowerCase(Locale.ROOT).contains(".jpg") ||
url.toLowerCase(Locale.ROOT).contains(".png") ||
url.toLowerCase(Locale.ROOT).contains(".gif") ||
url.toLowerCase(Locale.ROOT).contains(".svg") ||
url.toLowerCase(Locale.ROOT).contains(".webp")) {
mediaUrls.add(url)
// LogUtil.e("mediaUrls >>>>> add(${url})")
}
if(!hasYoutubePlayer) { if(!hasYoutubePlayer) {
hasYoutubePlayer = url.toLowerCase(Locale.ROOT) hasYoutubePlayer = url.toLowerCase(Locale.ROOT)
.contains("https://www.youtube.com/s/player".toLowerCase(Locale.ROOT)) .contains("https://www.youtube.com/s/player".toLowerCase(Locale.ROOT))
} }
//https://t1.daumcdn.net/cafeattach/mEr9/adc6e81a386099c4cc06f77f8b7eea15675de0d4
if (url.toLowerCase(Locale.ROOT) if (url.toLowerCase(Locale.ROOT)
.contains("ads".toLowerCase(Locale.ROOT))) { .contains("ads".toLowerCase(Locale.ROOT))) {
LogUtil.e("shouldInterceptRequest request url contains ads >>> ${request.url.toString()}") // LogUtil.e("shouldInterceptRequest request url contains ads >>> ${request.url.toString()}")
} }
var callSupers = arrayListOf("google-analytics.com","analytics.google.com","api.dable.io")
var adblockKeyWords = arrayOf("adcr.naver.com","daumcdn.net/biz/ui/ad/adcm","imgad","ad.daum.net","cr.adsappier.com","ar-adview","adtrafficquality","criteo","adlib.nhnace.com","google.com/ads","googleads.","/pagead","/adpost/","ads/search","plugin.adplex") var adblockKeyWords = arrayOf("adcr.naver.com","daumcdn.net/biz/ui/ad/adcm","imgad","ad.daum.net","cr.adsappier.com","ar-adview","adtrafficquality","criteo","adlib.nhnace.com","google.com/ads","googleads.","/pagead","/adpost/","ads/search","plugin.adplex")
val supers = callSupers.filter { url.toLowerCase(Locale.ROOT).contains(it.toLowerCase(Locale.ROOT)) }.size > 0
val adblock = adblockKeyWords.filter { url.toLowerCase(Locale.ROOT).contains(it.toLowerCase(Locale.ROOT)) }.size > 0 val adblock = adblockKeyWords.filter { url.toLowerCase(Locale.ROOT).contains(it.toLowerCase(Locale.ROOT)) }.size > 0
return if(adblock) { return if(adblock) {
try { try {
LogUtil.e("shouldInterceptRequest request block adblockKeyWords resource >>> ${request.url.toString()}") // LogUtil.e("shouldInterceptRequest request block adblockKeyWords resource >>> ${request.url.toString()}")
WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray())) WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray()))
} catch (e : Exception) { } catch (e : Exception) {
super.shouldInterceptRequest(view, url) super.shouldInterceptRequest(view, url)
} }
}else if(url.toLowerCase(Locale.ROOT).contains(".jpg") || url.toLowerCase(Locale.ROOT).contains(".jpeg")){ } else if(supers) {
super.shouldInterceptRequest(view, url)
} else if(url.toLowerCase(Locale.ROOT).contains(".jpg") || url.toLowerCase(Locale.ROOT).contains(".jpeg")){
try { try {
val bitmap = Glide.with(this@AwesomeWebViewActivity).asBitmap().timeout(30000).diskCacheStrategy(DiskCacheStrategy.ALL).load(url).submit().get() val bitmap = Glide.with(this@AwesomeWebViewActivity).asBitmap().timeout(30000).diskCacheStrategy(DiskCacheStrategy.ALL).load(url).submit().get()
WebResourceResponse("image/jpg", "UTF-8",getBitmapInputStream(bitmap,Bitmap.CompressFormat.JPEG)).apply { WebResourceResponse("image/jpg", "UTF-8",getBitmapInputStream(bitmap,Bitmap.CompressFormat.JPEG)).apply {
LogUtil.e("shouldInterceptRequest request url down from Glide >>> ${request.url.toString()}") // LogUtil.e("shouldInterceptRequest request url down from Glide >>> ${request.url.toString()}")
} }
} catch (e : Exception) { } catch (e : Exception) {
super.shouldInterceptRequest(view, url) super.shouldInterceptRequest(view, url)
@ -1896,7 +1982,7 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
try { try {
val bitmap = Glide.with(this@AwesomeWebViewActivity).asBitmap().timeout(30000).diskCacheStrategy(DiskCacheStrategy.ALL).load(url).submit().get() val bitmap = Glide.with(this@AwesomeWebViewActivity).asBitmap().timeout(30000).diskCacheStrategy(DiskCacheStrategy.ALL).load(url).submit().get()
WebResourceResponse("image/png", "UTF-8",getBitmapInputStream(bitmap,Bitmap.CompressFormat.PNG)).apply { WebResourceResponse("image/png", "UTF-8",getBitmapInputStream(bitmap,Bitmap.CompressFormat.PNG)).apply {
LogUtil.e("shouldInterceptRequest request url down from Glide >>> ${request.url.toString()}") // LogUtil.e("shouldInterceptRequest request url down from Glide >>> ${request.url.toString()}")
} }
} catch (e : Exception) { } catch (e : Exception) {
super.shouldInterceptRequest(view, url) super.shouldInterceptRequest(view, url)
@ -1906,7 +1992,7 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
try { try {
val bitmap = Glide.with(this@AwesomeWebViewActivity).asBitmap().timeout(30000).diskCacheStrategy(DiskCacheStrategy.ALL).load(url).submit().get() val bitmap = Glide.with(this@AwesomeWebViewActivity).asBitmap().timeout(30000).diskCacheStrategy(DiskCacheStrategy.ALL).load(url).submit().get()
WebResourceResponse("image/webp", "UTF-8",getBitmapInputStream(bitmap,Bitmap.CompressFormat.WEBP)).apply { WebResourceResponse("image/webp", "UTF-8",getBitmapInputStream(bitmap,Bitmap.CompressFormat.WEBP)).apply {
LogUtil.e("shouldInterceptRequest request url down from Glide >>> ${request.url.toString()}") // LogUtil.e("shouldInterceptRequest request url down from Glide >>> ${request.url.toString()}")
} }
} catch (e : Exception) { } catch (e : Exception) {
super.shouldInterceptRequest(view, url) super.shouldInterceptRequest(view, url)
@ -1928,6 +2014,8 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
// } // }
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
mediaUrls.clear()
BroadCastManager.onPageStarted(this@AwesomeWebViewActivity, key, url) BroadCastManager.onPageStarted(this@AwesomeWebViewActivity, key, url)
if (!url.contains("docs.google.com") && url.endsWith(".pdf")) { if (!url.contains("docs.google.com") && url.endsWith(".pdf")) {
webView!!.loadUrl("http://docs.google.com/gview?embedded=true&url=$url") webView!!.loadUrl("http://docs.google.com/gview?embedded=true&url=$url")
@ -1951,7 +2039,9 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
BroadCastManager.onPageFinished(this@AwesomeWebViewActivity, key, url) BroadCastManager.onPageFinished(this@AwesomeWebViewActivity, key, url)
if (updateTitleFromHtml) binding.toolbarContent.title.text = view.title if (updateTitleFromHtml) binding.toolbarContent.title.text = view.title
binding.toolbarContent.url.text = UrlParser.getHost(url) try {
binding.toolbarContent.url.text = UrlParser.getHost(url)
}catch (e :Exception) {e.printStackTrace()}
requestCenterLayout() requestCenterLayout()
if (view.canGoBack() || view.canGoForward()) { if (view.canGoBack() || view.canGoForward()) {
@ -1980,11 +2070,23 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
registCancelSearch() registCancelSearch()
} }
@Deprecated("Deprecated in Java")
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
handler.sendEmptyMessage(MSG_CLICK_ON_URL) handler.sendEmptyMessage(MSG_CLICK_ON_URL)
if (url.contains("booktoki")) {
return false
}
if (url.contains("http:")) {
var newUrl = url.replace("http:","https:")
LogUtil.e("is StartWith ${url} , ${newUrl}")
if (newUrl.length > 10) {
view.stopLoading()
view.loadUrl(newUrl)
}
return true
}
var skipResource = host!= null && ((url.contains(host!!) ?: true) == false) && (host!!.contains("google") == false) var skipResource = host!= null && ((url.contains(host!!) ?: true) == false) && (host!!.contains("google") == false)
if (skipResource) { if (skipResource || loadWithIntent) {
LogUtil.e("shouldOverrideUrlLoading block url $url , host >>>> $host ") LogUtil.e("shouldOverrideUrlLoading block url $url , host >>>> $host ")
val alertDialog = AlertDialog.Builder(view.context).create() val alertDialog = AlertDialog.Builder(view.context).create()
alertDialog.setCancelable(false) alertDialog.setCancelable(false)
@ -2071,6 +2173,22 @@ open class AwesomeWebViewActivity : AppCompatActivity(), View.OnClickListener,
override fun onPageCommitVisible(view: WebView, url: String) { override fun onPageCommitVisible(view: WebView, url: String) {
BroadCastManager.onPageCommitVisible(this@AwesomeWebViewActivity, key, url) BroadCastManager.onPageCommitVisible(this@AwesomeWebViewActivity, key, url)
} }
override fun onReceivedError(
view: WebView?,
request: WebResourceRequest?,
error: WebResourceError?
) {
super.onReceivedError(view, request, error)
}
override fun onReceivedSslError(
view: WebView?,
handler: SslErrorHandler?,
error: SslError?
) {
handler?.proceed()
}
} }
protected fun parsePermission(resource: Array<String>): Array<String?> { protected fun parsePermission(resource: Array<String>): Array<String?> {

View File

@ -4,9 +4,16 @@ package kr.lunaticbum.awesomewebview.helpers;
* Created by wuzongheng on 2018/2/18. * Created by wuzongheng on 2018/2/18.
*/ */
import static java.sql.DriverManager.println;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Environment; import android.os.Environment;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
@ -17,6 +24,11 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import kr.lunaticbum.utils.log.LogUtil;
/** /**
* 图片下载的工具类 * 图片下载的工具类
@ -28,37 +40,86 @@ public class DownPicUtil {
* @param url * @param url
*/ */
public static void downPic(String url, DownFinishListener downFinishListener){ public static void downPic(String url, DownFinishListener downFinishListener){
downPic(url, null, null, null, downFinishListener); downPic(null, url, null, null, null, downFinishListener);
} }
/** /**
* Download the pic * Download the pic
* @param url * @param url
*/ */
public static void downPic(String url, String userAgent, String referer, String cookie, DownFinishListener downFinishListener){ public static void downPic(String path , String url, String userAgent, String referer, String cookie, DownFinishListener downFinishListener){
// 获取存储卡的目录 if(path == null) {
String filePath = Environment.getExternalStorageDirectory().getPath(); String filePath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filePath + File.separator + Environment.DIRECTORY_DOWNLOADS); File file = new File(filePath + File.separator + Environment.DIRECTORY_DOWNLOADS);
if(!file.exists()){ if (!file.exists()) {
file.mkdirs(); file.mkdirs();
}
loadPic(file.getPath(), url, userAgent, referer, cookie, downFinishListener, false);
} else {
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
loadPic(path, url, userAgent, referer, cookie, downFinishListener, false);
} }
loadPic(file.getPath(), url, userAgent, referer, cookie, downFinishListener);
} }
private static void loadPic(final String filePath, final String url, final String userAgent, final String referer, final String cookie, final DownFinishListener downFinishListener) { public static void downMp4(String path , String url, String userAgent, String referer, String cookie, DownFinishListener downFinishListener){
if(path == null) {
String filePath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filePath + File.separator + Environment.DIRECTORY_DOWNLOADS);
if (!file.exists()) {
file.mkdirs();
}
loadPic(file.getPath(), url, userAgent, referer, cookie, downFinishListener, true);
} else {
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
loadPic(path, url, userAgent, referer, cookie, downFinishListener, true);
}
}
public static String toHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static byte[] hashString(String str, String algorithm) {
try {
MessageDigest digest = MessageDigest.getInstance(algorithm);
return digest.digest(str.getBytes(StandardCharsets.UTF_8));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
private static void loadPic(final String filePath, final String url, final String userAgent, final String referer, final String cookie, final DownFinishListener downFinishListener, boolean isMp4) {
new AsyncTask<Void,Void,String>(){ new AsyncTask<Void,Void,String>(){
String fileName; String fileName;
InputStream is; InputStream is;
OutputStream out; OutputStream out;
private String replaceDcUrl(String origin) {
String result = origin;
for (int i = 0; i < 20; i++) {
result = result.replace(String.format("dcimg%d.",i),"dcimg2.");
}
return result;
}
@Override @Override
protected String doInBackground(Void... voids) { protected String doInBackground(Void... voids) {
// 原文件名 // 原文件名
String[] split = url.split("/"); String[] split = url.split("/");
fileName = split[split.length - 1]; byte[] dd = hashString(url, "MD5");
fileName = dd == null ? split[split.length - 1] : toHex(dd);
// 创建目标文件使用时间戳作为临时文件名确保可以不重复 // 创建目标文件使用时间戳作为临时文件名确保可以不重复
String now = String.valueOf(System.currentTimeMillis()); String now = String.valueOf(System.currentTimeMillis());
@ -72,7 +133,13 @@ public class DownPicUtil {
byte[] image = base64ImgHelper.decode(); byte[] image = base64ImgHelper.decode();
is = new ByteArrayInputStream(image); //处理服务器的响应结果 is = new ByteArrayInputStream(image); //处理服务器的响应结果
} else { } else {
URL picUrl = new URL(url); URL picUrl = null;
if (url.contains("dcimg")) {
picUrl = new URL(replaceDcUrl(url));
} else {
picUrl = new URL(url);
}
//通过图片的链接打开输入流 //通过图片的链接打开输入流
HttpURLConnection httpURLConnection = (HttpURLConnection) picUrl.openConnection(); HttpURLConnection httpURLConnection = (HttpURLConnection) picUrl.openConnection();
httpURLConnection.setConnectTimeout(10000); //设置连接超时时间 httpURLConnection.setConnectTimeout(10000); //设置连接超时时间
@ -81,13 +148,26 @@ public class DownPicUtil {
httpURLConnection.setDoOutput(false); //Get请求不需要DoOutPut httpURLConnection.setDoOutput(false); //Get请求不需要DoOutPut
httpURLConnection.setRequestMethod("GET"); //设置以Get方式请求数据 httpURLConnection.setRequestMethod("GET"); //设置以Get方式请求数据
httpURLConnection.setUseCaches(false); //不使用缓存 httpURLConnection.setUseCaches(false); //不使用缓存
//设置请求体的类型是文本类型 //设置请求体的类型是文本类型
// if (url.contains("dcimg")) {
//// httpURLConnection.setRequestProperty("authority", Uri.parse(url).getHost());
// httpURLConnection.setRequestProperty("Accept", "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8");
// httpURLConnection.setRequestProperty("Accept-encoding", "gzip, deflate, br, zstd");
// httpURLConnection.setRequestProperty("Sec-Fetch-Dest","image");
// httpURLConnection.setRequestProperty("Sec-Fetch-Mode","no-cors");
// httpURLConnection.setRequestProperty("Sec-Fetch-Site","cross-site");
// }
httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
if (!TextUtils.isEmpty(userAgent)) { if (!TextUtils.isEmpty(userAgent)) {
httpURLConnection.setRequestProperty("User-Agent", userAgent); httpURLConnection.setRequestProperty("User-Agent", userAgent);
} }
if (!TextUtils.isEmpty(referer)) { if (!TextUtils.isEmpty(referer)) {
httpURLConnection.setRequestProperty("Referer", referer); httpURLConnection.setRequestProperty("Referer", referer);
println("referer>>>> " + referer);
} }
if (!TextUtils.isEmpty(cookie)) { if (!TextUtils.isEmpty(cookie)) {
httpURLConnection.setRequestProperty("Cookie", cookie); httpURLConnection.setRequestProperty("Cookie", cookie);
@ -140,6 +220,9 @@ public class DownPicUtil {
} else { } else {
newFileNameNoExtension = fileName; newFileNameNoExtension = fileName;
} }
if (isVideoFileByMetadata(picFile) && extension == null && isMp4) {
extension = "mp4";
}
// 重命名文件 // 重命名文件
if (extension == null) { if (extension == null) {
@ -151,21 +234,24 @@ public class DownPicUtil {
// 无拓展名整个文件名递增重命名 // 无拓展名整个文件名递增重命名
return renamePic(picFile, filePath, newFileNameNoExtension, null, MODE.MODE_INCREMENT); return renamePic(picFile, filePath, newFileNameNoExtension, null, MODE.MODE_INCREMENT);
} }
} else {
return renamePic(picFile, filePath, newFileNameNoExtension, extension, MODE.MODE_IGNORE);
} }
// 支持解析的格式使用md5文件名真实拓展名 // 支持解析的格式使用md5文件名真实拓展名
String md5 = Md5Helper.getFileMD5ToString(picFile); // return picFile.getPath();
if (TextUtils.isEmpty(md5)) { // String md5 = Md5Helper.getFileMD5ToString(picFile);
return renamePic(picFile, filePath, newFileNameNoExtension, extension, MODE.MODE_INCREMENT); // if (TextUtils.isEmpty(md5)) {
} else { // return renamePic(picFile, filePath, newFileNameNoExtension, extension, MODE.MODE_INCREMENT);
return renamePic(picFile, filePath, md5.substring(0, 16), extension, MODE.MODE_IGNORE); // } else {
} // return renamePic(picFile, filePath, md5.substring(0, 16), extension, MODE.MODE_IGNORE);
// }
} }
@Override @Override
protected void onPostExecute(String path) { protected void onPostExecute(String path) {
super.onPostExecute(path); super.onPostExecute(path);
if(path!=null){ if(path!=null){
downFinishListener.onDownFinish(path); downFinishListener.onDownFinish(url,path);
} else { } else {
downFinishListener.onError(); downFinishListener.onError();
} }
@ -188,6 +274,26 @@ public class DownPicUtil {
MODE_OVERRIDE MODE_OVERRIDE
} }
private static Boolean isVideoFileByMetadata(File file) {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
retriever.setDataSource(file.getAbsolutePath());
println("retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE) >>> " + retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE));
String duration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
return duration != null;
} catch (Exception e) {
return false;
} finally {
try {
retriever.release();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static String renamePic(File picFile, String filePath, String newFileNameNoExtension, String extension, MODE mode) { private static String renamePic(File picFile, String filePath, String newFileNameNoExtension, String extension, MODE mode) {
String extensionWithPoint = TextUtils.isEmpty(extension)? "": "." + extension; String extensionWithPoint = TextUtils.isEmpty(extension)? "": "." + extension;
String newFileName = newFileNameNoExtension + extensionWithPoint; String newFileName = newFileNameNoExtension + extensionWithPoint;
@ -242,7 +348,7 @@ public class DownPicUtil {
//下载完成回调的接口 //下载完成回调的接口
public interface DownFinishListener{ public interface DownFinishListener{
void onDownFinish(String path); void onDownFinish(String srcUrl ,String path);
void onError(); void onError();
} }
} }

View File

@ -6,6 +6,8 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import kr.lunaticbum.utils.log.LogUtil;
public class FormatHelper { public class FormatHelper {
private FormatHelper() { private FormatHelper() {
@ -13,6 +15,7 @@ public class FormatHelper {
public static String getExtension(File file) { public static String getExtension(File file) {
try { try {
// long fileLength = file.length(); // long fileLength = file.length();
FileInputStream fileInputStream = new FileInputStream(file); FileInputStream fileInputStream = new FileInputStream(file);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
@ -81,7 +84,34 @@ public class FormatHelper {
start[5] == (byte) 0x61) { start[5] == (byte) 0x61) {
return "gif"; return "gif";
} }
bufferedInputStream.reset();
start = new byte[6];
bufferedInputStream.read(start);
if (start[0] == (byte) 0x47 &&
start[1] == (byte) 0x49 &&
start[2] == (byte) 0x46 &&
start[3] == (byte) 0x38 &&
start[4] == (byte) 0x37 &&
start[5] == (byte) 0x61) {
return "gif";
}
bufferedInputStream.reset();
start = new byte[100];
bufferedInputStream.read(start);
String xmlDeclaration = new String(start, 0, 100, "UTF-8");
LogUtil.INSTANCE.e("Path " + file.getAbsolutePath() + " ::: HEADE" + xmlDeclaration + ";");
if (xmlDeclaration.contains("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") ||
xmlDeclaration.contains("http://www.w3.org/2000/svg")) {
return "svg";
}else if (xmlDeclaration.contains("iso") &&
xmlDeclaration.contains("mp4")) {
return "mp4";
}
bufferedInputStream.reset();
LogUtil.INSTANCE.e("Path " + file.getAbsolutePath() + " ::: HEADE" + start[0] + "," + start[1] + "," + start[2] + "," + start[3] + "," + start[4] + "," + start[5] + ";");
bufferedInputStream.close(); bufferedInputStream.close();
fileInputStream.close(); fileInputStream.close();
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {

View File

@ -46,33 +46,12 @@ public class PermissionHelper {
public static void CheckPermissions(final Context context, final CheckPermissionListener checkPermissionListener, String... permissionName) { public static void CheckPermissions(final Context context, final CheckPermissionListener checkPermissionListener, String... permissionName) {
if (hasPermissions(context, permissionName)) { // if (hasPermissions(context, permissionName)) {
if (checkPermissionListener != null) { if (checkPermissionListener != null) {
checkPermissionListener.onAllGranted(true); checkPermissionListener.onAllGranted(true);
} }
}else { // }else {
// AndPermission.with(context) // }
// .runtime()
// .permission(permissionName)
// .onGranted(new Action<List<String>>() {
// @Override
// public void onAction(List<String> permissions) {
// // 权限申请成功回调
// if (checkPermissionListener != null) {
// checkPermissionListener.onAllGranted(false);
// }
// }
// })
// .onDenied(new Action<List<String>>() {
// @Override
// public void onAction(List<String> permissions) {
// if (checkPermissionListener != null) {
// checkPermissionListener.onPartlyGranted(permissions, false);
// }
// }
// })
// .start();
}
} }
} }

View File

@ -97,5 +97,54 @@ public class VideoEnabledWebView extends WebView
videoJsHelper.addJavascriptInterface(this); videoJsHelper.addJavascriptInterface(this);
super.loadUrl(url, additionalHttpHeaders); super.loadUrl(url, additionalHttpHeaders);
} }
private boolean topReached = false;
private boolean bottomReached = false;
@Override
public int computeVerticalScrollRange() {
int readerViewHeight = getMeasuredHeight();
int verticalScrollRange = super.computeVerticalScrollRange();
if (readerViewHeight >= verticalScrollRange) {
topReached = true;
bottomReached = true;
}
return verticalScrollRange;
}
@Override
public void onScrollChanged(int newLeft, int newTop, int oldLeft, int oldTop) {
topReached = false;
bottomReached = false;
int readerViewHeight = getMeasuredHeight();
int contentHeight = getContentHeight();
if (newTop == 0) {
topReached = true;
} else if (newTop + readerViewHeight >= contentHeight) {
bottomReached = true;
}
super.onScrollChanged(newLeft, newTop, oldLeft, oldTop);
}
} }

View File

@ -82,6 +82,34 @@
android:visibility="invisible" /> --> android:visibility="invisible" /> -->
</RelativeLayout> </RelativeLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/blocking"
android:visibility="gone"
android:background="#99000000"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lotti"
android:layout_width="match_parent"
android:layout_height="250dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:lottie_autoPlay="true"
app:lottie_loop="true"
app:lottie_rawRes="@raw/lt_lodaing_01"
app:lottie_repeatMode="reverse"
/>
<TextView
app:layout_constraintTop_toBottomOf="@id/lotti"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="30dp"
android:text="저장을 위해\n리소스 모으는중..."
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout> </layout>

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,6 +3,8 @@ pluginManagement {
gradlePluginPortal() gradlePluginPortal()
google() google()
mavenCentral() mavenCentral()
// jcenter()
maven (url = "https://maven.mozilla.org/maven2/")
} }
} }
@ -10,12 +12,13 @@ pluginManagement {
dependencyResolutionManagement { dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories { repositories {
// jcenter()
google() google()
mavenCentral() mavenCentral()
maven (url = "https://maven.mozilla.org/maven2/")
maven(url = "https://jitpack.io") maven(url = "https://jitpack.io")
} }
} }
rootProject.name = "LunarLauncher" rootProject.name = "LunarLauncher"
include ("app","library","utils") include ("app","library","utils")
//annotations

View File

@ -1,13 +0,0 @@
package com.thefinestartist.utils;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -1,278 +0,0 @@
package com.thefinestartist.utils.etc;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import kr.lunaticbum.Base;
import kr.lunaticbum.utils.preferences.PreferencesUtil;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
/**
* Tests of the {@link PreferencesUtil} class.
*
* @author Robin Gustafsson
*/
public class PreferencesUtilTest extends AndroidTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
Base.initialize(getContext());
}
@SmallTest
public void testSetGetDefaultName() {
final String expected = "TEST_DEFAULT_NAME";
PreferencesUtil.setDefaultName(expected);
String actual = PreferencesUtil.getDefaultName();
assertEquals(expected, actual);
}
@SmallTest
public void testDifferentNames() {
final String name1 = "TEST_DIFFERENTNAMES_NAME1";
final String name2 = "TEST_DIFFERENTNAMES_NAME2";
final String key = "TEST_DIFFERENTNAMES_KEY";
final boolean value = true;
final boolean expected = false;
PreferencesUtil.put(name1, key, value);
boolean actual = PreferencesUtil.get(name2, key, expected);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreBoolean() {
final String key = "TEST_BOOLEAN";
final boolean expected = true;
final boolean defValue = false;
PreferencesUtil.put(key, expected);
boolean actual = PreferencesUtil.get(key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreBooleanNamed() {
final String name = "TEST_NAMED";
final String key = "TEST_BOOLEAN";
final boolean expected = true;
final boolean defValue = false;
PreferencesUtil.put(name, key, expected);
boolean actual = PreferencesUtil.get(name, key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreInt() {
final String key = "TEST_INT";
final int expected = 321;
final int defValue = 0;
PreferencesUtil.put(key, expected);
int actual = PreferencesUtil.get(key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreIntNamed() {
final String name = "TEST_NAMED";
final String key = "TEST_INT";
final int expected = 321;
final int defValue = 0;
PreferencesUtil.put(name, key, expected);
int actual = PreferencesUtil.get(name, key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreFloat() {
final String key = "TEST_FLOAT";
final float expected = 12.3f;
final float defValue = 0.0f;
PreferencesUtil.put(key, expected);
float actual = PreferencesUtil.get(key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreFloatNamed() {
final String name = "TEST_NAMED";
final String key = "TEST_FLOAT";
final float expected = 12.3f;
final float defValue = 0.0f;
PreferencesUtil.put(name, key, expected);
float actual = PreferencesUtil.get(name, key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreLong() {
final String key = "TEST_LONG";
final long expected = 321L;
final long defValue = 0L;
PreferencesUtil.put(key, expected);
long actual = PreferencesUtil.get(key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreLongNamed() {
final String name = "TEST_NAMED";
final String key = "TEST_LONG";
final long expected = 321L;
final long defValue = 0L;
PreferencesUtil.put(name, key, expected);
long actual = PreferencesUtil.get(name, key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreString() {
final String key = "TEST_STRING";
final String expected = "Lorem ipsum";
final String defValue = null;
PreferencesUtil.put(key, expected);
String actual = PreferencesUtil.get(key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreStringNamed() {
final String name = "TEST_NAMED";
final String key = "TEST_STRING";
final String expected = "Lorem ipsum";
final String defValue = null;
PreferencesUtil.put(name, key, expected);
String actual = PreferencesUtil.get(name, key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreStringSet() {
final String key = "TEST_STRINGSET";
final Set<String> expected = new HashSet<>();
expected.add("Lorem ipsum");
expected.add("dolor sit amet");
expected.add("consectetur adipiscing elit");
final Set<String> defValue = null;
PreferencesUtil.put(key, expected);
Set<String> actual = PreferencesUtil.get(key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testStoreStringSetNamed() {
final String name = "TEST_NAMED";
final String key = "TEST_STRINGSET";
final Set<String> expected = new HashSet<>();
expected.add("Lorem ipsum");
expected.add("dolor sit amet");
expected.add("consectetur adipiscing elit");
final Set<String> defValue = null;
PreferencesUtil.put(name, key, expected);
Set<String> actual = PreferencesUtil.get(name, key, defValue);
assertEquals(expected, actual);
}
@MediumTest
public void testStoreSerializable() {
final String key = "TEST_SERIALIZABLE";
final ArrayList<String> expected = new ArrayList<>();
expected.add("Lorem ipsum");
expected.add("dolor sit amet");
expected.add("consectetur adipiscing elit");
final ArrayList<String> defValue = new ArrayList<>();
defValue.add("Proin mollis dictum");
PreferencesUtil.put(key, expected);
ArrayList<String> actual = PreferencesUtil.get(key, defValue);
assertEquals(expected, actual);
}
@MediumTest
public void testStoreSerializableNamed() {
final String name = "TEST_NAMED";
final String key = "TEST_SERIALIZABLE";
final ArrayList<String> expected = new ArrayList<>();
expected.add("Lorem ipsum");
expected.add("dolor sit amet");
expected.add("consectetur adipiscing elit");
final ArrayList<String> defValue = new ArrayList<>();
defValue.add("Proin mollis dictum");
PreferencesUtil.put(name, key, expected);
ArrayList<String> actual = PreferencesUtil.get(name, key, defValue);
assertEquals(expected, actual);
}
@SmallTest
public void testRemove() {
final String key = "TEST_REMOVE";
final String expected = null;
PreferencesUtil.put(key, "Lorem ipsum");
PreferencesUtil.remove(key);
String actual = PreferencesUtil.get(key, expected);
assertEquals(expected, actual);
}
@SmallTest
public void testRemoveNamed() {
final String name = "TEST_NAMED";
final String key = "TEST_REMOVE";
final String expected = null;
PreferencesUtil.put(name, key, "Lorem ipsum");
PreferencesUtil.remove(name, key);
String actual = PreferencesUtil.get(name, key, expected);
assertEquals(expected, actual);
}
@SmallTest
public void testClear() {
final String[] keys = {"TEST_REMOVE_1", "TEST_REMOVE_2", "TEST_REMOVE_2"};
final String expected = null;
for (String key : keys) {
PreferencesUtil.put(key, "Lorem ipsum");
}
PreferencesUtil.clear();
for (String key : keys) {
String actual = PreferencesUtil.get(key, expected);
assertEquals(expected, actual);
}
}
@SmallTest
public void testClearNamed() {
final String name = "TEST_NAMED";
final String[] keys = {"TEST_REMOVE_1", "TEST_REMOVE_2", "TEST_REMOVE_2"};
final String expected = null;
for (String key : keys) {
PreferencesUtil.put(name, key, "Lorem ipsum");
}
PreferencesUtil.clear(name);
for (String key : keys) {
String actual = PreferencesUtil.get(name, key, expected);
assertEquals(expected, actual);
}
}
}

View File

@ -65,7 +65,8 @@ public class PDFPrint {
public static void generatePDFFromWebView(final File file, final WebView webView, final OnPDFPrintListener onPDFPrintListener) { public static void generatePDFFromWebView(final File file, final WebView webView, final OnPDFPrintListener onPDFPrintListener) {
PrintAttributes printAttributes = new PrintAttributes.Builder() PrintAttributes printAttributes = new PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.ISO_A4) .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
.setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600)) .setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", PrintAttributes.MediaSize.ISO_A4.getWidthMils(), PrintAttributes.MediaSize.ISO_A4.getWidthMils()))
.setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.setMinMargins(PrintAttributes.Margins.NO_MARGINS) .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.build(); .build();

View File

@ -1,15 +0,0 @@
package com.thefinestartist.utils;
import static org.junit.Assert.*;
import org.junit.Test;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}