version 1.0.5 release

This commit is contained in:
Simon 2024-08-16 18:29:50 +08:00
parent 50225a3cfe
commit 3de6d92a64
40 changed files with 1334 additions and 433 deletions

View File

@ -2,5 +2,8 @@
在线
语言识别
文本识别
语音翻译
拍照翻译
悬浮窗翻译
辞典

View File

@ -15,8 +15,9 @@ android {
applicationId = "com.assimilate.alltrans"
minSdk = 23
targetSdk = 34
versionCode = 3
versionName = "1.0.3"
// 该打 6
versionCode = 5
versionName = "1.0.5"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@ -76,14 +77,10 @@ dependencies {
// Import the BoM for the Firebase platform
implementation(platform("com.google.firebase:firebase-bom:33.1.1"))
// Add the dependencies for the Crashlytics and Analytics libraries
// When using the BoM, you don't specify versions in Firebase library dependencies
implementation("com.google.firebase:firebase-crashlytics")
implementation("com.google.firebase:firebase-analytics")
implementation("com.google.firebase:firebase-config")
// To recognize Latin script
implementation("com.google.mlkit:text-recognition:16.0.0")
// To recognize Chinese script

View File

@ -261,7 +261,6 @@
}
},
"config": [
[
"admob_inst",
{
@ -324,6 +323,51 @@
}
]
},
"alltrans_directory_int_auto": {
"data": [
{
"after_click": {
"admob_inst": "keep",
"max_inst": "keep"
},
"block": {
"admob_inst": {
"delay": 0,
"rate": 0
},
"max_inst": {
"delay": 0,
"rate": 0
}
},
"close": {
"admob_inst": {
"delay": 0,
"rate": 0
},
"max_inst": {
"delay": 0,
"rate": 0
}
},
"config": [
[
"admob_inst",
{
"ca-app-pub-9280511366580942/1975489976": 100
}
]
],
"limit": {
"admob_inst": 100,
"max_inst": 100
},
"cycle": 0,
"timeout": 15000,
"showIntervalEnable": false
}
]
},
"alltrans_home_native_auto": {
"data": [
{
@ -372,6 +416,54 @@
}
]
},
"alltrans_text_trans_native_auto": {
"data": [
{
"config": [
[
"admob_native",
{
"ca-app-pub-9280511366580942/6930403378": 100
}
]
],
"block": {
"admob_native": {
"delay": 0,
"rate": 0
},
"max_native": {
"delay": 0,
"rate": 0
}
},
"click": {
"admob_native": [
100,
100,
100,
100,
100
],
"max_native": [
100,
100,
100,
100,
100
]
},
"after_click": {
"admob_native": "next",
"max_native": "next"
},
"limit": {
"admob_native": 100,
"max_native": 100
}
}
]
},
"alltrans_backup_int_auto": {
"data": [
{
@ -417,4 +509,4 @@
}
]
}
}
}

View File

@ -14,6 +14,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
<application
@ -30,12 +31,12 @@
tools:targetApi="31">
<!-- Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713 -->
<!-- <meta-data-->
<!-- <meta-data-->
<!-- android:name="com.google.android.gms.ads.APPLICATION_ID"-->
<!-- android:value="ca-app-pub-3940256099942544~3347511713" />-->
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="@string/my_admob_app_id" />
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="@string/my_admob_app_id" />
<meta-data
android:name="applovin.sdk.key"
@ -45,7 +46,7 @@
<property
android:name="android.adservices.AD_SERVICES_CONFIG"
android:resource="@xml/ga_ad_services_config"
tools:replace="android:resource"/>
tools:replace="android:resource" />
<activity
android:name=".viewui.MainActivity"

View File

