...
This commit is contained in:
@@ -22,13 +22,11 @@ package bums.lunatic.launcher
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.SearchManager
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -49,89 +47,50 @@ import android.view.PointerIcon
|
||||
import android.view.View
|
||||
import android.view.WindowInsets
|
||||
import android.view.WindowManager
|
||||
import android.widget.Button
|
||||
import android.widget.HorizontalScrollView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||
import bums.lunatic.launcher.apps.AppDrawer
|
||||
import bums.lunatic.launcher.tokiz.Novels
|
||||
import bums.lunatic.launcher.common.CommonActivity
|
||||
import bums.lunatic.launcher.databinding.LauncherActivityBinding
|
||||
import bums.lunatic.launcher.feeds.WidgetHost
|
||||
import bums.lunatic.launcher.helpers.BluetoothManager
|
||||
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_STATUS_BAR
|
||||
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
||||
import bums.lunatic.launcher.helpers.Constants.Companion.widgetHostId
|
||||
import bums.lunatic.launcher.helpers.ForeGroundService
|
||||
import bums.lunatic.launcher.helpers.HeadsetActionButtonReceiver
|
||||
import bums.lunatic.launcher.helpers.PrefHelper.putString
|
||||
import bums.lunatic.launcher.helpers.PrefLong
|
||||
import bums.lunatic.launcher.home.GeckoWeb
|
||||
import bums.lunatic.launcher.home.RssHome
|
||||
import bums.lunatic.launcher.home.RssViewBuilder
|
||||
import bums.lunatic.launcher.model.RssData
|
||||
import bums.lunatic.launcher.model.RssDataType
|
||||
import bums.lunatic.launcher.receiver.NLService
|
||||
import bums.lunatic.launcher.settings.SettingsActivity
|
||||
import bums.lunatic.launcher.tokiz.Comics
|
||||
import bums.lunatic.launcher.tokiz.Magnet
|
||||
import bums.lunatic.launcher.tokiz.Novels
|
||||
import bums.lunatic.launcher.tokiz.Perplexity
|
||||
import bums.lunatic.launcher.tokiz.Twitter
|
||||
import bums.lunatic.launcher.tokiz.Webtoons
|
||||
import bums.lunatic.launcher.tokiz.Zota
|
||||
import bums.lunatic.launcher.utils.Blog
|
||||
import bums.lunatic.launcher.utils.FeedParseManager
|
||||
import bums.lunatic.launcher.utils.getJ
|
||||
import bums.lunatic.launcher.workers.AppInfoGetter
|
||||
import bums.lunatic.launcher.workers.ArcaGetter
|
||||
import bums.lunatic.launcher.workers.CalendarGetter
|
||||
import bums.lunatic.launcher.workers.ClienGetter
|
||||
import bums.lunatic.launcher.workers.ContactInfoGetter
|
||||
import bums.lunatic.launcher.workers.DCGetter
|
||||
import bums.lunatic.launcher.workers.DotaxGetter
|
||||
import bums.lunatic.launcher.workers.DotaxGetter.Companion.COMIC2_WORK_TAG
|
||||
import bums.lunatic.launcher.workers.FmKoreaGetter
|
||||
import bums.lunatic.launcher.workers.FmKoreaGetter.Companion.FM_WORK_TAG
|
||||
import bums.lunatic.launcher.workers.LocationGetter
|
||||
import bums.lunatic.launcher.workers.NewsFeedsGetter
|
||||
import bums.lunatic.launcher.workers.NewsFeedsGetter.Companion.FEDDS_WORK_TAG
|
||||
import bums.lunatic.launcher.workers.RecentCallGetter
|
||||
import bums.lunatic.launcher.workers.RecentSmsGetter
|
||||
import bums.lunatic.launcher.workers.RecentSmsGetter.Companion.SMS_WORK_TAG
|
||||
import bums.lunatic.launcher.workers.RedditGetter
|
||||
import bums.lunatic.launcher.workers.RedditGetter.Companion.REDDIT_WORK_TAG
|
||||
import bums.lunatic.launcher.workers.RuliWebGetter
|
||||
import bums.lunatic.launcher.workers.TheQooGetter
|
||||
import bums.lunatic.launcher.workers.WorkersDb
|
||||
import bums.lunatic.launcher.workers.YoutubeGetter
|
||||
import bums.lunatic.launcher.workers.YoutubeGetter.Companion.YT_WORK_TAG
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import com.yausername.ffmpeg.FFmpeg
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import com.yausername.youtubedl_android.YoutubeDLException
|
||||
import io.realm.kotlin.ext.query
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kr.lunaticbum.utils.ui.DisplayUtil
|
||||
import org.json.JSONObject
|
||||
import org.mozilla.geckoview.ExperimentDelegate
|
||||
import org.mozilla.geckoview.GeckoResult
|
||||
import org.mozilla.geckoview.GeckoRuntime
|
||||
import org.mozilla.geckoview.GeckoRuntimeSettings
|
||||
import java.util.Base64
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.jvm.java
|
||||
|
||||
|
||||
open class LauncherActivity : CommonActivity() {
|
||||
@@ -209,7 +168,8 @@ open class LauncherActivity : CommonActivity() {
|
||||
Blog.LOGE("onConfigurationChanged newConfig?.screenWidthDp >> ${newConfig?.screenWidthDp}")
|
||||
Blog.LOGE("onConfigurationChanged newConfig?.screenHeightDp >> ${newConfig?.screenHeightDp}")
|
||||
isOpendFold = (newConfig.screenWidthDp * 1.1f) > newConfig.screenHeightDp
|
||||
|
||||
val nullCursor = PointerIcon.getSystemIcon(this, PointerIcon.TYPE_NULL)
|
||||
binding.root.setPointerIcon(nullCursor)
|
||||
}
|
||||
// override fun onKeyClick(keyCode: Int): Boolean {
|
||||
// when (keyCode) {
|
||||
@@ -533,15 +493,24 @@ open class LauncherActivity : CommonActivity() {
|
||||
@SuppressLint("NewApi", "MissingPermission")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
installSplashScreen()
|
||||
super.onCreate(savedInstanceState)
|
||||
try {
|
||||
YoutubeDL.getInstance().init(this)
|
||||
FFmpeg.getInstance().init(this);
|
||||
} catch (e: YoutubeDLException) {
|
||||
Blog.LOGE("failed to initialize youtubedl-android", e)
|
||||
}
|
||||
val intent = Intent(this, ForeGroundService::class.java)
|
||||
this.startForegroundService(intent)
|
||||
|
||||
val nlService = Intent(this, NLService::class.java)
|
||||
this.startService(nlService)
|
||||
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
lActivity = this
|
||||
|
||||
DynamicColors.applyToActivityIfAvailable(this)
|
||||
|
||||
|
||||
settingsPrefs = getSharedPreferences(PREFS_SETTINGS, 0)
|
||||
// AppCompatDelegate.setDefaultNightMode(settingsPrefs.getInt(KEY_APPLICATION_THEME, MODE_NIGHT_FOLLOW_SYSTEM))
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
||||
binding = LauncherActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
@@ -553,8 +522,8 @@ open class LauncherActivity : CommonActivity() {
|
||||
updateLocationService()
|
||||
|
||||
|
||||
val intent = Intent(this, BluetoothManager::class.java)
|
||||
ContextCompat.startForegroundService(this, intent)
|
||||
|
||||
|
||||
showContents(binding.feeds.id)
|
||||
binding.floatingActionMenu.setOnMenuButtonClickListener { v->
|
||||
Blog.LOGE("v >> ${v}")
|
||||
@@ -622,6 +591,10 @@ open class LauncherActivity : CommonActivity() {
|
||||
.replace(R.id.fragment_container, Magnet())
|
||||
.commit()
|
||||
}
|
||||
R.id.setting ->{
|
||||
startActivity(Intent(this, SettingsActivity::class.java))
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
binding.floatingActionMenu.close(false)
|
||||
|
||||
+85
-24
@@ -2,9 +2,9 @@ package bums.lunatic.launcher.helpers
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothDevice
|
||||
@@ -17,12 +17,13 @@ import android.os.Build
|
||||
import android.os.IBinder
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import bums.lunatic.launcher.LauncherActivity
|
||||
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||
import bums.lunatic.launcher.R
|
||||
import bums.lunatic.launcher.home.GeckoWeb
|
||||
import bums.lunatic.launcher.utils.Blog
|
||||
import bums.lunatic.launcher.workers.ArcaGetter
|
||||
import bums.lunatic.launcher.workers.ClienGetter
|
||||
@@ -51,8 +52,11 @@ import okhttp3.ResponseBody
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class BluetoothManager : Service() {
|
||||
|
||||
class ForeGroundService : Service() {
|
||||
companion object {
|
||||
val ACTION_SENDMSG = "ACTION_SEND_TO_LOVE"
|
||||
val EXTRA_MSGKEY = "SEND_MSG"
|
||||
}
|
||||
enum class BLUETOOTH_STATE(val statestr: String) {
|
||||
ENABLED("enabledBlutooth"),
|
||||
DISABLED("disableBlutooth"),
|
||||
@@ -67,44 +71,71 @@ class BluetoothManager : Service() {
|
||||
super.onCreate()
|
||||
Blog.LOGE("onCreate")
|
||||
mWorkManager = WorkManager.getInstance(this)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForeground(NOTIF_ID, createNotification(this))
|
||||
}
|
||||
val filter = IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)
|
||||
registerReceiver(bluetoothreceiver, filter)
|
||||
refreshFeeds()
|
||||
// GeckoWeb(applicationContext).apply {
|
||||
// loadUrl("https://arca.live/b/live")
|
||||
// }
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
Blog.LOGE("intent >>> ${intent}")
|
||||
return null
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
Blog.LOGE("onStartCommand >>> ${intent}")
|
||||
if (ACTION_SENDMSG.equals(intent?.action)) {
|
||||
intent?.getStringExtra(EXTRA_MSGKEY)?.let {
|
||||
sendToI(it)
|
||||
}
|
||||
}
|
||||
startForeGround()
|
||||
return START_STICKY
|
||||
}
|
||||
private val CHANNEL_ID = "ble_service_channel"
|
||||
private val CHANNEL_NAME = "BLE 서비스"
|
||||
|
||||
fun createNotification(context: Context): Notification {
|
||||
fun startForeGround() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_HIGH // 중요도 낮게 (필요시 변경)
|
||||
"BLE 서비스 채널",
|
||||
NotificationManager.IMPORTANCE_HIGH
|
||||
)
|
||||
val notificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
val manager = getSystemService(NotificationManager::class.java)
|
||||
manager.createNotificationChannel(channel)
|
||||
}
|
||||
return NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
val intent = Intent(this, LauncherActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
}
|
||||
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
this,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
startForeground(NOTIF_ID, NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setContentTitle("BLE 서비스")
|
||||
.setContentText("실행중입니다.")
|
||||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||
.setSmallIcon(R.drawable.ic_b)
|
||||
.setContentIntent(pendingIntent)
|
||||
.addAction(android.R.drawable.ic_btn_speak_now,"퇴근", makeSendMsgAction(0,"돼지 퇴근했다요~!"))
|
||||
.addAction(android.R.drawable.ic_btn_speak_now,"버스 탐", makeSendMsgAction(1,"돼지 버스 탔다요~!"))
|
||||
.addAction(android.R.drawable.ic_btn_speak_now,"버스 내림", makeSendMsgAction(2,"돼지 버스 내린다요~!"))
|
||||
.setOngoing(true) // 사용자가 알림을 스와이프로 지울 수 없게 만듦
|
||||
.build()
|
||||
.build())
|
||||
}
|
||||
|
||||
fun makeSendMsgAction(code : Int, msg : String) : PendingIntent {
|
||||
val actionIntent = Intent(this, ForeGroundService::class.java).apply {
|
||||
action = ACTION_SENDMSG
|
||||
putExtra(EXTRA_MSGKEY, msg) // 전달할 데이터
|
||||
}
|
||||
return PendingIntent.getService(this, code, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE )
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
Blog.LOGE("onBind intent >>> ${intent}")
|
||||
return null
|
||||
}
|
||||
private val CHANNEL_ID = "ble_service_channel"
|
||||
private val CHANNEL_NAME = "BLE 서비스"
|
||||
|
||||
|
||||
//페어링된 디바이스 정보 가져오기
|
||||
fun getPairedDevices() {
|
||||
@@ -192,6 +223,14 @@ class BluetoothManager : Service() {
|
||||
PeriodicWorkRequestBuilder<LocationGetter>(PrefLong.locationTimePeriod.get(), TimeUnit.MINUTES)
|
||||
.addTag(LocationGetter.TAG)
|
||||
.build())
|
||||
mWorkManager?.cancelAllWorkByTag(ServiceWatchdogWorker.TAG)
|
||||
mWorkManager?.enqueueUniquePeriodicWork(
|
||||
ServiceWatchdogWorker.TAG,
|
||||
ExistingPeriodicWorkPolicy.REPLACE,
|
||||
PeriodicWorkRequestBuilder<ServiceWatchdogWorker>(15, TimeUnit.MINUTES)
|
||||
.addTag(ServiceWatchdogWorker.TAG)
|
||||
.build())
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -202,6 +241,21 @@ class BluetoothManager : Service() {
|
||||
return mWorkManager
|
||||
}
|
||||
|
||||
fun sendToI(msg: String) {
|
||||
if (PrefString.telegramSendTarget.get().length > 5) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
OkHttpClient.Builder()
|
||||
.connectionPool(ConnectionPool(5, 60, TimeUnit.SECONDS))
|
||||
.build().newCall(Request.Builder().url("https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w/sendMessage?chat_id=${PrefString.telegramSendTarget.get()}&text=${msg}")
|
||||
.addHeader("Content-Type", "application/json").get().build()).execute()?.let { response ->
|
||||
if (response.isSuccessful()) {
|
||||
val body: ResponseBody? = response.body()
|
||||
if (body != null) { }
|
||||
} else Blog.LOGE("sendToI telegram Error Occurred")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fun sendToI(boolean: Boolean) {
|
||||
if (PrefString.telegramSendTarget.get().length > 5) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
@@ -215,7 +269,7 @@ class BluetoothManager : Service() {
|
||||
val response: Response = OkHttpClient.Builder()
|
||||
.connectionPool(ConnectionPool(5, 60, TimeUnit.SECONDS))
|
||||
.build().newCall(Request.Builder().url(url)
|
||||
.addHeader("Content-Type", "application/json").get().build()).execute()
|
||||
.addHeader("Content-Type", "application/json").get().build()).execute()
|
||||
if (response.isSuccessful()) {
|
||||
// 응답 받아서 처리
|
||||
val body: ResponseBody? = response.body()
|
||||
@@ -251,6 +305,13 @@ class BluetoothManager : Service() {
|
||||
return BLUETOOTH_STATE.NOT_SUPPORT.statestr
|
||||
}
|
||||
|
||||
override fun stopService(name: Intent?): Boolean {
|
||||
Blog.LOGE("stopService ${name}")
|
||||
val intent = Intent(this, ForeGroundService::class.java)
|
||||
ContextCompat.startForegroundService(this, intent)
|
||||
return super.stopService(name)
|
||||
}
|
||||
|
||||
//add Receive action
|
||||
private fun addFilterAction(): IntentFilter {
|
||||
val stateFilter = IntentFilter()
|
||||
@@ -0,0 +1,36 @@
|
||||
package bums.lunatic.launcher.helpers
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
|
||||
class ServiceWatchdogWorker(
|
||||
private val context: Context,
|
||||
workerParams: WorkerParameters
|
||||
) : Worker(context, workerParams) {
|
||||
|
||||
companion object{
|
||||
val TAG = "ServiceWatchdogWorker"
|
||||
}
|
||||
|
||||
override fun doWork(): Result {
|
||||
val isServiceRunning = isServiceRunning(ForeGroundService::class.java)
|
||||
if (!isServiceRunning) {
|
||||
val intent = Intent(context, ForeGroundService::class.java)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(intent)
|
||||
} else {
|
||||
context.startService(intent)
|
||||
}
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
fun isServiceRunning(serviceClass: Class<*>): Boolean {
|
||||
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
return manager.getRunningServices(Int.MAX_VALUE)
|
||||
.any { it.service.className == serviceClass.name }
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ import androidx.core.net.toUri
|
||||
import androidx.core.view.isVisible
|
||||
import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime
|
||||
import bums.lunatic.launcher.R
|
||||
import bums.lunatic.launcher.model.others.Button
|
||||
import bums.lunatic.launcher.tokiz.data.model.PortMessage
|
||||
import bums.lunatic.launcher.tokiz.view.BWebview
|
||||
import bums.lunatic.launcher.utils.Blog
|
||||
@@ -47,6 +48,9 @@ import bums.lunatic.launcher.utils.CommonUtils
|
||||
import bums.lunatic.launcher.workers.WorkersDb
|
||||
import com.google.gson.Gson
|
||||
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||
import com.yausername.youtubedl_android.YoutubeDLResponse
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -54,6 +58,7 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kr.lunaticbum.utils.service.ServiceUtil.getSystemService
|
||||
import kr.lunaticbum.utils.service.ServiceUtil.layoutInflater
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.json.JSONException
|
||||
@@ -61,6 +66,7 @@ import org.json.JSONObject
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import org.mozilla.gecko.util.ThreadUtils
|
||||
import org.mozilla.gecko.util.ThreadUtils.runOnUiThread
|
||||
import org.mozilla.geckoview.ExperimentDelegate
|
||||
import org.mozilla.geckoview.GeckoResult
|
||||
import org.mozilla.geckoview.GeckoSession
|
||||
@@ -76,6 +82,7 @@ import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.UUID
|
||||
|
||||
class GeckoWeb : BWebview {
|
||||
constructor(context: Context?) : super(context) {
|
||||
@@ -84,7 +91,7 @@ class GeckoWeb : BWebview {
|
||||
var decoViews = arrayListOf<View>()
|
||||
override fun setVisibility(visibility: Int) {
|
||||
super.setVisibility(visibility)
|
||||
decoViews.filter { it != null && it.id > -1 }.forEach { it.visibility = visibility }
|
||||
decoViews.filter { it != null && it.id > -1 && it.id != R.id.dl_video }.forEach { it.visibility = visibility }
|
||||
}
|
||||
interface OnSave {
|
||||
fun saved()
|
||||
@@ -448,6 +455,153 @@ class GeckoWeb : BWebview {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkIfDownloadable(url: String) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
runOnUiThread {
|
||||
decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let {
|
||||
it.setOnClickListener {}
|
||||
it.visibility = View.GONE
|
||||
}}}
|
||||
Blog.LOGE("checkIfDownloadable ${url}")
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val videoInfo = YoutubeDL.getInstance().getInfo(url)
|
||||
// videoInfo 가 null 아니고, 필요한 키(예: title, url 등)가 있으면 다운로드 가능
|
||||
Blog.LOGE("checkIfDownloadable ${url}\n videoInfo : ${videoInfo}")
|
||||
var canVideoDown = videoInfo != null && !videoInfo.title.isNullOrEmpty()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
runOnUiThread {
|
||||
decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let {
|
||||
it.setOnClickListener {
|
||||
videoDlownLoad(url)
|
||||
}
|
||||
it.visibility = if (canVideoDown){View.VISIBLE} else{View.GONE}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
Blog.LOGE("checkIfDownloadable ${url} ${e}")
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
runOnUiThread {
|
||||
decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let {
|
||||
it.setOnClickListener {}
|
||||
it.visibility = View.GONE
|
||||
}}}
|
||||
}
|
||||
}
|
||||
}
|
||||
fun replaceDcUrl(origin: String): String {
|
||||
var result = origin
|
||||
for (i in 0..19) {
|
||||
result = result.replace(String.format("dcimg%d.", i), "dcimg2.")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun copyToClipboard(text: String?) {
|
||||
if (text == null) return
|
||||
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("Media URL", text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(context, "주소가 복사되었습니다.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
|
||||
suspend fun getFormatList(url: String): List<String> = withContext(Dispatchers.IO) {
|
||||
val command = YoutubeDLRequest(lastedUrl!!)
|
||||
command.addOption("--list-formats", url)
|
||||
val output = YoutubeDL.getInstance().execute(command)
|
||||
// output.stdout에 포맷 리스트가 문자열로 들어있음
|
||||
// 줄 단위로 분리 후 리턴
|
||||
Blog.LOGE("output.out >>> ${output.out}")
|
||||
return@withContext output.out.split("\n").filter { it.isNotBlank() }
|
||||
}
|
||||
|
||||
fun showFormatSelectionDialog(formats: List<String>, onFormatSelected: (String) -> Unit) {
|
||||
val builder = AlertDialog.Builder(context)
|
||||
builder.setTitle("포맷 선택")
|
||||
builder.setItems(formats.toTypedArray()) { _, which ->
|
||||
onFormatSelected(formats[which])
|
||||
}
|
||||
builder.setNegativeButton("취소", null)
|
||||
builder.show()
|
||||
}
|
||||
|
||||
|
||||
|
||||
lateinit var progressDialog: AlertDialog
|
||||
fun showProgressDialog() {
|
||||
val dialogView = layoutInflater.inflate(R.layout.progress_dialog, null)
|
||||
val progressBar = dialogView.findViewById<ProgressBar>(R.id.progressBar)
|
||||
val textProgress = dialogView.findViewById<TextView>(R.id.textProgress)
|
||||
val btn = dialogView.findViewById<android.widget.Button>(R.id.dl_cancel)
|
||||
progressDialog = AlertDialog.Builder(context)
|
||||
.setTitle("다운로드 중...")
|
||||
.setView(dialogView)
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
progressDialog.show()
|
||||
|
||||
// UI 업데이트 함수 예 (나중에 실행)
|
||||
fun updateProgress(progress: Int, est : Long, str : String) {
|
||||
runOnUiThread {
|
||||
progressBar.progress = progress
|
||||
textProgress.text = "$progress%"
|
||||
}
|
||||
}
|
||||
}
|
||||
fun dismissProgressDialog() {
|
||||
progressDialog.dismiss()
|
||||
}
|
||||
|
||||
suspend fun downloadVideo(processId : String,url: String, updateProgress: (Float, Long, String) -> Unit) = withContext(Dispatchers.IO) {
|
||||
val youtubeDLDir = File(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
|
||||
"youtubedl-android"
|
||||
)
|
||||
val command = YoutubeDLRequest(url)
|
||||
command.addOption("-o", youtubeDLDir.getAbsolutePath() + "/%(title)s.%(ext)s");
|
||||
var process = YoutubeDL.getInstance().execute(command,processId) { progress, est , str ->
|
||||
updateProgress(progress, est, str)
|
||||
}
|
||||
return@withContext process
|
||||
}
|
||||
|
||||
fun videoDlownLoad(videoUrl : String) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
try {
|
||||
showProgressDialog()
|
||||
var res: YoutubeDLResponse? = null
|
||||
val processId = UUID.randomUUID().toString()
|
||||
res = downloadVideo(processId, videoUrl) { progress , time , str->
|
||||
runOnUiThread {
|
||||
val pb =
|
||||
progressDialog.findViewById<ProgressBar>(R.id.progressBar)
|
||||
val tv =
|
||||
progressDialog.findViewById<TextView>(R.id.textProgress)
|
||||
pb?.progress = progress.toInt()
|
||||
val btn = progressDialog.findViewById<android.widget.Button>(R.id.dl_cancel)
|
||||
tv?.text = "$progress%\n$str"
|
||||
btn?.setOnClickListener {
|
||||
progressDialog?.dismiss()
|
||||
YoutubeDL.getInstance().destroyProcessById(processId);
|
||||
}
|
||||
}
|
||||
}
|
||||
dismissProgressDialog()
|
||||
Toast.makeText(context, "다운로드 완료", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
progressDialog?.dismiss()
|
||||
Toast.makeText(context, "오류: ${e.message}", Toast.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var dialog : Dialog? = null
|
||||
fun getFilterF() = String(java.util.Base64.getMimeDecoder().decode("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=".toByteArray()))
|
||||
var currentTitle = ""
|
||||
@@ -474,21 +628,7 @@ class GeckoWeb : BWebview {
|
||||
|
||||
super.onFirstContentfulPaint(session)
|
||||
}
|
||||
fun replaceDcUrl(origin: String): String {
|
||||
var result = origin
|
||||
for (i in 0..19) {
|
||||
result = result.replace(String.format("dcimg%d.", i), "dcimg2.")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun copyToClipboard(text: String?) {
|
||||
if (text == null) return
|
||||
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("Media URL", text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(context, "주소가 복사되었습니다.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onExternalResponse(session: GeckoSession, response: WebResponse) {
|
||||
Blog.LOGE("response >>> ${response.uri} ")
|
||||
@@ -504,6 +644,7 @@ class GeckoWeb : BWebview {
|
||||
val client = OkHttpClient()
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.addHeader("Referer", lastedUrl)
|
||||
.addHeader("User-Agent", "Mozilla/5.0")
|
||||
// 필요시 Referer, 쿠키 등 헤더 추가
|
||||
.build()
|
||||
@@ -531,6 +672,7 @@ class GeckoWeb : BWebview {
|
||||
super.onExternalResponse(session, response)
|
||||
}
|
||||
|
||||
|
||||
override fun onContextMenu(
|
||||
session: GeckoSession,
|
||||
screenX: Int,
|
||||
@@ -539,18 +681,11 @@ class GeckoWeb : BWebview {
|
||||
) {
|
||||
|
||||
if (element.baseUri?.contains("youtube") == true) {
|
||||
copyToClipboard(lastedUrl)
|
||||
loadUrl("https://ko.savefrom.net/227lt/#url=${lastedUrl}")
|
||||
// copyToClipboard(lastedUrl)
|
||||
// Dialog(context)?.let { dialog ->
|
||||
// val popupWebView = GeckoWeb(context).apply {
|
||||
// loadUrl(lastedUrl!!.replace("https://","https://ss"))
|
||||
// this.dialog = dialog
|
||||
// }
|
||||
// dialog.setCanceledOnTouchOutside(true)
|
||||
// dialog.setContentView(popupWebView)
|
||||
// dialog.show()
|
||||
// }
|
||||
lastedUrl?.let { videoUrl ->
|
||||
lastedUrl?.let {
|
||||
videoDlownLoad(it)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Blog.LOGE("onContextMenu:: x = ${x}, y = ${y} , element = ${Gson().toJson(element)}")
|
||||
if (element.type == GeckoSession.ContentDelegate.ContextElement.TYPE_IMAGE) {
|
||||
@@ -656,8 +791,8 @@ class GeckoWeb : BWebview {
|
||||
)
|
||||
} == true ||
|
||||
((it.host?.contains("x.com") ?: false) == true) ||
|
||||
((it.host?.contains("www.instagram.com") ?: false) == true)
|
||||
) {
|
||||
((it.host?.contains("www.instagram.com") ?: false) == true)
|
||||
) {
|
||||
loadUrl(uri)
|
||||
} else if(uri.contains("googlevideo.com")) {
|
||||
CommonUtils.downloadFileWithOkHttp(context, Uri.parse(lastedUrl),uri)
|
||||
@@ -723,6 +858,7 @@ class GeckoWeb : BWebview {
|
||||
} else {
|
||||
lastedUrl = url
|
||||
}
|
||||
checkIfDownloadable(url)
|
||||
}
|
||||
|
||||
|
||||
@@ -735,6 +871,8 @@ class GeckoWeb : BWebview {
|
||||
it.tag = currentTitle
|
||||
it.text = url
|
||||
}
|
||||
}else if (it.id == R.id.reload) {
|
||||
it.setOnClickListener { session.reload() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,6 +625,8 @@ internal class RssHome : Fragment() {
|
||||
(activity as? LauncherActivity)?.let { activity ->
|
||||
binding.geckoWeb.decoViews.add(activity.findViewById<TextView>(R.id.current_address))
|
||||
binding.geckoWeb.decoViews.add(activity.findViewById<ImageButton>(R.id.back))
|
||||
binding.geckoWeb.decoViews.add(activity.findViewById<ImageButton>(R.id.reload))
|
||||
binding.geckoWeb.decoViews.add(activity.findViewById<ImageButton>(R.id.dl_video))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package bums.lunatic.launcher.receiver
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
@@ -13,9 +14,11 @@ import android.service.notification.NotificationListenerService
|
||||
import android.service.notification.StatusBarNotification
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.getSystemService
|
||||
import bums.lunatic.launcher.helpers.ForeGroundService
|
||||
import bums.lunatic.launcher.model.CurrentPlayItem
|
||||
import bums.lunatic.launcher.model.NotificationItem
|
||||
import bums.lunatic.launcher.utils.BitmapConverter
|
||||
import bums.lunatic.launcher.utils.Blog
|
||||
import bums.lunatic.launcher.workers.WorkersDb
|
||||
import io.realm.kotlin.UpdatePolicy
|
||||
import io.realm.kotlin.ext.query
|
||||
@@ -29,7 +32,6 @@ class NLService : NotificationListenerService() {
|
||||
super.onCreate()
|
||||
nlservicereciver = NLServiceReceiver()
|
||||
val filter = IntentFilter()
|
||||
// filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE")
|
||||
registerReceiver(nlservicereciver, filter)
|
||||
}
|
||||
|
||||
@@ -38,130 +40,54 @@ class NLService : NotificationListenerService() {
|
||||
unregisterReceiver(nlservicereciver)
|
||||
}
|
||||
|
||||
val skips = arrayListOf("com.wssyncmldm")
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.S)
|
||||
override fun onNotificationPosted(sbn: StatusBarNotification) {
|
||||
// BLog.LOGE("NLService********** onNotificationPosted")
|
||||
// BLog.LOGE("NLServiceID :" + sbn.id + "\t${sbn.notification.tickerText}\t" + sbn.packageName)
|
||||
// sbn.notification.extras.keySet().forEach {
|
||||
// BLog.LOGE("NLService********** keySet >> ${it} ${sbn.notification.extras.get(it)}")
|
||||
// }
|
||||
try {
|
||||
if (sbn.id != 0 && (sbn.packageName.contains(".") || sbn.packageName.contains("android")) && sbn.packageName.length > 0) {
|
||||
NotificationItem().apply {
|
||||
notiId = sbn.id
|
||||
pkgName = sbn.packageName
|
||||
title = sbn.notification?.extras?.getString("android.title") ?: ""
|
||||
subtext = sbn.notification?.extras?.getString("android.subText") ?: ""
|
||||
selfDisplayName = sbn.notification?.extras?.getString("android.selfDisplayName") ?: ""
|
||||
tikerMsg = sbn.notification?.tickerText?.toString() ?: ""
|
||||
postTime = sbn.postTime
|
||||
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 == "org.telegram.messenger".equals(pkgName))}")
|
||||
// BLog.LOGE("NLService********** enqueue TelegramBotGetter ${sbn.notification?.extras?.getString("android.text")?.startsWith("/") == true}")
|
||||
}.apply {
|
||||
if (skips.contains(pkgName)) {
|
||||
Blog.LOGE("onNotificationPosted ${sbn}")
|
||||
val notification = sbn.notification
|
||||
val extras = notification.extras
|
||||
when (sbn.packageName){
|
||||
"com.kakao.talk" -> {
|
||||
|
||||
} else {
|
||||
// WorkersDb.insertNoti(this)
|
||||
// BLog.LOGE("NLService********** onNotificationPosted ${Gson().toJson(this)}")
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
if (sbn.packageName.contains("youtube")) {
|
||||
val m = getSystemService<MediaSessionManager>()!!
|
||||
val component = ComponentName(this, NLService::class.java)
|
||||
val sessions = m.getActiveSessions(component)
|
||||
sessions.forEach { session ->
|
||||
WorkersDb.getRealm().writeBlocking {
|
||||
// Blog.LOGE("session.playbackState >>> ${session.playbackState}")
|
||||
if (session.playbackState != null) {
|
||||
if (session.playbackState?.isActive == true && session.playbackState?.state?.equals(
|
||||
STATE_PLAYING
|
||||
) == true
|
||||
) {
|
||||
session.playbackState?.state
|
||||
val result = query<CurrentPlayItem>().find()
|
||||
var current: CurrentPlayItem? = null
|
||||
if (result.size > 0) {
|
||||
current = result.first()
|
||||
} else {
|
||||
current = CurrentPlayItem()
|
||||
copyToRealm(current, UpdatePolicy.ALL)
|
||||
}
|
||||
if (session?.metadata?.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART) == true) {
|
||||
current.albumArt = BitmapConverter.BitmapToString(
|
||||
session.metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)
|
||||
)
|
||||
} else {
|
||||
current.albumArt = ""
|
||||
}
|
||||
current.title =
|
||||
session?.metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
|
||||
current.artists =
|
||||
session?.metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
|
||||
} else {
|
||||
delete(query<CurrentPlayItem>().find())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}}catch (e : Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
// val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
// i.putExtra("notification_event", "onNotificationPosted :" + sbn.packageName + "\n")
|
||||
// sendBroadcast(i)
|
||||
val title = extras.getString(Notification.EXTRA_TITLE) ?: ""
|
||||
val text = extras.getCharSequence(Notification.EXTRA_TEXT)?.toString() ?: ""
|
||||
val bigText = extras.getCharSequence(Notification.EXTRA_BIG_TEXT)?.toString() ?: ""
|
||||
val extraInfo = extras.getCharSequence(Notification.EXTRA_INFO_TEXT)?.toString() ?: ""
|
||||
val subText = extras.getCharSequence(Notification.EXTRA_SUB_TEXT)?.toString() ?: ""
|
||||
val conversationTitle = extras.getCharSequence(Notification.EXTRA_CONVERSATION_TITLE)?.toString() ?: ""
|
||||
val summaryText = extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT)?.toString() ?: ""
|
||||
val verificationText = extras.getCharSequence(Notification.EXTRA_VERIFICATION_TEXT)?.toString() ?: ""
|
||||
|
||||
Blog.LOGE("title >> ${title} text >> ${text} bigText >> ${bigText} extraInfo >> ${extraInfo} subText >> ${subText} conversationTitle >> ${conversationTitle} summaryText >> ${summaryText} verificationText >> ${verificationText}")
|
||||
|
||||
}
|
||||
|
||||
override fun onNotificationRemoved(sbn: StatusBarNotification) {
|
||||
//// BLog.LOGE("NLService********** onNOtificationRemoved")
|
||||
//// BLog.LOGE("NLService ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName)
|
||||
// var uniq_id = "${sbn.id}_${sbn.packageName}"
|
||||
// try {
|
||||
// WorkersDb.getRealm()?.apply {
|
||||
// this.writeBlocking {
|
||||
//// delete(query<NotificationItem>().query("pkgName == $0", sbn.packageName).find())
|
||||
// }
|
||||
// }
|
||||
// }catch (e : Exception){e.printStackTrace()}
|
||||
//// val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
//// i.putExtra("notification_event", "onNotificationRemoved :" + sbn.packageName + "\n")
|
||||
//// sendBroadcast(i)
|
||||
Blog.LOGE("onNotificationPosted ${sbn}")
|
||||
if (sbn.packageName == "bums.lunatic.launcher" && sbn.id == 830721) {
|
||||
// 포그라운드 알림이 사라짐 감지
|
||||
Blog.LOGE("NotificationListener", "포그라운드 알림 제거 감지")
|
||||
|
||||
// 서비스 재시작 시도
|
||||
val intent = Intent(this, ForeGroundService::class.java)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(intent)
|
||||
} else {
|
||||
startService(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal inner class NLServiceReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent) {
|
||||
// BLog.LOGE("NLService intent >>> ${intent.action}")
|
||||
if (intent.getStringExtra("command") == "clearall") {
|
||||
this@NLService.cancelAllNotifications()
|
||||
} else if (intent.getStringExtra("command") == "list") {
|
||||
// val i1 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
// i1.putExtra("notification_event", "=====================")
|
||||
// sendBroadcast(i1)
|
||||
var i = 1
|
||||
for (sbn in this@NLService.activeNotifications) {
|
||||
// BLog.LOGE("NLService sbn >>> ${sbn.packageName} , ${Gson().toJson(sbn.notification.extras.keySet())}")
|
||||
// val i2 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
// i2.putExtra("notification_event", i.toString() + " " + sbn.packageName + "\n")
|
||||
// sendBroadcast(i2)
|
||||
// i++
|
||||
}
|
||||
// val i3 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
// i3.putExtra("notification_event", "===== Notification List ====")
|
||||
// sendBroadcast(i3)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package bums.lunatic.launcher.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import android.view.ScaleGestureDetector
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
class ZoomImageView(context: Context, attrs: AttributeSet) : AppCompatImageView(context, attrs),
|
||||
ScaleGestureDetector.OnScaleGestureListener, GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
|
||||
|
||||
private var scaleFactor = 1.0f
|
||||
private val scaleGestureDetector = ScaleGestureDetector(context, this)
|
||||
private val gestureDetector = GestureDetector(context, this)
|
||||
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
scaleGestureDetector.onTouchEvent(event)
|
||||
gestureDetector.onTouchEvent(event)
|
||||
return true
|
||||
}
|
||||
|
||||
// ScaleGestureDetector callbacks
|
||||
override fun onScale(detector: ScaleGestureDetector): Boolean {
|
||||
scaleFactor *= detector.scaleFactor
|
||||
scaleFactor = scaleFactor.coerceIn(1.0f, 4.0f)
|
||||
scaleX = scaleFactor
|
||||
scaleY = scaleFactor
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onScaleBegin(detector: ScaleGestureDetector) = true
|
||||
override fun onScaleEnd(detector: ScaleGestureDetector) {}
|
||||
|
||||
// GestureDetector callbacks (클릭, 터치 등)
|
||||
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
||||
performClick() // 클릭 이벤트 발생
|
||||
return true
|
||||
}
|
||||
|
||||
override fun performClick(): Boolean {
|
||||
super.performClick()
|
||||
// 추가로 클릭 시 동작할 코드 넣기
|
||||
if (hasOnClickListeners()) {
|
||||
callOnClick()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDown(e: MotionEvent) = true
|
||||
override fun onShowPress(e: MotionEvent) {}
|
||||
override fun onSingleTapUp(e: MotionEvent) = true
|
||||
override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float) = false
|
||||
override fun onLongPress(e: MotionEvent) {}
|
||||
override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float) = false
|
||||
override fun onDoubleTap(e: MotionEvent) = true
|
||||
override fun onDoubleTapEvent(e: MotionEvent) = true
|
||||
}
|
||||
Reference in New Issue
Block a user