437 lines
15 KiB
Kotlin
437 lines
15 KiB
Kotlin
package com.assimilate.alltrans.viewui
|
|
|
|
import android.app.ActivityManager
|
|
import android.content.ActivityNotFoundException
|
|
import android.content.ClipboardManager
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.media.projection.MediaProjectionManager
|
|
import android.net.Uri
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import android.os.Handler
|
|
import android.os.Looper
|
|
import android.provider.Settings
|
|
import android.speech.RecognizerIntent
|
|
import android.text.Editable
|
|
import android.text.TextWatcher
|
|
import android.util.Log
|
|
import android.view.View
|
|
import android.widget.Toast
|
|
import androidx.activity.OnBackPressedCallback
|
|
import androidx.activity.enableEdgeToEdge
|
|
import androidx.activity.result.contract.ActivityResultContracts
|
|
import androidx.appcompat.app.AppCompatActivity
|
|
import androidx.core.view.ViewCompat
|
|
import androidx.core.view.WindowInsetsCompat
|
|
import com.assimilate.alltrans.MyApp
|
|
import com.assimilate.alltrans.R
|
|
import com.assimilate.alltrans.allservice.SusService
|
|
import com.assimilate.alltrans.common.AppStore
|
|
import com.assimilate.alltrans.common.FirebaseAnalyticsHelper
|
|
import com.assimilate.alltrans.common.LolAdWrapper
|
|
import com.assimilate.alltrans.common.Widget
|
|
import com.assimilate.alltrans.databinding.ActivityMainBinding
|
|
import com.assimilate.alltrans.model.LanguagesConstants
|
|
import com.assimilate.alltrans.model.PreferenceLanguageUtils
|
|
|
|
class MainActivity : AppCompatActivity() {
|
|
|
|
private var isBackPressedOnce = false
|
|
private var serverIsStart = false
|
|
private val backPressHandler = Handler(Looper.getMainLooper())
|
|
|
|
private var launcher = registerForActivityResult(
|
|
ActivityResultContracts.StartActivityForResult()
|
|
) { result ->
|
|
if (result.resultCode == RESULT_OK && result.data != null) {
|
|
val speech =
|
|
result.data!!.getStringArrayListExtra("android.speech.extra.RESULTS")?.get(0)
|
|
|
|
if (speech != null) {
|
|
binding.etText.setText(speech)
|
|
} else {
|
|
FirebaseAnalyticsHelper.textVoiceResultEvent(
|
|
MyApp.Config.FAIL_REASON,
|
|
"speech_is_null"
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
private lateinit var binding: ActivityMainBinding
|
|
|
|
private lateinit var mediaProjectionManager: MediaProjectionManager
|
|
private val REQUEST_CODE_OVERLAY = 1011
|
|
private val REQUEST_CODE_MEDIA_PROJECTION = 1012
|
|
|
|
private val mpResultCode = "mpResultCode"
|
|
private val mpData = "mpData"
|
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
enableEdgeToEdge()
|
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
|
setContentView(binding.root)
|
|
|
|
|
|
|
|
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
|
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
|
v.setPadding(26, systemBars.top + 26, 26, systemBars.bottom)
|
|
insets
|
|
}
|
|
initSet()
|
|
|
|
initClick()
|
|
|
|
}
|
|
|
|
|
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
super.onActivityResult(requestCode, resultCode, data)
|
|
|
|
if (requestCode == REQUEST_CODE_OVERLAY) {
|
|
// 检查悬浮窗权限是否已授予
|
|
if (Settings.canDrawOverlays(this)) {
|
|
checkAndRequestMediaProjectionPermission()
|
|
} else {
|
|
Widget.makeToast(this, "To allow floating windows for quick translation.")
|
|
}
|
|
} else if (requestCode == REQUEST_CODE_MEDIA_PROJECTION) {
|
|
// 处理mediaProjectionManager权限请求结果
|
|
if (resultCode == RESULT_OK) {
|
|
serverIsStart = true
|
|
binding.ivQuickStart.setImageResource(R.drawable.main_setting_quick)
|
|
|
|
|
|
// 权限授予,启动截图
|
|
val serviceIntent = Intent(this, SusService::class.java).apply {
|
|
putExtra(mpResultCode, resultCode)
|
|
putExtra(mpData, data)
|
|
}
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
startForegroundService(serviceIntent)
|
|
} else {
|
|
startService(serviceIntent)
|
|
}
|
|
FirebaseAnalyticsHelper.hoverButtonAgreeEvent()
|
|
} else {
|
|
Widget.makeToast(
|
|
this,
|
|
"Please allow access to screen information to identify the content that needs translation."
|
|
)
|
|
FirebaseAnalyticsHelper.hoverButtonCancelEvent()
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun initView() {
|
|
LolAdWrapper.shared.loadAdShowNativeAd(
|
|
this,
|
|
"your_native_ad_placement",
|
|
binding.homeNative,
|
|
R.layout.ad_layout_admob_banner,
|
|
R.layout.ad_layout_max_banner
|
|
)
|
|
|
|
binding.chSourceLanguage.text = PreferenceLanguageUtils.getString("language_source")
|
|
binding.chTargetLanguage.text = PreferenceLanguageUtils.getString("language_target")
|
|
}
|
|
|
|
private fun initSet() {
|
|
|
|
loadNative()
|
|
|
|
val isRunning = isServiceRunning(this, SusService::class.java)
|
|
if (isRunning) {
|
|
binding.ivQuickStart.setImageResource(R.drawable.main_setting_quick)
|
|
|
|
} else {
|
|
binding.ivQuickStart.setImageResource(R.drawable.main_setting_quick_def)
|
|
Widget.startScaleAnimation(binding.ivQuickStart)
|
|
|
|
}
|
|
|
|
backPressedCall()
|
|
// 初始化截屏
|
|
mediaProjectionManager =
|
|
getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
|
|
FirebaseAnalyticsHelper.homePvEvent(MyApp.Config.CLICK_FROM, "create")
|
|
|
|
}
|
|
|
|
private fun initClick() {
|
|
binding.tvMainDic.setOnClickListener {
|
|
// startActivity(Intent(this,DicActivity::class.java))
|
|
}
|
|
|
|
binding.tvMainPhotoTrans.setOnClickListener {
|
|
startActivity(
|
|
Intent(this, PhotoImageActivity::class.java).putExtra("key_start_ph", "camera")
|
|
)
|
|
}
|
|
binding.tvMainVoice.setOnClickListener {
|
|
voiceToText()
|
|
toTextTransResult()
|
|
FirebaseAnalyticsHelper.textVoiceClickEvent()
|
|
}
|
|
binding.tvMainPaste.setOnClickListener {
|
|
pasteFromClipboard()
|
|
FirebaseAnalyticsHelper.textTransPasteEvent()
|
|
}
|
|
binding.tvMainTrans.setOnClickListener {
|
|
toTextTransResult()
|
|
FirebaseAnalyticsHelper.textTransClickEvent()
|
|
}
|
|
binding.ivMainSetting.setOnClickListener {
|
|
startActivity(
|
|
Intent(this, SettingsActivity::class.java)
|
|
)
|
|
}
|
|
binding.chSourceLanguage.setOnClickListener {
|
|
startActivity(
|
|
Intent(this, LanguageChangeActivity::class.java)
|
|
)
|
|
}
|
|
binding.chTargetLanguage.setOnClickListener {
|
|
val intentT = Intent(this, LanguageChangeActivity::class.java)
|
|
intentT.putExtra("choose_t", true)
|
|
startActivity(intentT)
|
|
}
|
|
binding.ivMainHistory.setOnClickListener {
|
|
intent = Intent(this, HistoryActivity::class.java)
|
|
intent.putExtra("remove", "remove_collection")
|
|
startActivity(
|
|
intent
|
|
)
|
|
FirebaseAnalyticsHelper.historyClickEvent()
|
|
}
|
|
binding.llQuickSet.setOnClickListener {
|
|
// startActivity(
|
|
// Intent(this, QuickSetActivity::class.java)
|
|
// )
|
|
}
|
|
binding.ivQuickStart.setOnClickListener {
|
|
if (!serverIsStart) {
|
|
// 检查并请求悬浮窗权限
|
|
if (!Settings.canDrawOverlays(this)) {
|
|
val intent = Intent(
|
|
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
|
Uri.parse("package:$packageName")
|
|
)
|
|
startActivityForResult(intent, REQUEST_CODE_OVERLAY)
|
|
} else {
|
|
FirebaseAnalyticsHelper.hoverLimitAgreeEvent()
|
|
checkAndRequestMediaProjectionPermission()
|
|
}
|
|
} else {
|
|
stopService(Intent(this, SusService::class.java))
|
|
|
|
serverIsStart = false
|
|
binding.ivQuickStart.setImageResource(R.drawable.main_setting_quick_def)
|
|
|
|
}
|
|
FirebaseAnalyticsHelper.hoverButtonClickEvent()
|
|
|
|
}
|
|
|
|
binding.ivMainExChange.setOnClickListener {
|
|
// 读取当前的源语言和目标语言
|
|
val currentSourceLanguage = PreferenceLanguageUtils.getString("language_source")
|
|
val currentTargetLanguage = PreferenceLanguageUtils.getString("language_target")
|
|
|
|
// 交换源语言和目标语言
|
|
PreferenceLanguageUtils.putString("language_source", currentTargetLanguage)
|
|
PreferenceLanguageUtils.putString("language_target", currentSourceLanguage)
|
|
|
|
// 更新界面显示
|
|
binding.chSourceLanguage.text = currentTargetLanguage
|
|
binding.chTargetLanguage.text = currentSourceLanguage
|
|
|
|
}
|
|
|
|
binding.etText.setOnClickListener {
|
|
FirebaseAnalyticsHelper.textInputEvent()
|
|
}
|
|
// 监听EditText的文本变化
|
|
binding.etText.addTextChangedListener(object : TextWatcher {
|
|
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
|
}
|
|
|
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
|
}
|
|
|
|
override fun afterTextChanged(s: Editable?) {
|
|
// 统计字符数并显示在 TextView 中
|
|
val charCount = s?.length ?: 0
|
|
// 截断逻辑
|
|
if (charCount > 1800) {
|
|
val truncatedText = s?.subSequence(0, 1800)
|
|
binding.etText.setText(truncatedText)
|
|
binding.etText.setSelection(1800) // 设置光标位置到文本末尾
|
|
}
|
|
// 根据EditText的内容显示或隐藏粘贴按钮
|
|
if (s.isNullOrEmpty()) {
|
|
binding.tvMainTrans.visibility = View.GONE
|
|
|
|
} else {
|
|
binding.tvMainTrans.visibility = View.VISIBLE
|
|
}
|
|
|
|
// 更新字符计数显示
|
|
val displayCharCount = if (charCount > 1800) 1800 else charCount
|
|
binding.tvMainLimitText.text = getString(R.string.main_limit_num, displayCharCount)
|
|
}
|
|
})
|
|
|
|
|
|
}
|
|
|
|
private fun checkAndRequestMediaProjectionPermission() {
|
|
// 启动截图
|
|
startActivityForResult(
|
|
mediaProjectionManager.createScreenCaptureIntent(),
|
|
REQUEST_CODE_MEDIA_PROJECTION
|
|
)
|
|
}
|
|
|
|
private fun toTextTransResult() {
|
|
if (binding.etText.text.isEmpty()) {
|
|
return
|
|
}
|
|
val intent = Intent(this, TextResultActivity::class.java)
|
|
intent.putExtra("source_text", binding.etText.text.toString())
|
|
startActivity(intent)
|
|
binding.etText.text = null
|
|
}
|
|
|
|
|
|
// 语音转文本
|
|
private fun voiceToText() {
|
|
val speechIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
|
|
speechIntent.putExtra(
|
|
RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS,
|
|
4000
|
|
) // 设置5秒的静默时间
|
|
speechIntent.putExtra(
|
|
RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS,
|
|
4000
|
|
) // 设置5秒的可能完全静默时间
|
|
|
|
|
|
// speechIntent.putExtra(
|
|
// "android.speech.extra.LANGUAGE_MODEL",
|
|
// MyApp.getSourceLanguage()
|
|
// )
|
|
val languageCode = LanguagesConstants.getInstance()
|
|
.getLanguageCodeByLanguage(PreferenceLanguageUtils.getString("language_source"), this)
|
|
speechIntent.putExtra(
|
|
"android.speech.extra.LANGUAGE",
|
|
languageCode
|
|
|
|
)
|
|
// speechIntent.putExtra(
|
|
// "android.speech.extra.LANGUAGE_PREFERENCE",
|
|
//
|
|
// )
|
|
try {
|
|
launcher.launch(speechIntent)
|
|
} catch (ea: ActivityNotFoundException) {
|
|
FirebaseAnalyticsHelper.textVoiceResultEvent(
|
|
MyApp.Config.FAIL_REASON,
|
|
"device_not_support"
|
|
)
|
|
Widget.makeToast(this, getString(R.string.main_voice_to_text))
|
|
|
|
}
|
|
}
|
|
|
|
private fun isServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
|
|
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
|
val services = activityManager.getRunningServices(Integer.MAX_VALUE)
|
|
|
|
for (service in services) {
|
|
if (serviceClass.name == service.service.className) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// 粘贴文本
|
|
private fun pasteFromClipboard() {
|
|
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
|
if (clipboard.hasPrimaryClip()) {
|
|
val clipData = clipboard.primaryClip
|
|
if (clipData != null && clipData.itemCount > 0) {
|
|
val item = clipData.getItemAt(0)
|
|
val pasteData = item.coerceToText(this).toString()
|
|
if (pasteData.isNotEmpty()) {
|
|
binding.etText.setText(pasteData)
|
|
binding.etText.requestFocus() // 获取焦点
|
|
toTextTransResult()
|
|
} else {
|
|
Toast.makeText(
|
|
this,
|
|
resources.getString(R.string.main_paste_empty),
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
|
|
}
|
|
} else {
|
|
Log.e("PasteFromClipboard", "No items in clipboard.")
|
|
}
|
|
} else {
|
|
Log.e("PasteFromClipboard", "Clipboard has no primary clip.")
|
|
}
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
initView()
|
|
}
|
|
|
|
override fun onRestart() {
|
|
super.onRestart()
|
|
FirebaseAnalyticsHelper.homePvEvent(MyApp.Config.CLICK_FROM, "cap")
|
|
}
|
|
|
|
override fun onDestroy() {
|
|
super.onDestroy()
|
|
launcher.unregister()
|
|
}
|
|
|
|
//定义手势返回
|
|
private fun backPressedCall() {
|
|
val callback = object : OnBackPressedCallback(true) {
|
|
override fun handleOnBackPressed() {
|
|
if (isBackPressedOnce) {
|
|
finishAffinity()
|
|
} else {
|
|
isBackPressedOnce = true
|
|
Toast.makeText(
|
|
applicationContext,
|
|
"Press the back again to exit.",
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
backPressHandler.postDelayed({ isBackPressedOnce = false }, 2000)
|
|
}
|
|
|
|
}
|
|
}
|
|
onBackPressedDispatcher.addCallback(this, callback)
|
|
}
|
|
|
|
private fun loadNative() {
|
|
LolAdWrapper.shared.loadAdShowNativeAd(
|
|
this,
|
|
MyApp.Config.home_native_auto,
|
|
binding.homeNative,
|
|
R.layout.ad_layout_admob_banner,
|
|
R.layout.ad_layout_max_banner
|
|
)
|
|
}
|
|
|
|
} |