@ -9,7 +9,6 @@ import android.os.Build
import android.os.Bundle
import android.webkit.WebView
import com.assimilate.alltrans.common.AppStore
import com.assimilate.alltrans.common.CurrentActivityHolder
import com.assimilate.alltrans.common.RemoteConfigManager
import com.assimilate.alltrans.model.LanguagesConstants
import com.assimilate.alltrans.model.PreferenceLanguageUtils
@ -26,47 +25,46 @@ class MyApp : Application() {
private var activityReferences = 0
private var isActivityChangingConfigurations = false
var isFirstLaunch = true
var isFirstPremisiton = false
private fun registerActivityLifecycle() {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
CurrentActivityHolder.currentActivity = activity
}
override fun onActivityStarted(activity: Activity) {
CurrentActivityHolder.currentActivity = activity
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
if (isFirstLaunch) {
isFirstLaunch = false
} else {
// Log.d("MyApplication", "应用进入前台")
if (!isFirstLaunch) {
if (isFirstPremisiton) return
val intent = Intent(activity, WelActivity::class.java)
activity.startActivity(intent)
}
}
}
override fun onActivityResumed(activity: Activity) {
CurrentActivityHolder.currentActivity = activity
}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations;
isActivityChangingConfigurations = activity.isChangingConfigurations
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// The app goes to the background
isFirstLaunch = false
// Log.d("MyApplication", "应用进入后台")
}
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {
if (CurrentActivityHolder.currentActivity == activity) {
CurrentActivityHolder.currentActivity = null
}
}
})
}
@ -106,7 +104,7 @@ class MyApp : Application() {
override fun onCreate() {
super.onCreate()
instance = this
// ScreenUtils.init(this)
registerActivityLifecycle()
initAd()
setSystemLanguage()
@ -151,6 +149,8 @@ class MyApp : Application() {
// firebase_event_map_key
const val CLICK_FROM = "clickfrom"
const val FAIL_REASON = "failreason"
const val LAN_SOURCE = "source"
const val LAN_TARGET = "target"
// firebase_event_key
const val launchPv = "launch_pv"
@ -170,7 +170,6 @@ class MyApp : Application() {
const val textTransShare = "text_trans_share"
const val textTransLike = "text_trans_like"
const val hoverButtonClick = "hover_button_click"
const val hoverLimitAgree = "hover_limit_agree"
const val hoverButtonCancel = "hover_button_cancel"
@ -191,6 +190,10 @@ class MyApp : Application() {
const val historyClick = "history_click"
const val historyDelete = "history_delete"
const val directoryClick = "directory_click"
const val directoryTransClick = "directory_trans_click"
const val directoryTransResult = "directory_trans_result"
// google_ad_place
const val start_cold_int_auto = "start_cold_int_auto"
@ -200,9 +203,12 @@ class MyApp : Application() {
const val text_camera_int_auto = "text_camera_int_auto"
const val image_camera_int_auto = "image_camera_int_auto"
const val history_int_auto = "history_int_auto"
const val directory_int_auto = "directory_int_auto"
const val home_native_auto = "home_native_auto"
const val text_trans_native_auto = "text_trans_native_auto"
const val backup_int_auto = "backup_int_auto"
const val adKey = "alltrans"
const val adDefJson = """
{
@ -468,7 +474,6 @@ class MyApp : Application() {
}
},
"config": [
[
"admob_inst",
{
@ -531,6 +536,51 @@ class MyApp : Application() {
}
]
},
"alltrans_directory_int_auto": {
"data": [
{
"after_click": {
"admob_inst": "keep",
"max_inst": "keep"
},
"block": {
"admob_inst": {
"delay": 0,
"rate": 0
},
"max_inst": {
"delay": 0,
"rate": 0
}
},
"close": {
"admob_inst": {
"delay": 0,
"rate": 0
},
"max_inst": {
"delay": 0,
"rate": 0
}
},
"config": [
[
"admob_inst",
{
"ca-app-pub-9280511366580942/1975489976": 100
}
]
],
"limit": {
"admob_inst": 100,
"max_inst": 100
},
"cycle": 0,
"timeout": 15000,
"showIntervalEnable": false
}
]
},
"alltrans_home_native_auto": {
"data": [
{
@ -579,6 +629,54 @@ class MyApp : Application() {
}
]
},
"alltrans_text_trans_native_auto": {
"data": [
{
"config": [
[
"admob_native",
{
"ca-app-pub-9280511366580942/6930403378": 100
}
]
],
"block": {
"admob_native": {
"delay": 0,
"rate": 0
},
"max_native": {
"delay": 0,
"rate": 0
}
},
"click": {
"admob_native": [
100,
100,
100,
100,
100
],
"max_native": [
100,
100,
100,
100,
100
]
},
"after_click": {
"admob_native": "next",
"max_native": "next"
},
"limit": {
"admob_native": 100,
"max_native": 100
}
}
]
},
"alltrans_backup_int_auto": {
"data": [
{

View File

@ -23,7 +23,7 @@ class AppStore(context: Context) {
}
companion object {
private const val DEFAULT_INTERVAL_TIME: Long = 5000 // 默认间隔时间,单位毫秒
private const val DEFAULT_INTERVAL_TIME: Long = 3000 // 默认间隔时间,单位毫秒
private const val DEFAULT_WELCOME_MESSAGE: String = "" // 默认欢迎信息
}
}

View File

@ -1,7 +0,0 @@
package com.assimilate.alltrans.common
import android.app.Activity
object CurrentActivityHolder {
var currentActivity: Activity? = null
}

View File

@ -1,12 +1,12 @@
package com.assimilate.alltrans.common
import android.os.Bundle
import android.text.TextUtils
import com.assimilate.alltrans.BuildConfig
import com.assimilate.alltrans.MyApp
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase
import org.json.JSONObject
object FirebaseAnalyticsHelper {
private val firebaseAnalytics: FirebaseAnalytics by lazy {
@ -14,6 +14,10 @@ object FirebaseAnalyticsHelper {
}
private fun logCusEvent(eventName: String, params: Map<String, Any?>? = null) {
// if (BuildConfig.DEBUG) {
// // 在调试模式下不上传事件
// return
// }
val bundle = Bundle().apply {
params?.forEach { (key, value) ->
when (value) {
@ -44,12 +48,12 @@ object FirebaseAnalyticsHelper {
logCusEvent(MyApp.Config.textTransSwitch, params)
}
fun languageChooseEvent(from: String,value: String) {
fun languageChooseEvent(from: String, value: String) {
val params = mapOf(from to value)
logCusEvent(MyApp.Config.languageChoose, params)
}
fun languageFromEvent(clickFrom: String,value: String) {
fun languageFromEvent(clickFrom: String, value: String) {
val params = mapOf(clickFrom to value)
logCusEvent(MyApp.Config.languageFrom, params)
}
@ -58,7 +62,7 @@ object FirebaseAnalyticsHelper {
logCusEvent(MyApp.Config.textTransClick, null)
}
fun textTransResultEvent(result: String,value: String) {
fun textTransResultEvent(result: String, value: String) {
val params = mapOf(result to value)
logCusEvent(MyApp.Config.textTransResult, params)
}
@ -77,7 +81,7 @@ object FirebaseAnalyticsHelper {
}
fun textVoiceResultEvent(failReason: String,value: String) {
fun textVoiceResultEvent(failReason: String, value: String) {
val params = mapOf(failReason to value)
logCusEvent(MyApp.Config.textVoiceResult, params)
}
@ -133,7 +137,7 @@ object FirebaseAnalyticsHelper {
logCusEvent(MyApp.Config.hoverScreenDistrict, null)
}
fun imageClickEvent(clickFrom: String,value: String) {
fun imageClickEvent(clickFrom: String, value: String) {
val params = mapOf(clickFrom to value)
logCusEvent(MyApp.Config.imageClick, params)
}
@ -155,30 +159,42 @@ object FirebaseAnalyticsHelper {
logCusEvent(MyApp.Config.historyDelete, null)
}
fun hoverGlobalResultEvent(failReason: String,value: String) {
fun directoryClickEvent() {
logCusEvent(MyApp.Config.directoryClick, null)
}
fun directoryTransClickEvent() {
logCusEvent(MyApp.Config.directoryTransClick, null)
}
fun directoryTransResultEvent(failReason: String, value: String) {
val params = mapOf(failReason to value)
logCusEvent(MyApp.Config.directoryTransResult, params)
}
fun hoverGlobalResultEvent(failReason: String, value: String) {
val params = mapOf(failReason to value)
logCusEvent(MyApp.Config.hoverGlobalResult, params)
}
fun hoverDistrictResultEvent(failReason: String,value: String) {
fun hoverDistrictResultEvent(failReason: String, value: String) {
val params = mapOf(failReason to value)
logCusEvent(MyApp.Config.hoverDistrictResult, params)
}
fun imageCameraResultEvent(failReason: String,value: String) {
fun imageCameraResultEvent(failReason: String, value: String) {
val params = mapOf(failReason to value)
logCusEvent(MyApp.Config.imageCameraResult, params)
}
fun imagePhotoResultEvent(failReason: String,value: String) {
fun imagePhotoResultEvent(failReason: String, value: String) {
val params = mapOf(failReason to value)
logCusEvent(MyApp.Config.imagePhotoResult, params)
}
//
// oeran domo
// fun logEvent(eventName: String, myParam: Map<String, String>? = null) {
//
// val jsonObject = JSONObject()

View File

@ -3,20 +3,16 @@ package com.assimilate.alltrans.common
import android.app.Activity
import android.widget.FrameLayout
import com.assimilate.alltrans.MyApp
import com.google.android.gms.ads.interstitial.InterstitialAd
import com.lol.apex.ok.google.adlibrary.base.listener.AdLoadListener
import com.lol.apex.ok.google.adlibrary.base.listener.AdShowListener
import com.lol.apex.ok.google.adlibrary.base.listener.LolLoadError
import com.lol.apex.ok.google.adlibrary.base.listener.LolShowError
import com.lol.apex.ok.google.adlibrary.bean.AdType
import com.lol.apex.ok.google.adlibrary.inner.LOLAdsInnerDispatcher
import com.lol.apex.ok.google.adlibrary.inner.base.AdInnerLoadAdapter
import com.lol.apex.ok.google.adlibrary.inner.base.AdInnerShowAdapter
import com.lol.apex.ok.google.adlibrary.inst.InstAdCache
import com.lol.apex.ok.google.adlibrary.inst.LOLAdsInstDispatcher
import com.lol.apex.ok.google.adlibrary.rewarded.LOLAdsRewardedDispatcher
class LolAdWrapper {
companion object {
@ -34,16 +30,18 @@ class LolAdWrapper {
fun closed() {}
}
// 有插屏缓存
fun hasCache(placement: String): Boolean {
return LOLAdsInstDispatcher.canShow(placement, false)
}
// 有激励缓存
fun hasRewardCache(placement: String): Boolean {
return LOLAdsRewardedDispatcher.canShow(placement)
}
private fun loadAd(act: Activity, placement: String, listener: LoLLoadListener? = null) {
// 无条件加载插屏
fun loadAd(act: Activity, placement: String, listener: LoLLoadListener? = null) {
if (act.isFinishing) return
LOLAdsInstDispatcher.getLoader(act, placement, object : AdLoadListener {
override fun onAdLoadFailed(error: LolLoadError?) {
@ -61,6 +59,7 @@ class LolAdWrapper {
}).loadAd()
}
//无条件加载激励
fun loadRewardAd(act: Activity, placement: String, listener: LoLLoadListener? = null) {
if (act.isFinishing) return
LOLAdsRewardedDispatcher.getLoader(act, placement, object : AdLoadListener {
@ -77,22 +76,40 @@ class LolAdWrapper {
}).loadAd()
}
//无缓存加载插屏
fun loadAdIfNotCached(act: Activity, placement: String, listener: LoLLoadListener? = null) {
if (act.isFinishing || hasCache(placement)) return
loadAd(act, placement, listener)
}
//有缓存(包含全局)展示
fun showAdIfCached(act: Activity, placement: String, listener: LolShowListener? = null) {
// if (act.isFinishing || !hasCache(placement)) {
//// val map = mutableMapOf(Pair(AnalysisUtil.PARAM_VALUE, "No cache for ads"))
//// AnalysisUtil.placeToLogEvent(placement, AnalysisAdState.AD_SHOW_FAILED, map)
// listener?.showFailed(LolShowError("No cache for ads"))
// } else {
// showAd(act, placement, listener)
// }
//判断当前广告位是否可以show不能show则判断补位广告是否可以show。
if (act.isFinishing || !hasCache(placement)) {
// val map = mutableMapOf(Pair(AnalysisUtil.PARAM_VALUE, "No cache for ads"))
// AnalysisUtil.placeToLogEvent(placement, AnalysisAdState.AD_SHOW_FAILED, map)
listener?.showFailed(LolShowError("No cache for ads"))
if (hasCache(MyApp.Config.backup_int_auto)) {
showAd(act, MyApp.Config.backup_int_auto, listener)
} else {
// val map = mutableMapOf(Pair(AnalysisUtil.PARAM_VALUE, "No cache for ads"))
// AnalysisUtil.placeToLogEvent(placement, AnalysisAdState.AD_SHOW_FAILED, map)
listener?.showFailed(LolShowError("No cache for ads"))
}
} else {
showAd(act, placement, listener)
}
}
// 带时间带缓存展示
fun showAdTiming(act: Activity, placement: String, listener: LolShowListener? = null) {
//当前时间减去旧时间,才展示广告满足间隔时间才show广告
if (System.currentTimeMillis() - MyApp.app.lastAdDisplayTime.get() >= AppStore(MyApp.app).showAdIntervalTime) {
@ -111,6 +128,47 @@ class LolAdWrapper {
}
}
// 无条件展示
private fun showAd(act: Activity, placement: String, listener: LolShowListener? = null) {
if (act.isFinishing) return
LOLAdsInstDispatcher.getShower(act, placement, object : AdShowListener {
override fun onAdClicked() {
MyApp.app.isAdShowing.set(true)
}
override fun onAdClosed() {
MyApp.app.isAdShowing.set(false)
listener?.closed()
}
override fun onAdRewarded() {}
override fun onAdShowFailed(error: LolShowError?) {
MyApp.app.isAdShowing.set(false)
//广告show失败打点
// val map = mutableMapOf(Pair(AnalysisUtil.PARAM_VALUE, "${error?.msg}"))
// AnalysisUtil.placeToLogEvent(placement, AnalysisAdState.AD_SHOW_FAILED, map)
listener?.showFailed(error)
}
override fun onAdShown() {
MyApp.app.isAdShowing.set(true)
listener?.shown()
// AnalysisUtil.placeToLogEvent(placement, AnalysisAdState.AD_SHOWN)
if (placement != MyApp.Config.start_cold_int_auto) {
MyApp.app.lastAdDisplayTime.set(System.currentTimeMillis())
}
}
override fun onAfterClickClosed() {}
override fun onDelayClosed() {}
}).showAd()
}
//加载展示原生
fun loadAdShowNativeAd(
context: Activity, nativeId: String, frameAd: FrameLayout, admobLayout: Int, maxLayout: Int
) {
@ -167,45 +225,6 @@ class LolAdWrapper {
})
}
private fun showAd(act: Activity, placement: String, listener: LolShowListener? = null) {
if (act.isFinishing) return
LOLAdsInstDispatcher.getShower(act, placement, object : AdShowListener {
override fun onAdClicked() {
MyApp.app.isAdShowing.set(true)
}
override fun onAdClosed() {
MyApp.app.isAdShowing.set(false)
listener?.closed()
}
override fun onAdRewarded() {}
override fun onAdShowFailed(error: LolShowError?) {
MyApp.app.isAdShowing.set(false)
//广告show失败打点
// val map = mutableMapOf(Pair(AnalysisUtil.PARAM_VALUE, "${error?.msg}"))
// AnalysisUtil.placeToLogEvent(placement, AnalysisAdState.AD_SHOW_FAILED, map)
listener?.showFailed(error)
}
override fun onAdShown() {
MyApp.app.isAdShowing.set(true)
listener?.shown()
// AnalysisUtil.placeToLogEvent(placement, AnalysisAdState.AD_SHOWN)
if (placement != MyApp.Config.start_cold_int_auto) {
MyApp.app.lastAdDisplayTime.set(System.currentTimeMillis())
}
}
override fun onAfterClickClosed() {}
override fun onDelayClosed() {}
}).showAd()
}
}

View File

@ -4,10 +4,19 @@ import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.speech.tts.TextToSpeech
import android.speech.tts.UtteranceProgressListener
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.TextPaint
import android.text.TextUtils
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.text.style.UnderlineSpan
import android.util.Log
import android.view.View
import android.widget.TextView
import android.widget.Toast
import com.assimilate.alltrans.R
import com.assimilate.alltrans.model.LanguagesConstants
@ -21,6 +30,55 @@ object MyTextTools {
private lateinit var tts: TextToSpeech
// 分割文本,添加下划线并让其可点击
fun makeWordsClickableWithUnderline(
textView: TextView,
text: String,
listener: OnWordClickListener?
) {
val spannableStringBuilder = SpannableStringBuilder(text)
val words = text.split(" ".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
var start = 0
for (word in words) {
val end = start + word.length
spannableStringBuilder.setSpan(object : ClickableSpan() {
override fun onClick(widget: View) {
// Call the listener when the word is clicked
listener?.onWordClick(word)
}
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = Color.BLUE // Change text color on click
ds.isUnderlineText = false // Remove default underline
}
}, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
// Apply underline span
spannableStringBuilder.setSpan(
UnderlineSpan(),
start,
end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
start = end + 1 // Move start position for next word
}
textView.text = spannableStringBuilder
textView.movementMethod = LinkMovementMethod.getInstance() // Enable clicks
}
// Interface for click listener
interface OnWordClickListener {
fun onWordClick(word: String?)
}
// 添加历史
fun addToHistory(context: Context, rText: String, transResult: String?) {
val dbTranslation = DbTranslation(context)

View File

@ -88,7 +88,6 @@ class ScreenCaptureManager(private val context: Context) {
}
fun getImageReader(): ImageReader {
return imageReader
}
}

View File

@ -9,6 +9,7 @@ import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint
import android.util.Log
import com.assimilate.alltrans.MyApp
import com.assimilate.alltrans.curview.GraphicOverlay
import com.google.mlkit.vision.text.Text
import kotlin.math.max
@ -17,14 +18,19 @@ import kotlin.math.min
class TextGraphic(
overlay: GraphicOverlay?,
private val text: Text,
private val shouldGroupTextInBlocks: Boolean,
private val showLanguageTag: Boolean,
private val showConfidence: Boolean,
private val textShow: Boolean,
private val needTrans: Boolean,
private val fbFrom: String
) : GraphicOverlay.Graphic(overlay) {
private val shouldGroupRecognizedTextInBlocks: Boolean =
PreferenceUtils.shouldGroupRecognizedTextInBlocks(MyApp.applicationContext())
private val showLanguageTag: Boolean =
PreferenceUtils.showLanguageTag(MyApp.applicationContext())
private val showConfidence: Boolean =
PreferenceUtils.shouldShowTextConfidence(MyApp.applicationContext())
private val textPaint: TextPaint = TextPaint().apply {
color = TEXT_COLOR
textSize = TEXT_SIZE
@ -39,16 +45,25 @@ class TextGraphic(
MutableList(text.textBlocks.size) { !textShow }
private var isVisible: Boolean
private var isLoading: Boolean = false
// 翻译后的文本
private var translatedTextBlocks: List<String> = listOf()
init {
isVisible = textShow
if (needTrans) {
isLoading = true
TranslationManager(text, fbFrom) { translatedTextPairs ->
translatedTextBlocks = translatedTextPairs.map { it.first }
isLoading = false
// 可以同时打印原Text和翻译后的结果
translatedTextPairs.forEach { (translated, original) ->
Log.d("Translation", "Original: $original -> Translated: $translated")
}
postInvalidate()
}
}
@ -56,7 +71,6 @@ class TextGraphic(
postInvalidate()
}
private var translatedTextBlocks: List<String> = listOf()
override fun draw(canvas: Canvas) {
if (!isVisible) return
@ -67,10 +81,26 @@ class TextGraphic(
}
}
private fun drawLoadingIndicator(textBlock: Text.TextBlock, canvas: Canvas) {
val rect = RectF(textBlock.boundingBox)
val centerX = (rect.left + rect.right) / 2
val centerY = (rect.top + rect.bottom) / 2
val radius = min(rect.width(), rect.height()) / 4
val paint = Paint().apply {
color = Color.BLUE
style = Paint.Style.STROKE
strokeWidth = 8f
}
canvas.drawCircle(centerX, centerY, radius, paint)
}
private fun drawTextBlock(textBlock: Text.TextBlock, canvas: Canvas, index: Int) {
val translatedBlockText = translatedTextBlocks.getOrNull(index) ?: textBlock.text
if (shouldGroupTextInBlocks) {
if (shouldGroupRecognizedTextInBlocks) {
val rect = RectF(textBlock.boundingBox)
drawText(
getFormattedText(translatedBlockText, textBlock.recognizedLanguage, null),
@ -79,6 +109,9 @@ class TextGraphic(
textPaint
)
}
// if (isLoading) {
// drawLoadingIndicator(textBlock, canvas)
// }
}
override fun contains(x: Float, y: Float): Boolean {

View File

@ -17,9 +17,6 @@ import com.google.mlkit.vision.text.TextRecognizerOptionsInterface
class TextRecognitionProcessor(
private val context: Context,
textRecognizerOptions: TextRecognizerOptionsInterface,
private val textShow:Boolean,
private val needTrans: Boolean,
private val fbFrom:String,
private val callback: TextRecognitionCallback? = null
) : VisionProcessorBase<Text>(context) {
@ -29,10 +26,6 @@ class TextRecognitionProcessor(
}
private val textRecognizer: TextRecognizer = TextRecognition.getClient(textRecognizerOptions)
private val shouldGroupRecognizedTextInBlocks: Boolean =
PreferenceUtils.shouldGroupRecognizedTextInBlocks(context)
private val showLanguageTag: Boolean = PreferenceUtils.showLanguageTag(context)
private val showConfidence: Boolean = PreferenceUtils.shouldShowTextConfidence(context)
override fun stop() {
super.stop()
@ -44,30 +37,15 @@ class TextRecognitionProcessor(
}
override fun onSuccess(text: Text, graphicOverlay: GraphicOverlay) {
//
PreferenceLanguageUtils.putString("language_source", getMostFrequentLanguage(text))
graphicOverlay.add(
TextGraphic(
graphicOverlay,
text,
shouldGroupRecognizedTextInBlocks,
showLanguageTag,
showConfidence,
textShow,
needTrans,
fbFrom
)
)
logExtrasForTesting(text)
// 调用回调
callback?.onTextRecognized(text,graphicOverlay)
logExtrasForTesting(text)
}
override fun onFailure(e: Exception) {
callback?.onTextFailure(e)
Log.w(TAG, "Text detection failed.$e")
callback?.onTextFailure(e)
}
// 推测最可能的语言

View File

@ -2,6 +2,7 @@ package com.assimilate.alltrans.common
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import com.assimilate.alltrans.MyApp
import com.assimilate.alltrans.http.GoogleTranslator
import com.assimilate.alltrans.http.Translator
@ -18,6 +19,8 @@ class TranslationManager(
private val handler = Handler(Looper.getMainLooper())
private val executor = Executors.newSingleThreadExecutor()
private var translatedTextBlocks: MutableList<Pair<Int, String>> = mutableListOf()
private var errorShowed = false
init {
prepareTranslation()
@ -62,30 +65,45 @@ class TranslationManager(
translator.translate(param, object : GoogleTranslator.GoogleTranslateCallback {
override fun onResponse(result: String?, errorMessage: String?) {
if (result != null) {
translatedTextBlocks.add(Pair(index, result))
} else {
translatedTextBlocks.add(Pair(index, text.textBlocks[index].text))
}
handler.post {
if (result != null) {
translatedTextBlocks.add(Pair(index, result))
} else {
translatedTextBlocks.add(
Pair(
index,
text.textBlocks[index].text
)
)
}
if (translatedTextBlocks.size == text.textBlocks.size) {
handler.post {
if (translatedTextBlocks.size == text.textBlocks.size) {
callback(translatedTextBlocks.sortedBy { it.first }
.map { it.second to text.textBlocks[it.first].text })
}
}
}
override fun onFailure(errorMessage: String?) {
translatedTextBlocks.add(Pair(index, text.textBlocks[index].text))
if (translatedTextBlocks.size == text.textBlocks.size) {
handler.post {
handler.post {
translatedTextBlocks.add(Pair(index, text.textBlocks[index].text))
if (translatedTextBlocks.size == text.textBlocks.size) {
callback(translatedTextBlocks.sortedBy { it.first }
.map { it.second to text.textBlocks[it.first].text })
}
}
transFailEvent(errorMessage)
if (!errorShowed) {
Toast.makeText(
MyApp.applicationContext(),
errorMessage,
Toast.LENGTH_SHORT
).show()
transFailEvent(errorMessage)
errorShowed = true
}
}
}
})
}

View File

@ -53,7 +53,7 @@ public class Widget {
Animation.RELATIVE_TO_SELF, 0.5f, // 以自身中心X轴为缩放中心
Animation.RELATIVE_TO_SELF, 0.5f // 以自身中心Y轴为缩放中心
);
scaleAnimation.setDuration(700); // 动画持续时间单位为毫秒
scaleAnimation.setDuration(900); // 动画持续时间单位为毫秒
scaleAnimation.setFillAfter(true); // 动画结束后保持放大状态
scaleAnimation.setAnimationListener(new Animation.AnimationListener() {

View File

@ -117,35 +117,36 @@ class ControlView(private val context: Context) {
listener?.onCopyClick()
}
binding.tvSusPhoto.setOnClickListener {
val intent = Intent(context, PhotoImageActivity::class.java)
intent.putExtra("key_start_ph", "hover")
val pendingIntent = PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
pendingIntent.send()
removeControlView()
}
binding.tvSusDistrict.setOnClickListener {
binding.susControlRoot.visibility = View.GONE
Log.d("ControlViewManager", "District translation clicked")
listener?.onDistrictClick()
}
binding.ivSusHome.setOnClickListener {
Log.d("ControlViewManager", "Home clicked")
val intent = Intent(context, MainActivity::class.java)
binding.tvSusPhoto.setOnClickListener {
val intentPh = Intent(context, PhotoImageActivity::class.java)
intentPh.putExtra("sus_ph", "sus_ph")
val pendingIntent = PendingIntent.getActivity(
context,
0,
intent,
intentPh,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
pendingIntent.send()
removeControlView()
}
binding.ivSusHome.setOnClickListener {
val intentHome = Intent(context, MainActivity::class.java)
intentHome.putExtra("sus_home","sus_home")
val pendingIntent = PendingIntent.getActivity(
context,
0,
intentHome,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
pendingIntent.send()
removeControlView()
}
}

View File

@ -1,22 +1,25 @@
package com.assimilate.alltrans.curview
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.graphics.Bitmap
import android.graphics.PixelFormat
import android.media.Image
import android.media.ImageReader
import android.os.Build
import android.text.TextUtils
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import android.widget.TextView
import android.widget.Toast
import com.assimilate.alltrans.R
import com.assimilate.alltrans.common.MyTextTools
import com.assimilate.alltrans.common.TextGraphic
import com.assimilate.alltrans.common.TextRecognitionProcessor
import com.assimilate.alltrans.common.VisionImageProcessor
import com.assimilate.alltrans.databinding.LayoutSusCopyBinding
import com.google.android.material.snackbar.Snackbar
import com.google.mlkit.vision.text.Text
import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
import java.io.IOException
@ -39,7 +42,7 @@ class CopyTextView(private val context: Context) :
// 这里还需要调整
imageProcessor = TextRecognitionProcessor(
context,
ChineseTextRecognizerOptions.Builder().build(), true, false, "", this
ChineseTextRecognizerOptions.Builder().build(), this
)
val inflater = LayoutInflater.from(context)
@ -68,9 +71,8 @@ class CopyTextView(private val context: Context) :
removeView()
}
binding?.btSusCopyAll?.setOnClickListener {
MyTextTools.copyToClipboard(context, recognizedText.toString())
Log.d("gdsfsfsadf", recognizedText.toString())
copyToClipboard(recognizedText.toString())
// removeView()
}
@ -124,7 +126,6 @@ class CopyTextView(private val context: Context) :
imageProcessor!!.processBitmap(bitmap, binding?.susGraphicOverlay)
} else {
Log.e(
"SusService",
@ -136,29 +137,19 @@ class CopyTextView(private val context: Context) :
}
}
override fun onTextRecognized(text: Text, graphicOverlay: GraphicOverlay) {
recognizedText = text.text
graphicOverlay.add(
TextGraphic(
graphicOverlay,
text, true, false, ""
)
)
}
override fun onTextFailure(e: Exception) {
Log.d("copy_", e.toString())
// Log.d("copy_", e.toString())
}
// 复制到粘贴板
private fun copyToClipboard(text: String?) {
val tip = "Copied to clipboard!"
val tipNull = "Text is null!"
if (!TextUtils.isEmpty(text)) {
val clipboardManager =
context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipData = ClipData.newPlainText("targetValue", text)
clipboardManager.setPrimaryClip(clipData)
Toast.makeText(context, tip, Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(context, tipNull, Toast.LENGTH_SHORT).show()
}
}
}

View File

@ -19,6 +19,7 @@ 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
@ -63,7 +64,10 @@ class DistrictView(
} else {
WindowManager.LayoutParams.TYPE_PHONE
},
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
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
)
@ -128,6 +132,48 @@ class DistrictView(
}
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 = ""
@ -205,9 +251,11 @@ class DistrictView(
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"
}
}
}
@ -219,6 +267,7 @@ class DistrictView(
"district" + errorMessage.toString()
)
bindingSusDistrict.tvTrTarget.text = "Translation failed: $errorMessage"
}
}
})

View File

@ -21,12 +21,13 @@ import com.assimilate.alltrans.R
import com.assimilate.alltrans.common.TextGraphic
import com.assimilate.alltrans.common.TextRecognitionProcessor
import com.assimilate.alltrans.common.VisionImageProcessor
import com.google.mlkit.vision.text.Text
import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
import java.io.IOException
class FloatingView(
private val context: Context
) {
) : TextRecognitionProcessor.TextRecognitionCallback {
private var isAttachedToWindow = false
private var imageProcessor: VisionImageProcessor? = null
@ -57,7 +58,7 @@ class FloatingView(
// 初始化语言识别
imageProcessor = TextRecognitionProcessor(
context,
ChineseTextRecognizerOptions.Builder().build(), false, true, "float"
ChineseTextRecognizerOptions.Builder().build(), this
)
graphicOverlay = GraphicOverlay(context, null)
@ -159,13 +160,20 @@ class FloatingView(
hasCapturedScreenshot = false
}
try {
windowManager.removeView(graphicOverlay)
windowManager.updateViewLayout(imageView, params)
} catch (e: IllegalArgumentException) {
Log.e("FloatingView", "View not attached to window manager", e)
if (graphicOverlay?.isAttachedToWindow == true) {
try {
windowManager.removeView(graphicOverlay)
} catch (e: IllegalArgumentException) {
Log.e("FloatingView", "View not attached to window manager", e)
}
} else {
Log.e(
"FloatingView",
"Attempted to remove a view that is not attached to the window manager"
)
}
windowManager.updateViewLayout(imageView, params)
return true
}
@ -367,4 +375,17 @@ class FloatingView(
windowManager.addView(graphicOverlay, fullScreenParams)
}
}
override fun onTextRecognized(text: Text, graphicOverlay: GraphicOverlay) {
graphicOverlay.add(
TextGraphic(
graphicOverlay,
text,
false, true, "float"
)
)
}
override fun onTextFailure(e: Exception) {
}
}

View File

@ -11,14 +11,16 @@ import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import com.assimilate.alltrans.common.TextGraphic
import com.assimilate.alltrans.common.TextRecognitionProcessor
import com.assimilate.alltrans.common.VisionImageProcessor
import com.assimilate.alltrans.databinding.LayoutSusGlobalBinding
import com.google.mlkit.vision.text.Text
import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
import java.io.IOException
class GlobalView(private val context: Context) {
class GlobalView(private val context: Context) : TextRecognitionProcessor.TextRecognitionCallback {
private var imageProcessor: VisionImageProcessor? = null
@ -32,7 +34,7 @@ class GlobalView(private val context: Context) {
// 这里还需要调整
imageProcessor = TextRecognitionProcessor(
context,
ChineseTextRecognizerOptions.Builder().build(), true, true, "global"
ChineseTextRecognizerOptions.Builder().build(), this
)
bindingSubGlobal = LayoutSusGlobalBinding.inflate(LayoutInflater.from(context))
globalView = bindingSubGlobal.root
@ -125,5 +127,18 @@ class GlobalView(private val context: Context) {
}
}
override fun onTextRecognized(text: Text, graphicOverlay: GraphicOverlay) {
graphicOverlay.add(
TextGraphic(
graphicOverlay,
text,
true, true, "global"
)
)
}
override fun onTextFailure(e: Exception) {
}
}

View File

@ -297,7 +297,6 @@ public class GraphicOverlay extends View {
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
synchronized (lock) {
updateTransformationIfNeeded();

View File

@ -12,12 +12,8 @@ import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.Toast
import com.assimilate.alltrans.MyApp
import com.assimilate.alltrans.R
import com.assimilate.alltrans.common.CurrentActivityHolder
import com.assimilate.alltrans.common.LolAdWrapper
import com.assimilate.alltrans.databinding.LayoutSusSelectBinding
import com.lol.apex.ok.google.adlibrary.base.listener.LolShowError
class SelectionView(private val context: Context) {
private lateinit var binding: LayoutSusSelectBinding
@ -51,7 +47,10 @@ class SelectionView(private val context: Context) {
} else {
WindowManager.LayoutParams.TYPE_PHONE
},
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
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
)

View File

@ -12,6 +12,7 @@ object PreferenceLanguageUtils {
private const val KEY_RECENT_LANGUAGES = "recent_languages"
private const val MAX_RECENT_LANGUAGES = 5
private const val PREF_KEY_FIRST_TIME = "first_time"
private const val PREF_KEY_FIRST_ALLOW = "first_allow"
private val LANGUAGE_LIST_TYPE = object : TypeToken<List<Language>>() {}.type
@Volatile
@ -85,4 +86,19 @@ object PreferenceLanguageUtils {
fun setNotFirstTime() {
getSharedPreferences().edit().putBoolean(PREF_KEY_FIRST_TIME, false).apply()
}
// 检查是否是第一次进入应用
fun isFirstAllow(): Boolean {
return getSharedPreferences().getBoolean(PREF_KEY_FIRST_ALLOW, true)
}
// 设置已经不是第一次进入应用了
fun setNotFirstAllow() {
getSharedPreferences().edit().putBoolean(PREF_KEY_FIRST_ALLOW, false).apply()
}
}

View File

@ -1,86 +1,310 @@
package com.assimilate.alltrans.viewui
import android.os.AsyncTask
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.webkit.WebChromeClient
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.assimilate.alltrans.MyApp
import com.assimilate.alltrans.R
import org.json.JSONArray
import org.json.JSONException
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
import com.assimilate.alltrans.common.FirebaseAnalyticsHelper
import com.assimilate.alltrans.common.LolAdWrapper
import com.assimilate.alltrans.databinding.ActivityDicBinding
import com.lol.apex.ok.google.adlibrary.base.listener.LolLoadError
import com.lol.apex.ok.google.adlibrary.base.listener.LolShowError
import java.util.Locale
class DicActivity : AppCompatActivity() {
private lateinit var editTextWord: EditText
private lateinit var buttonSearch: Button
private lateinit var textViewDefinition: TextView
private lateinit var binding: ActivityDicBinding
private var isWikiIng = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dic)
editTextWord = findViewById(R.id.editTextWord)
buttonSearch = findViewById(R.id.buttonSearch)
textViewDefinition = findViewById(R.id.textViewDefinition)
buttonSearch.setOnClickListener {
val word = editTextWord.text.toString().trim()
if (word.isNotEmpty()) {
FetchDefinitionTask().execute(word)
}
binding = ActivityDicBinding.inflate(layoutInflater)
enableEdgeToEdge()
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.dic_root)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
// 初始化ProgressBar
binding.wikiProgressBar.visibility = View.GONE
adLoad(MyApp.Config.directory_int_auto)
intiClick()
backPressedCall()
}
private inner class FetchDefinitionTask : AsyncTask<String, Void, String?>() {
override fun doInBackground(vararg params: String): String? {
val word = params[0]
val apiUrl = "https://api.dictionaryapi.dev/api/v2/entries/en/$word"
return try {
val url = URL(apiUrl)
val urlConnection = url.openConnection() as HttpURLConnection
urlConnection.requestMethod = "GET"
val responseCode = urlConnection.responseCode
if (responseCode == HttpURLConnection.HTTP_OK) {
val inputStream = BufferedReader(InputStreamReader(urlConnection.inputStream))
val response = StringBuilder()
var inputLine: String?
while (inputStream.readLine().also { inputLine = it } != null) {
response.append(inputLine)
private fun intiClick() {
binding.ivDicMore.setOnClickListener {
// 创建 PopupMenu
val popupMenu = PopupMenu(this, it)
// 关联菜单资源文件
popupMenu.menuInflater.inflate(R.menu.popup_menu, popupMenu.menu)
// 设置菜单项点击事件
popupMenu.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) {
R.id.action_one -> {
if (binding.editTextWord.text.toString().isNotEmpty()) {
val url = generateWiktionaryUrl(binding.editTextWord.text.toString())
// 创建Intent
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(url)
}
// 启动浏览器
startActivity(intent)
} else {
Toast.makeText(this, R.string.dic_et, Toast.LENGTH_SHORT).show()
}
// 处理第一个菜单项的点击事件
true
}
inputStream.close()
response.toString()
} else {
null
else -> false
}
} catch (e: Exception) {
e.printStackTrace()
null
}
// 显示 PopupMenu
popupMenu.show()
}
binding.editTextWord.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
// 隐藏键盘
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(binding.editTextWord.windowToken, 0)
true
} else {
false
}
}
override fun onPostExecute(result: String?) {
if (result != null) {
try {
val jsonArray = JSONArray(result)
val jsonObject = jsonArray.getJSONObject(0)
val meanings = jsonObject.getJSONArray("meanings")
val meaning = meanings.getJSONObject(0)
val definitions = meaning.getJSONArray("definitions")
val definition = definitions.getJSONObject(0)
val definitionText = definition.getString("definition")
textViewDefinition.text = definitionText
} catch (e: JSONException) {
e.printStackTrace()
textViewDefinition.text = "Error parsing definition"
binding.ivDicBack.setOnClickListener {
showInstAdFromCache(MyApp.Config.directory_int_auto)
finish()
}
binding.buttonSearch.setOnClickListener {
val word = binding.editTextWord.text.toString().trim()
if (word.isNotEmpty()) {
if (!isWikiIng) {
getWeb(word)
} else {
Toast.makeText(this, R.string.dic_wikiing, Toast.LENGTH_SHORT).show()
}
} else {
textViewDefinition.text = "Definition not found"
Toast.makeText(this, R.string.dic_et, Toast.LENGTH_SHORT).show()
}
FirebaseAnalyticsHelper.directoryTransClickEvent()
}
}
private fun backPressedCall() {
val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
showInstAdFromCache(MyApp.Config.directory_int_auto)
finish()
}
}
onBackPressedDispatcher.addCallback(this, callback)
}
private fun getWeb(word: String) {
// 显示 ProgressBar
binding.wikiProgressBar.visibility = View.VISIBLE
isWikiIng = true
// 创建 WebView 实例并配置
val webView = createConfiguredWebView()
// 设置 WebView 浏览器客户端
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
// 注入 JavaScript 隐藏指定区域
injectJavaScript(view)
// 加载完成后隐藏 ProgressBar
binding.wikiProgressBar.visibility = View.GONE
isWikiIng = false
}
override fun onReceivedError(
view: WebView?,
request: WebResourceRequest?,
error: WebResourceError?
) {
super.onReceivedError(view, request, error)
// 加载失败后隐藏 ProgressBar
binding.wikiProgressBar.visibility = View.GONE
isWikiIng = false
FirebaseAnalyticsHelper.directoryTransResultEvent(
MyApp.Config.FAIL_REASON,
error.toString()
)
}
}
webView.webChromeClient = WebChromeClient()
// 设置 WebView 布局参数并添加到视图中
val params = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT
)
webView.layoutParams = params
binding.toUrl.addView(webView)
// 加载指定的 URL
webView.loadUrl(generateWiktionaryUrl(word))
}
// 创建并配置 WebView
private fun createConfiguredWebView(): WebView {
val webView = WebView(this)
val settings = webView.settings
settings.loadsImagesAutomatically = true
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
WebView.setWebContentsDebuggingEnabled(false)
return webView
}
// 注入 JavaScript 脚本隐藏指定区域
private fun injectJavaScript(view: WebView?) {
view?.loadUrl(
"""
javascript:(function() {
var mainTitle = document.getElementById('firstHeading');
if (mainTitle) {
mainTitle.style.color = 'rgb(16, 171, 251)';
mainTitle.style.fontWeight = 'bold';
mainTitle.style.fontSize = '43px';
}
var bodyContent = document.getElementById('bodyContent');
if (bodyContent) {
bodyContent.style.marginBottom = '55px';
}
var header = document.getElementsByClassName('minerva-header');
if (header.length > 0) {
header[0].style.display = 'none';
}
var footer = document.getElementsByClassName('post-content footer-content');
if (footer.length > 0) {
footer[0].style.display = 'none';
}
var minerva_footer = document.getElementsByClassName('mw-footer minerva-footer');
if (minerva_footer.length > 0) {
minerva_footer[0].style.display = 'none';
}
var last_modified_bar = document.getElementsByClassName('post-content last-modified-bar__content');
if (last_modified_bar.length > 0) {
last_modified_bar[0].style.display = 'none';
}
var actionsMenu = document.getElementsByClassName('page-actions-menu');
if (actionsMenu.length > 0) {
actionsMenu[0].style.display = 'none';
}
var editSections = document.getElementsByClassName('mw-editsection');
for (var i = 0; i < editSections.length; i++) {
editSections[i].style.display = 'none';
}
})();
""".trimIndent()
)
}
private fun generateWiktionaryUrl(word: String?): String {
// 检查传入的字符串是否为空或null
if (word.isNullOrBlank()) {
throw IllegalArgumentException("Word cannot be null or blank")
}
val language = try {
// 获取本地语言,若获取失败则抛出异常
Locale.getDefault().language
} catch (e: Exception) {
throw RuntimeException("Unable to retrieve the default language", e)
}
val lowerCaseWord = try {
// 将传入字符串转换为小写,若转换失败则抛出异常
word.lowercase(Locale.ROOT)
} catch (e: Exception) {
throw RuntimeException("Unable to convert word to lowercase", e)
}
return "https://$language.m.wiktionary.org/wiki/$lowerCaseWord"
}
private fun adLoad(place: String) {
// 加载广告
LolAdWrapper.shared.loadAdIfNotCached(
this,
place,
object : LolAdWrapper.LoLLoadListener {
override fun loadFailed(error: LolLoadError?) {
}
override fun loaded() {
// 处理加载成功
}
})
}
private fun showInstAdFromCache(place: String) {
// 如果需要立刻展示广告,可以调用展示方法
LolAdWrapper.shared.showAdIfCached(
this,
place,
object : LolAdWrapper.LolShowListener {
override fun shown() {
// 处理广告展示成功
}
override fun showFailed(error: LolShowError?) {
// 处理广告展示失败
finish()
}
override fun closed() {
// 处理广告关闭
finish()
}
})
}
}

View File

@ -121,16 +121,22 @@ class LanguageChangeActivity : AppCompatActivity() {
}
private fun handleLanguageSelection(language: Language) {
Log.d("LanguageChange", language.language)
// Log.d("LanguageChange", language.language)
if (lastTranslateLanguage) {
PreferenceLanguageUtils.putString("language_target", language.language)
FirebaseAnalyticsHelper.languageChooseEvent(
MyApp.Config.LAN_TARGET,
"target_${language.language}"
)
} else {
PreferenceLanguageUtils.putString("language_source", language.language)
FirebaseAnalyticsHelper.languageChooseEvent(
MyApp.Config.LAN_SOURCE,
"source_${language.language}"
)
}
FirebaseAnalyticsHelper.languageChooseEvent(
MyApp.Config.CLICK_FROM,
if (lastTranslateLanguage) "target_${language.language}" else "source_${language.language}"
)
FirebaseAnalyticsHelper.languageFromEvent(
MyApp.Config.CLICK_FROM,
if (lastTranslateLanguage) "home_target" else "home_source"

View File

@ -34,6 +34,7 @@ import com.assimilate.alltrans.databinding.ActivityMainBinding
import com.assimilate.alltrans.model.LanguagesConstants
import com.assimilate.alltrans.model.PreferenceLanguageUtils
import com.google.mlkit.nl.languageid.LanguageIdentification
import java.util.Locale
class MainActivity : AppCompatActivity() {
@ -100,6 +101,8 @@ class MainActivity : AppCompatActivity() {
Widget.makeToast(this, "To allow floating windows for quick translation.")
}
} else if (requestCode == REQUEST_CODE_MEDIA_PROJECTION) {
// 第一次授权后将正常走hot
MyApp.app.isFirstPremisiton = false
// 处理mediaProjectionManager权限请求结果
if (resultCode == RESULT_OK) {
serverIsStart = true
@ -128,10 +131,11 @@ class MainActivity : AppCompatActivity() {
}
private fun initView(){
private fun initView() {
binding.chSourceLanguage.text = PreferenceLanguageUtils.getString("language_source")
binding.chTargetLanguage.text = PreferenceLanguageUtils.getString("language_target")
}
private fun initSet() {
loadNative()
@ -156,7 +160,8 @@ class MainActivity : AppCompatActivity() {
private fun initClick() {
binding.tvMainDic.setOnClickListener {
// startActivity(Intent(this,DicActivity::class.java))
startActivity(Intent(this, DicActivity::class.java))
FirebaseAnalyticsHelper.directoryClickEvent()
}
binding.tvMainPhotoTrans.setOnClickListener {
@ -206,6 +211,7 @@ class MainActivity : AppCompatActivity() {
// )
}
binding.ivQuickStart.setOnClickListener {
if (!serverIsStart) {
// 检查并请求悬浮窗权限
if (!Settings.canDrawOverlays(this)) {
@ -214,6 +220,7 @@ class MainActivity : AppCompatActivity() {
Uri.parse("package:$packageName")
)
startActivityForResult(intent, REQUEST_CODE_OVERLAY)
MyApp.app.isFirstPremisiton = true
} else {
FirebaseAnalyticsHelper.hoverLimitAgreeEvent()
checkAndRequestMediaProjectionPermission()
@ -283,6 +290,7 @@ class MainActivity : AppCompatActivity() {
}
private fun checkAndRequestMediaProjectionPermission() {
// 启动截图
startActivityForResult(
mediaProjectionManager.createScreenCaptureIntent(),
@ -383,7 +391,7 @@ class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
initView()
initView()
}
override fun onRestart() {
@ -427,7 +435,7 @@ class MainActivity : AppCompatActivity() {
)
}
private fun reconText(text:String){
private fun reconText(text: String) {
val languageIdentifier = LanguageIdentification.getClient()
languageIdentifier.identifyLanguage(text)
.addOnSuccessListener { languageCode ->
@ -436,9 +444,11 @@ class MainActivity : AppCompatActivity() {
} else {
Log.i("dsafdsf", "Language: $languageCode")
val lan = LanguagesConstants.getInstance().getLanguageByLanguageCode(languageCode,this)
PreferenceLanguageUtils.putString("language_source",lan.language)
binding.chSourceLanguage.text = PreferenceLanguageUtils.getString("language_source")
val lan = LanguagesConstants.getInstance()
.getLanguageByLanguageCode(languageCode, this)
PreferenceLanguageUtils.putString("language_source", lan.language)
binding.chSourceLanguage.text =
PreferenceLanguageUtils.getString("language_source")
}
}
.addOnFailureListener {

View File

@ -37,16 +37,19 @@ import com.assimilate.alltrans.adapters.LanguageAdapter
import com.assimilate.alltrans.common.BitmapUtils
import com.assimilate.alltrans.common.FirebaseAnalyticsHelper
import com.assimilate.alltrans.common.LolAdWrapper
import com.assimilate.alltrans.common.TextGraphic
import com.assimilate.alltrans.model.Language
import com.assimilate.alltrans.model.LanguagesConstants
import com.assimilate.alltrans.model.PreferenceLanguageUtils
import com.assimilate.alltrans.common.TextRecognitionProcessor
import com.assimilate.alltrans.common.VisionImageProcessor
import com.assimilate.alltrans.common.Widget
import com.assimilate.alltrans.curview.GraphicOverlay
import com.assimilate.alltrans.databinding.ActivityStillImageBinding
import com.google.android.gms.common.annotation.KeepName
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.common.util.concurrent.ListenableFuture
import com.google.mlkit.vision.text.Text
import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
import com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions
import com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions
@ -62,7 +65,7 @@ import kotlin.math.max
import kotlin.math.min
@KeepName
class PhotoImageActivity : AppCompatActivity() {
class PhotoImageActivity : AppCompatActivity(), TextRecognitionProcessor.TextRecognitionCallback {
private var selectedMode = TEXT_RECOGNITION_CHINESE
private var selectedSize: String? = SIZE_SCREEN
@ -74,8 +77,10 @@ class PhotoImageActivity : AppCompatActivity() {
private lateinit var imageCapture: ImageCapture
private lateinit var outputDirectory: File
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
private var isFlashOn = false
private var fbFrom = "photo"
private var needReshoot = false
private val REQUEST_CAMERA_PERMISSION = 100
private lateinit var bottomSheetDialog: BottomSheetDialog
@ -151,7 +156,7 @@ class PhotoImageActivity : AppCompatActivity() {
}
private fun initView() {
private fun initView() {
binding.photoPreview.visibility = View.VISIBLE
@ -216,7 +221,7 @@ class PhotoImageActivity : AppCompatActivity() {
private fun initList() {
val languages: ArrayList<Language> = LanguagesConstants.getInstance().getList(this)
if (languages.isNotEmpty()) {
val adapter = LanguageAdapter(this, languages) { _, language ->
val myAdapter = LanguageAdapter(this, languages) { _, language ->
if (!chooseLanguage) {
PreferenceLanguageUtils.putString("language_source", language.language)
@ -245,9 +250,16 @@ class PhotoImageActivity : AppCompatActivity() {
binding.stillTargetLanguage.text =
PreferenceLanguageUtils.getString("language_target")
}
bottomSheetDialog.findViewById<RecyclerView>(R.id.list_languages)?.layoutManager =
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
bottomSheetDialog.findViewById<RecyclerView>(R.id.list_languages)?.adapter = adapter
bottomSheetDialog.findViewById<RecyclerView>(R.id.list_languages)?.apply {
layoutManager =
LinearLayoutManager(
this@PhotoImageActivity,
LinearLayoutManager.VERTICAL,
false
)
adapter = myAdapter
}
}
}
@ -257,11 +269,21 @@ class PhotoImageActivity : AppCompatActivity() {
startChooseImageIntentForResult()
FirebaseAnalyticsHelper.imageTransPhotoEvent()
}
binding.ivStillTake.setOnClickListener {
binding.photoPreview.visibility = View.VISIBLE
binding.ivReshoot.setOnClickListener {
needReshoot = false
binding.photoPreview.visibility = View.VISIBLE
binding.preview.setImageBitmap(null)
binding.graphicOverlay.clear()
}
binding.ivStillTake.setOnClickListener {
if (needReshoot) return@setOnClickListener
binding.photoPreview.visibility = View.VISIBLE
takePhoto()
FirebaseAnalyticsHelper.imageTransCameraEvent()
needReshoot = true
}
binding.ivStillBack.setOnClickListener {
showInstAdFromCache(MyApp.Config.image_camera_int_auto)
@ -413,31 +435,30 @@ class PhotoImageActivity : AppCompatActivity() {
private fun createImageProcessor() {
imageProcessor?.stop()
try {
imageProcessor = when (selectedMode) {
TEXT_RECOGNITION_CHINESE -> TextRecognitionProcessor(
this,
ChineseTextRecognizerOptions.Builder().build(), true, true, fbFrom
ChineseTextRecognizerOptions.Builder().build(), this
)
"Hindi", "Marathi", "Nepali", "Sanskrit" -> TextRecognitionProcessor(
this,
DevanagariTextRecognizerOptions.Builder().build(), true, true, fbFrom
DevanagariTextRecognizerOptions.Builder().build(), this
)
TEXT_RECOGNITION_JAPANESE -> TextRecognitionProcessor(
this,
JapaneseTextRecognizerOptions.Builder().build(), true, true, fbFrom
JapaneseTextRecognizerOptions.Builder().build(), this
)
TEXT_RECOGNITION_KOREAN -> TextRecognitionProcessor(
this,
KoreanTextRecognizerOptions.Builder().build(), true, true, fbFrom
KoreanTextRecognizerOptions.Builder().build(), this
)
else -> TextRecognitionProcessor(
this,
TextRecognizerOptions.Builder().build(), true, true, fbFrom
TextRecognizerOptions.Builder().build(), this
)
}
@ -586,6 +607,22 @@ class PhotoImageActivity : AppCompatActivity() {
private const val REQUEST_CHOOSE_IMAGE = 1001
}
override fun onTextRecognized(text: Text, graphicOverlay: GraphicOverlay) {
graphicOverlay.add(
TextGraphic(
graphicOverlay,
text,
true, true,
fbFrom
)
)
}
override fun onTextFailure(e: Exception) {
}
}

View File

@ -35,7 +35,6 @@ class QuickSetActivity : AppCompatActivity() {
}
private fun sliderSet() {
binding.slider1.setLabelFormatter { value ->
val percentage = ((value / 5) * 100).toInt()
"$percentage%"

View File

@ -2,18 +2,25 @@ package com.assimilate.alltrans.viewui
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.Gravity
import android.view.MenuInflater
import android.view.View
import android.widget.RatingBar
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.assimilate.alltrans.R
import com.assimilate.alltrans.databinding.ActivitySettingsBinding
import com.google.android.material.bottomsheet.BottomSheetDialog
import java.util.Locale
class SettingsActivity
@ -22,6 +29,8 @@ class SettingsActivity
private lateinit var bottomSheetDialog: BottomSheetDialog
private var userChoose = 1
private val languageCodes = mutableListOf("en", "zh")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySettingsBinding.inflate(layoutInflater)
@ -44,6 +53,9 @@ class SettingsActivity
}
private fun initClick() {
// binding.llLanguages.setOnClickListener(this::showLanguagePopup)
binding.ivSetBack.setOnClickListener { finish() }
binding.llRate.setOnClickListener {
bottomSheetDialog.show()
@ -96,7 +108,7 @@ class SettingsActivity
private fun setBottomSheet() {
// 设置 BottomSheetDialog
bottomSheetDialog = BottomSheetDialog(this,R.style.CustomBottomSheetDialogTheme)
bottomSheetDialog = BottomSheetDialog(this, R.style.CustomBottomSheetDialogTheme)
bottomSheetDialog.setContentView(R.layout.bottomsheet_rate)
bottomSheetDialog.dismissWithAnimation = true
@ -145,4 +157,56 @@ class SettingsActivity
}
private fun showLanguagePopup(view: View) {
val popupMenu = PopupMenu(this, view, Gravity.END)
val inflater: MenuInflater = popupMenu.menuInflater
inflater.inflate(R.menu.language_menu, popupMenu.menu)
popupMenu.setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.language_english -> {
setLocale(languageCodes[0])
return@setOnMenuItemClickListener true
}
R.id.language_chinese -> {
setLocale(languageCodes[1])
return@setOnMenuItemClickListener true
}
else -> return@setOnMenuItemClickListener false
}
}
popupMenu.show()
}
private fun setLocale(lang: String) {
val locale = Locale(lang)
Locale.setDefault(locale)
val config = Configuration()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
config.setLocale(locale)
} else {
config.locale = locale
}
// 更新资源配置
resources.updateConfiguration(config, resources.displayMetrics)
// 创建新的配置上下文
baseContext.createConfigurationContext(config)
// // 保存用户选择的语言
// val editor = getSharedPreferences("Settings", MODE_PRIVATE).edit()
// editor.putString("My_Lang", lang)
// editor.apply()
// 重新启动Activity以应用语言更改
// val intent = Intent(this, SettingsActivity::class.java)
// startActivity(intent)
// finish()
}
}

View File

@ -47,6 +47,7 @@ class TextResultActivity : AppCompatActivity() {
}
private fun initSet() {
loadNative()
backPressedCall()
adLoad(MyApp.Config.text_trans_int_auto)
adLoad(MyApp.Config.text_new_int_auto)
@ -59,6 +60,16 @@ class TextResultActivity : AppCompatActivity() {
}
private fun loadNative() {
LolAdWrapper.shared.loadAdShowNativeAd(
this,
MyApp.Config.text_trans_native_auto,
binding.textNative,
R.layout.ad_layout_admob_banner,
R.layout.ad_layout_max_banner
)
}
private fun backPressedCall() {
val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
@ -70,6 +81,8 @@ class TextResultActivity : AppCompatActivity() {
}
private fun initClick() {
binding.ivTrBack.setOnClickListener {
showInstAdFromCache(MyApp.Config.text_trans_int_auto)
finish()
@ -86,7 +99,7 @@ class TextResultActivity : AppCompatActivity() {
MyTextTools.copyToClipboard(this, binding.tvTrTarget.text.toString())
FirebaseAnalyticsHelper.textTransCopyEvent()
}
binding.ivSourceClear.setOnClickListener { finish() }
// binding.ivSourceClear.setOnClickListener { finish() }
binding.ivSourceTts.setOnClickListener {
MyTextTools.ttsReadText(
binding.tvTrSource.text.toString(),
@ -201,7 +214,6 @@ class TextResultActivity : AppCompatActivity() {
}
private fun doBack() {
finish()
}
@ -247,7 +259,6 @@ class TextResultActivity : AppCompatActivity() {
doBack()
}
}
override fun closed() {

View File

@ -2,9 +2,9 @@ package com.assimilate.alltrans.viewui
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.ViewGroup
import android.widget.Button
import android.os.Handler
import android.os.Looper
import android.os.Message
import androidx.activity.OnBackPressedCallback
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
@ -17,14 +17,80 @@ import com.assimilate.alltrans.databinding.ActivityWelBinding
import com.lol.apex.ok.google.adlibrary.base.listener.LolLoadError
import com.lol.apex.ok.google.adlibrary.base.listener.LolShowError
class WelActivity : AppCompatActivity(){
class WelActivity : AppCompatActivity() {
companion object {
private const val MSG_PROGRESS = 0
private const val MSG_LOAD_AD_LOADED = 1
private const val MSG_LOAD_AD_FAIL = 2
}
private lateinit var binding: ActivityWelBinding
private val mMaxLoading = 10 * 1000L//最大超时
private var progress = 0f
private val delayMillis = mMaxLoading / 100
private var place: String = MyApp.Config.start_cold_int_auto
private val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
val progressBar = binding.customProgressBar
if (!isFinishing && !isDestroyed) {
when (msg.what) {
MSG_PROGRESS -> {
if (progress >= 100f) {//超时
//超时就是没有广告就是广告show失败了
toNextPage()
return
}
if (adCanShow()) {
//能展示走展示,移除进度,结束循环
sendEmptyMessageDelayed(MSG_LOAD_AD_LOADED, delayMillis)
removeMessages(MSG_PROGRESS)
return
}
// 继续加载进度,除非上面条件有成立
progress += 1
progressBar.progress = progress.toInt()
sendEmptyMessageDelayed(MSG_PROGRESS, delayMillis)
}
MSG_LOAD_AD_LOADED -> {
//展示广告,移除加载,移除进度条,结束循环
// if (progress >= 100f) {
showAd()
removeMessages(MSG_LOAD_AD_LOADED)
removeMessages(MSG_PROGRESS)
return
// }
// progress += 1
// progressBar.progress = progress.toInt()
// sendEmptyMessageDelayed(MSG_LOAD_AD_LOADED, delayMillis)
}
MSG_LOAD_AD_FAIL -> {
if (progress < 77f) {
progress = 77f
}
// 失败走进度条,移除失败
sendEmptyMessageDelayed(MSG_PROGRESS, delayMillis)
removeMessages(MSG_LOAD_AD_FAIL)
// removeMessages(MSG_PROGRESS)
}
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
binding = ActivityWelBinding.inflate(layoutInflater)
setContentView(binding.root)
//debugFirebase()
ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
@ -35,30 +101,20 @@ class WelActivity : AppCompatActivity(){
initSet()
}
private fun debugFirebase() {
val crashButton = Button(this)
crashButton.text = "Test Crash"
crashButton.setOnClickListener {
throw RuntimeException("Test Crash") // Force a crash
}
addContentView(
crashButton, ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
)
}
private fun initSet() {
backPressedCall()
if (MyApp.app.isFirstLaunch) {
adSplash(MyApp.Config.start_cold_int_auto)
} else {
adSplashHot(MyApp.Config.start_hot_int_auto)
}
}
// 判断走冷启动还是热启动广告
place = if (!MyApp.app.isFirstLaunch) {
MyApp.Config.start_cold_int_auto
} else {
MyApp.Config.start_hot_int_auto
}
//请求广告,启动进度条
loadAd()
handler.sendEmptyMessageDelayed(MSG_PROGRESS, delayMillis)
}
private fun backPressedCall() {
val callback = object : OnBackPressedCallback(true) {
@ -73,83 +129,45 @@ class WelActivity : AppCompatActivity(){
FirebaseAnalyticsHelper.launchPvEvent()
}
private fun toNextPage() {
startActivity(Intent(this@WelActivity, MainActivity::class.java))
// 热启动关闭加载页,冷启动进入主页
if (MyApp.app.isFirstLaunch) {
startActivity(Intent(this@WelActivity, MainActivity::class.java))
} else {
finish()
}
}
private fun adSplash(place: String) {
// 加载广告
LolAdWrapper.shared.loadAdIfNotCached(
private fun loadAd() {
LolAdWrapper.shared.loadAd(
this,
place,
object : LolAdWrapper.LoLLoadListener {
override fun loadFailed(error: LolLoadError?) {
// 处理加载失败
handler.sendEmptyMessage(MSG_LOAD_AD_FAIL)
}
})
LolAdWrapper.shared.loadAdIfNotCached(this, MyApp.Config.backup_int_auto)
}
private fun adCanShow(): Boolean {
return LolAdWrapper.shared.hasCache(place)
}
private fun showAd() {
LolAdWrapper.shared.showAdIfCached(
this,
place,
object : LolAdWrapper.LolShowListener {
override fun closed() {
toNextPage()
}
override fun loaded() {
// 处理加载成功
// 如果需要立刻展示广告,可以调用展示方法
LolAdWrapper.shared.showAdIfCached(
this@WelActivity,
place,
object : LolAdWrapper.LolShowListener {
override fun shown() {
// 处理广告展示成功
Log.d("fcasc", place)
}
override fun showFailed(error: LolShowError?) {
// 处理广告展示失败
toNextPage()
}
override fun closed() {
// 处理广告关闭
toNextPage()
}
})
override fun showFailed(error: LolShowError?) {
toNextPage()
}
})
}
private fun adSplashHot(place: String) {
// 加载广告
LolAdWrapper.shared.loadAdIfNotCached(
this,
place,
object : LolAdWrapper.LoLLoadListener {
override fun loadFailed(error: LolLoadError?) {
// 处理加载失败
finish()
}
override fun loaded() {
// 处理加载成功
// 如果需要立刻展示广告,可以调用展示方法
LolAdWrapper.shared.showAdIfCached(
this@WelActivity,
place,
object : LolAdWrapper.LolShowListener {
override fun shown() {
// 处理广告展示成功
}
override fun showFailed(error: LolShowError?) {
// 处理广告展示失败
finish()
}
override fun closed() {
// 处理广告关闭
finish()
}
})
}
})
}
}

View File

@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="270"
android:endColor="#FF1099FC"
android:angle="10"
android:startColor="#FF14CBF9"
android:type="linear" />
</shape>

View File

@ -1,25 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/dic_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/main_bg_ffe2efff"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/editTextWord"
android:layout_width="match_parent"
<ImageView
android:id="@+id/iv_dic_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Enter a word" />
android:padding="16dp"
android:src="@drawable/ic_back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_dic_more"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
android:src="@drawable/ic_dic_more"
app:layout_constraintBottom_toBottomOf="@id/tv_dic_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_dic_title" />
<Button
android:id="@+id/buttonSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Search" />
<TextView
android:id="@+id/textViewDefinition"
android:id="@+id/tv_dic_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="19dp"
android:text="@string/dic_title"
android:textColor="@color/main_text_ff1f1724"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:id="@+id/fl_e"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="30dp"
android:background="@drawable/button_r20_white_bg"
app:layout_constraintEnd_toStartOf="@id/buttonSearch"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_dic_title">
<EditText
android:id="@+id/editTextWord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:gravity="center|start"
android:hint="@string/dic_et"
android:imeOptions="actionDone"
android:inputType="text"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp" />
</FrameLayout>
<TextView
android:id="@+id/buttonSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="16dp"
android:background="@drawable/button_r24_blue_bg"
android:paddingStart="20dp"
android:paddingTop="7dp"
android:paddingEnd="20dp"
android:paddingBottom="7dp"
android:text="@string/dic_search"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="@id/fl_e"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/fl_e"
app:layout_constraintTop_toTopOf="@id/fl_e" />
<FrameLayout
android:id="@+id/to_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp" />
</LinearLayout>
android:layout_marginTop="30dp"
android:layout_marginBottom="40dp"
android:minHeight="500dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/fl_e">
</FrameLayout>
<android.widget.ProgressBar
android:id="@+id/wiki_progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@id/to_url"
app:layout_constraintEnd_toEndOf="@id/to_url"
app:layout_constraintStart_toStartOf="@id/to_url"
app:layout_constraintTop_toTopOf="@id/to_url" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -206,8 +206,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="@drawable/button_r20_white_bg"
android:minHeight="120dp" />
android:background="@drawable/button_r20_white_bg" />
<LinearLayout
android:id="@+id/ll_main_quick"
@ -254,7 +253,6 @@
android:visibility="gone"
app:drawableEndCompat="@drawable/ic_arrow_right" />
</LinearLayout>
<ImageView
@ -265,6 +263,7 @@
android:paddingTop="11dp"
android:paddingBottom="11dp"
android:src="@drawable/main_setting_quick_def" />
</LinearLayout>
<LinearLayout
@ -308,7 +307,6 @@
android:textColor="@color/main_text_ff1f1724"
android:textSize="14sp"
android:textStyle="bold"
android:visibility="gone"
app:drawableTopCompat="@drawable/main_dic" />
</LinearLayout>

View File

@ -61,6 +61,7 @@
android:paddingEnd="10dp"
android:src="@drawable/ic_still_pic" />
<ImageView
android:id="@+id/iv_still_take"
android:layout_width="0dp"
@ -69,15 +70,34 @@
android:layout_weight="1"
android:src="@drawable/ic_still_take" />
<ImageView
android:id="@+id/iv_still_buling"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_weight="1"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:src="@drawable/ic_still_notbuli" />
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_reshoot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_reshoot"
android:textColor="@color/white"
app:layout_constraintBottom_toTopOf="@+id/change_language"
app:layout_constraintEnd_toEndOf="parent" />
<ImageView
android:id="@+id/iv_still_buling"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginStart="16dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:src="@drawable/ic_still_notbuli" />
</LinearLayout>
</LinearLayout>

View File

@ -66,13 +66,13 @@
android:textSize="16sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/iv_source_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="12dp"
android:src="@drawable/ic_tr_close" />
<!-- <ImageView-->
<!-- android:id="@+id/iv_source_clear"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="center"-->
<!-- android:padding="12dp"-->
<!-- android:src="@drawable/ic_tr_close" />-->
</LinearLayout>
<ImageView
@ -148,6 +148,16 @@
</LinearLayout>
<FrameLayout
android:id="@+id/text_native"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="13dp"
android:layout_marginEnd="16dp"
android:background="@drawable/button_r20_white_bg"
app:layout_constraintTop_toBottomOf="@id/ll_main_enter_text" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"

View File

@ -8,6 +8,14 @@
android:background="@drawable/ic_wel_bg"
tools:context=".viewui.WelActivity">
<android.widget.ProgressBar
android:id="@+id/custom_progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -28,5 +36,4 @@
app:lottie_fileName="tran_wel_1.json"
app:lottie_loop="true" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -77,9 +77,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:padding="5dp"
android:layout_marginBottom="10dp"
android:src="@drawable/ic_voice"
android:visibility="invisible" />
android:src="@drawable/ic_voice" />
<View
@ -92,6 +92,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:autoLink="web"
android:linksClickable="true"
android:background="@android:color/transparent"
android:gravity="start|top"
android:maxLines="5"
@ -104,8 +106,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="horizontal"
android:visibility="invisible">
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_target_tts"
@ -123,13 +124,13 @@
android:layout_marginEnd="12dp"
android:src="@drawable/ic_copy" />
<ImageView
android:id="@+id/iv_tr_target_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="12dp"
android:src="@drawable/ic_share" />
<!-- <ImageView-->
<!-- android:id="@+id/iv_tr_target_share"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="center"-->
<!-- android:layout_marginEnd="12dp"-->
<!-- android:src="@drawable/ic_share" />-->
<ImageView
android:id="@+id/iv_tr_target_dic"
@ -137,6 +138,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="12dp"
android:visibility="invisible"
android:src="@drawable/ic_dic" />
<View

View File

@ -57,10 +57,17 @@
<!-- his_page-->
<string name="his_delete">Delete</string>
<string name="his_title">History</string>
<string name="his_emtpoy">Empty no history...</string>
<string name="his_emtpoy">Empty no history</string>
<string name="favor_title">Favorite</string>
<string name="favor_emtpoy">Empty no favorite...</string>
<string name="favor_emtpoy">Empty no favorite</string>
<string name="translate_now">Translate Now</string>
<!-- dic_page-->
<string name="dic_title">Directory</string>
<string name="dic_search">Search</string>
<string name="dic_et">Enter a word</string>
<string name="dic_wikiing">loading…</string>
<string name="dic_open_in">Open in browser</string>
<!--settings_page-->
<string name="settings">Settings</string>
@ -94,5 +101,9 @@
<string name="quick_set_kj_double">双击悬浮球</string>
<string name="fav_emp_description">Click the \"Favorite\" button at the end\nafter translation.\nEasily bookmark sentences.</string>
<!-- menu_choose_lan-->
<string name="language_english">English</string>
<string name="language_chinese">Chinese</string>
</resources>

View File

@ -8,7 +8,7 @@
<style name="Theme.Alltrans" parent="Base.Theme.Alltrans" />
<style name="CustomBottomSheetDialogTheme" parent="Theme.Material3.Light.BottomSheetDialog">
<item name="backgroundTint">@color/white</item>
<item name="android:background">@android:color/transparent</item>
</style>
</resources>