277 lines
11 KiB
Kotlin
277 lines
11 KiB
Kotlin
package com.assimilate.alltrans.curview
|
|
|
|
import android.content.Context
|
|
import android.graphics.Bitmap
|
|
import android.graphics.PixelFormat
|
|
import android.graphics.Rect
|
|
import android.media.ImageReader
|
|
import android.os.Build
|
|
import android.os.Handler
|
|
import android.os.Looper
|
|
import android.util.Log
|
|
import android.view.Gravity
|
|
import android.view.LayoutInflater
|
|
import android.view.MotionEvent
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import android.view.WindowManager
|
|
import com.assimilate.alltrans.MyApp
|
|
import com.assimilate.alltrans.R
|
|
import com.assimilate.alltrans.common.FirebaseAnalyticsHelper
|
|
import com.assimilate.alltrans.common.Logger
|
|
import com.assimilate.alltrans.common.MyTextTools
|
|
import com.assimilate.alltrans.databinding.LayoutSusDistrictBinding
|
|
import com.assimilate.alltrans.http.GoogleTranslator
|
|
import com.assimilate.alltrans.http.Translator
|
|
import com.assimilate.alltrans.model.LanguagesConstants
|
|
import com.assimilate.alltrans.model.PreferenceLanguageUtils
|
|
import com.google.mlkit.vision.common.InputImage
|
|
import com.google.mlkit.vision.text.TextRecognition
|
|
import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
|
|
import java.nio.ByteBuffer
|
|
|
|
class DistrictView(
|
|
private val context: Context
|
|
) {
|
|
private lateinit var bindingSusDistrict: LayoutSusDistrictBinding
|
|
private lateinit var districtView: View
|
|
private lateinit var overlayView: View
|
|
private val windowManager: WindowManager =
|
|
context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
|
|
|
fun showDistrictView(imageReader: ImageReader, startX: Int, startY: Int, endX: Int, endY: Int) {
|
|
// 添加一个全屏的透明背景视图
|
|
overlayView = View(context).apply {
|
|
layoutParams = ViewGroup.LayoutParams(
|
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
ViewGroup.LayoutParams.MATCH_PARENT
|
|
)
|
|
setBackgroundColor(0x00000000) // 全透明
|
|
setOnTouchListener { _, event ->
|
|
if (event.action == MotionEvent.ACTION_DOWN) {
|
|
removeDistrictView()
|
|
performClick()
|
|
}
|
|
true
|
|
}
|
|
}
|
|
|
|
val overlayParams = WindowManager.LayoutParams(
|
|
WindowManager.LayoutParams.MATCH_PARENT,
|
|
WindowManager.LayoutParams.MATCH_PARENT,
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
|
|
} else {
|
|
WindowManager.LayoutParams.TYPE_PHONE
|
|
},
|
|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
|
|
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
|
|
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
|
|
WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR,
|
|
PixelFormat.TRANSLUCENT
|
|
)
|
|
|
|
windowManager.addView(overlayView, overlayParams)
|
|
|
|
// 初始化 DistrictView
|
|
bindingSusDistrict = LayoutSusDistrictBinding.inflate(LayoutInflater.from(context))
|
|
districtView = bindingSusDistrict.root
|
|
|
|
val displayMetrics = context.resources.displayMetrics
|
|
val screenWidth = displayMetrics.widthPixels
|
|
val density = displayMetrics.density
|
|
val marginDp = 16
|
|
val marginPx = (marginDp * density).toInt()
|
|
|
|
val layoutParams = WindowManager.LayoutParams(
|
|
WindowManager.LayoutParams.MATCH_PARENT,
|
|
WindowManager.LayoutParams.MATCH_PARENT,
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
|
|
} else {
|
|
WindowManager.LayoutParams.TYPE_PHONE
|
|
},
|
|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
|
|
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
|
|
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
|
|
WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR,
|
|
PixelFormat.TRANSLUCENT
|
|
)
|
|
|
|
layoutParams.gravity = Gravity.TOP or Gravity.LEFT
|
|
layoutParams.x = marginPx
|
|
layoutParams.y = 100
|
|
layoutParams.width = screenWidth - 2 * marginPx
|
|
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT
|
|
|
|
windowManager.addView(districtView, layoutParams)
|
|
initDistrictClick()
|
|
|
|
// 获取最新的图像并处理
|
|
val image = imageReader.acquireLatestImage()
|
|
image?.let {
|
|
val planes = it.planes
|
|
if (planes.isNotEmpty()) {
|
|
val buffer: ByteBuffer = planes[0].buffer
|
|
val pixelStride: Int = planes[0].pixelStride
|
|
val rowStride: Int = planes[0].rowStride
|
|
val rowPadding: Int = rowStride - pixelStride * image.width
|
|
|
|
// 从缓冲区创建位图
|
|
val bitmap = Bitmap.createBitmap(
|
|
image.width + rowPadding / pixelStride, image.height, Bitmap.Config.ARGB_8888
|
|
)
|
|
bitmap.copyPixelsFromBuffer(buffer)
|
|
|
|
// 根据用户框选区域裁剪位图
|
|
val rect = Rect(startX, startY, endX, endY)
|
|
takeDistrictScreenshot(bitmap, rect)
|
|
}
|
|
image.close()
|
|
}
|
|
}
|
|
|
|
private fun initDistrictClick() {
|
|
bindingSusDistrict.ivSourceTts.setOnClickListener {
|
|
val lanSourceCode = LanguagesConstants.getInstance().getLanguageCodeByLanguage(
|
|
PreferenceLanguageUtils.getString("language_source"),
|
|
MyApp.applicationContext()
|
|
)
|
|
MyTextTools.ttsReadText(
|
|
bindingSusDistrict.tvTrSource.text.toString(), lanSourceCode, context
|
|
)
|
|
}
|
|
bindingSusDistrict.ivTrCopy.setOnClickListener {
|
|
MyTextTools.copyToClipboard(context, bindingSusDistrict.tvTrTarget.text.toString())
|
|
}
|
|
bindingSusDistrict.ivTrTargetDic.setOnClickListener {
|
|
if (bindingSusDistrict.tvTrTarget.text.toString().isNotEmpty()) {
|
|
MyTextTools.makeWordsClickableWithUnderline(
|
|
bindingSusDistrict.tvTrTarget,
|
|
bindingSusDistrict.tvTrTarget.text.toString(),
|
|
object : MyTextTools.OnWordClickListener {
|
|
override fun onWordClick(word: String?) {
|
|
Log.d("gvsdacd", "$word is clicked")
|
|
}
|
|
|
|
})
|
|
}
|
|
|
|
}
|
|
// bindingSusDistrict.ivTrTargetShare.setOnClickListener {
|
|
// MyTextTools.shareText(
|
|
// context,
|
|
// bindingSusDistrict.tvTrTarget.text.toString()
|
|
// )
|
|
// }
|
|
bindingSusDistrict.ivTargetTts.setOnClickListener {
|
|
val lanTargetCode = LanguagesConstants.getInstance().getLanguageCodeByLanguage(
|
|
PreferenceLanguageUtils.getString("language_target"),
|
|
MyApp.applicationContext()
|
|
)
|
|
|
|
MyTextTools.ttsReadText(
|
|
bindingSusDistrict.tvTrTarget.text.toString(), lanTargetCode, context
|
|
)
|
|
}
|
|
bindingSusDistrict.ivTrCollect.setOnClickListener { addCollect() }
|
|
bindingSusDistrict.ivSourceClear.setOnClickListener {
|
|
bindingSusDistrict.tvTrSource.text = ""
|
|
bindingSusDistrict.tvTrTarget.text = ""
|
|
removeDistrictView()
|
|
}
|
|
}
|
|
|
|
fun removeDistrictView() {
|
|
windowManager.removeView(districtView)
|
|
windowManager.removeView(overlayView)
|
|
|
|
}
|
|
|
|
private fun takeDistrictScreenshot(image: Bitmap, rect: Rect) {
|
|
if (rect.width() > 0 && rect.height() > 0) {
|
|
val croppedBitmap = Bitmap.createBitmap(
|
|
image,
|
|
rect.left,
|
|
rect.top,
|
|
rect.width(),
|
|
rect.height()
|
|
)
|
|
|
|
val recognizer =
|
|
TextRecognition.getClient(ChineseTextRecognizerOptions.Builder().build())
|
|
val imageNew = InputImage.fromBitmap(croppedBitmap, 0)
|
|
recognizer.process(imageNew)
|
|
.addOnSuccessListener { visionText ->
|
|
bindingSusDistrict.tvTrSource.text = visionText.text
|
|
// Add translation functionality here if needed
|
|
translate(visionText.text)
|
|
}
|
|
.addOnFailureListener { e ->
|
|
Log.e("DistrictView", "Text recognition failed", e)
|
|
}
|
|
} else {
|
|
Log.e("DistrictView", "Rect width or height is 0")
|
|
}
|
|
}
|
|
|
|
private fun addCollect() {
|
|
// Add collect functionality here
|
|
bindingSusDistrict.ivTrCollect.setImageResource(R.drawable.ic_like_yes)
|
|
}
|
|
|
|
private fun translate(text: String) {
|
|
if (text.isEmpty()) {
|
|
Logger.d("log", "translating(not post data)...")
|
|
return
|
|
}
|
|
|
|
val lanSourceCode = LanguagesConstants.getInstance().getLanguageCodeByLanguage(
|
|
PreferenceLanguageUtils.getString("language_source"),
|
|
MyApp.applicationContext()
|
|
)
|
|
val lanTargetCode = LanguagesConstants.getInstance().getLanguageCodeByLanguage(
|
|
PreferenceLanguageUtils.getString("language_target"),
|
|
MyApp.applicationContext()
|
|
)
|
|
|
|
val param = HashMap<String, String>().apply {
|
|
put("sourceLanguage", lanSourceCode)
|
|
put("translationLanguage", lanTargetCode)
|
|
put("text", text)
|
|
}
|
|
|
|
Handler(Looper.getMainLooper()).post {
|
|
bindingSusDistrict.tvTrTarget.text = "translating..."
|
|
}
|
|
|
|
val translator: Translator<GoogleTranslator.GoogleTranslateCallback> = GoogleTranslator()
|
|
translator.translate(param, object : GoogleTranslator.GoogleTranslateCallback {
|
|
override fun onResponse(result: String?, errorMessage: String?) {
|
|
Handler(Looper.getMainLooper()).post {
|
|
if (!result.isNullOrEmpty()) {
|
|
bindingSusDistrict.tvTrTarget.text = result
|
|
|
|
} else if (!errorMessage.isNullOrEmpty()) {
|
|
Log.e("TranslationError", errorMessage)
|
|
bindingSusDistrict.tvTrTarget.text = "Translation error: $errorMessage"
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onFailure(errorMessage: String?) {
|
|
Handler(Looper.getMainLooper()).post {
|
|
FirebaseAnalyticsHelper.hoverDistrictResultEvent(
|
|
MyApp.Config.FAIL_REASON,
|
|
"district" + errorMessage.toString()
|
|
)
|
|
bindingSusDistrict.tvTrTarget.text = "Translation failed: $errorMessage"
|
|
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
|
|
} |