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" applicationId = "com.assimilate.alltrans"
minSdk = 23 minSdk = 23
targetSdk = 34 targetSdk = 34
versionCode = 3 // 该打 6
versionName = "1.0.3" versionCode = 5
versionName = "1.0.5"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@ -76,14 +77,10 @@ dependencies {
// Import the BoM for the Firebase platform // Import the BoM for the Firebase platform
implementation(platform("com.google.firebase:firebase-bom:33.1.1")) 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-crashlytics")
implementation("com.google.firebase:firebase-analytics") implementation("com.google.firebase:firebase-analytics")
implementation("com.google.firebase:firebase-config") implementation("com.google.firebase:firebase-config")
// To recognize Latin script // To recognize Latin script
implementation("com.google.mlkit:text-recognition:16.0.0") implementation("com.google.mlkit:text-recognition:16.0.0")
// To recognize Chinese script // To recognize Chinese script

View File

@ -261,7 +261,6 @@
} }
}, },
"config": [ "config": [
[ [
"admob_inst", "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": { "alltrans_home_native_auto": {
"data": [ "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": { "alltrans_backup_int_auto": {
"data": [ "data": [
{ {

View File

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

View File

@ -9,7 +9,6 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.webkit.WebView import android.webkit.WebView
import com.assimilate.alltrans.common.AppStore import com.assimilate.alltrans.common.AppStore
import com.assimilate.alltrans.common.CurrentActivityHolder
import com.assimilate.alltrans.common.RemoteConfigManager import com.assimilate.alltrans.common.RemoteConfigManager
import com.assimilate.alltrans.model.LanguagesConstants import com.assimilate.alltrans.model.LanguagesConstants
import com.assimilate.alltrans.model.PreferenceLanguageUtils import com.assimilate.alltrans.model.PreferenceLanguageUtils
@ -26,47 +25,46 @@ class MyApp : Application() {
private var activityReferences = 0 private var activityReferences = 0
private var isActivityChangingConfigurations = false private var isActivityChangingConfigurations = false
var isFirstLaunch = true var isFirstLaunch = true
var isFirstPremisiton = false
private fun registerActivityLifecycle() { private fun registerActivityLifecycle() {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
CurrentActivityHolder.currentActivity = activity
} }
override fun onActivityStarted(activity: Activity) { override fun onActivityStarted(activity: Activity) {
CurrentActivityHolder.currentActivity = activity
if (++activityReferences == 1 && !isActivityChangingConfigurations) { if (++activityReferences == 1 && !isActivityChangingConfigurations) {
if (isFirstLaunch) { // Log.d("MyApplication", "应用进入前台")
isFirstLaunch = false if (!isFirstLaunch) {
} else { if (isFirstPremisiton) return
val intent = Intent(activity, WelActivity::class.java) val intent = Intent(activity, WelActivity::class.java)
activity.startActivity(intent) activity.startActivity(intent)
} }
} }
} }
override fun onActivityResumed(activity: Activity) { override fun onActivityResumed(activity: Activity) {}
CurrentActivityHolder.currentActivity = activity
}
override fun onActivityPaused(activity: Activity) {} override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) { override fun onActivityStopped(activity: Activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations; isActivityChangingConfigurations = activity.isChangingConfigurations
if (--activityReferences == 0 && !isActivityChangingConfigurations) { if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// The app goes to the background
isFirstLaunch = false
// Log.d("MyApplication", "应用进入后台")
} }
} }
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) { override fun onActivityDestroyed(activity: Activity) {
if (CurrentActivityHolder.currentActivity == activity) {
CurrentActivityHolder.currentActivity = null
}
} }
}) })
} }
@ -106,7 +104,7 @@ class MyApp : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
instance = this instance = this
// ScreenUtils.init(this)
registerActivityLifecycle() registerActivityLifecycle()
initAd() initAd()
setSystemLanguage() setSystemLanguage()
@ -151,6 +149,8 @@ class MyApp : Application() {
// firebase_event_map_key // firebase_event_map_key
const val CLICK_FROM = "clickfrom" const val CLICK_FROM = "clickfrom"
const val FAIL_REASON = "failreason" const val FAIL_REASON = "failreason"
const val LAN_SOURCE = "source"
const val LAN_TARGET = "target"
// firebase_event_key // firebase_event_key
const val launchPv = "launch_pv" const val launchPv = "launch_pv"
@ -170,7 +170,6 @@ class MyApp : Application() {
const val textTransShare = "text_trans_share" const val textTransShare = "text_trans_share"
const val textTransLike = "text_trans_like" const val textTransLike = "text_trans_like"
const val hoverButtonClick = "hover_button_click" const val hoverButtonClick = "hover_button_click"
const val hoverLimitAgree = "hover_limit_agree" const val hoverLimitAgree = "hover_limit_agree"
const val hoverButtonCancel = "hover_button_cancel" const val hoverButtonCancel = "hover_button_cancel"
@ -191,6 +190,10 @@ class MyApp : Application() {
const val historyClick = "history_click" const val historyClick = "history_click"
const val historyDelete = "history_delete" 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 // google_ad_place
const val start_cold_int_auto = "start_cold_int_auto" 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 text_camera_int_auto = "text_camera_int_auto"
const val image_camera_int_auto = "image_camera_int_auto" const val image_camera_int_auto = "image_camera_int_auto"
const val history_int_auto = "history_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 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 backup_int_auto = "backup_int_auto"
const val adKey = "alltrans" const val adKey = "alltrans"
const val adDefJson = """ const val adDefJson = """
{ {
@ -468,7 +474,6 @@ class MyApp : Application() {
} }
}, },
"config": [ "config": [
[ [
"admob_inst", "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": { "alltrans_home_native_auto": {
"data": [ "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": { "alltrans_backup_int_auto": {
"data": [ "data": [
{ {

View File

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

View File

@ -3,20 +3,16 @@ package com.assimilate.alltrans.common
import android.app.Activity import android.app.Activity
import android.widget.FrameLayout import android.widget.FrameLayout
import com.assimilate.alltrans.MyApp 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.AdLoadListener
import com.lol.apex.ok.google.adlibrary.base.listener.AdShowListener 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.LolLoadError
import com.lol.apex.ok.google.adlibrary.base.listener.LolShowError 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.LOLAdsInnerDispatcher
import com.lol.apex.ok.google.adlibrary.inner.base.AdInnerLoadAdapter 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.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.inst.LOLAdsInstDispatcher
import com.lol.apex.ok.google.adlibrary.rewarded.LOLAdsRewardedDispatcher import com.lol.apex.ok.google.adlibrary.rewarded.LOLAdsRewardedDispatcher
class LolAdWrapper { class LolAdWrapper {
companion object { companion object {
@ -34,16 +30,18 @@ class LolAdWrapper {
fun closed() {} fun closed() {}
} }
// 有插屏缓存
fun hasCache(placement: String): Boolean { fun hasCache(placement: String): Boolean {
return LOLAdsInstDispatcher.canShow(placement, false) return LOLAdsInstDispatcher.canShow(placement, false)
} }
// 有激励缓存
fun hasRewardCache(placement: String): Boolean { fun hasRewardCache(placement: String): Boolean {
return LOLAdsRewardedDispatcher.canShow(placement) 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 if (act.isFinishing) return
LOLAdsInstDispatcher.getLoader(act, placement, object : AdLoadListener { LOLAdsInstDispatcher.getLoader(act, placement, object : AdLoadListener {
override fun onAdLoadFailed(error: LolLoadError?) { override fun onAdLoadFailed(error: LolLoadError?) {
@ -61,6 +59,7 @@ class LolAdWrapper {
}).loadAd() }).loadAd()
} }
//无条件加载激励
fun loadRewardAd(act: Activity, placement: String, listener: LoLLoadListener? = null) { fun loadRewardAd(act: Activity, placement: String, listener: LoLLoadListener? = null) {
if (act.isFinishing) return if (act.isFinishing) return
LOLAdsRewardedDispatcher.getLoader(act, placement, object : AdLoadListener { LOLAdsRewardedDispatcher.getLoader(act, placement, object : AdLoadListener {
@ -77,22 +76,40 @@ class LolAdWrapper {
}).loadAd() }).loadAd()
} }
//无缓存加载插屏
fun loadAdIfNotCached(act: Activity, placement: String, listener: LoLLoadListener? = null) { fun loadAdIfNotCached(act: Activity, placement: String, listener: LoLLoadListener? = null) {
if (act.isFinishing || hasCache(placement)) return if (act.isFinishing || hasCache(placement)) return
loadAd(act, placement, listener) loadAd(act, placement, listener)
} }
//有缓存(包含全局)展示
fun showAdIfCached(act: Activity, placement: String, listener: LolShowListener? = null) { 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)) { if (act.isFinishing || !hasCache(placement)) {
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")) // val map = mutableMapOf(Pair(AnalysisUtil.PARAM_VALUE, "No cache for ads"))
// AnalysisUtil.placeToLogEvent(placement, AnalysisAdState.AD_SHOW_FAILED, map) // AnalysisUtil.placeToLogEvent(placement, AnalysisAdState.AD_SHOW_FAILED, map)
listener?.showFailed(LolShowError("No cache for ads")) listener?.showFailed(LolShowError("No cache for ads"))
}
} else { } else {
showAd(act, placement, listener) showAd(act, placement, listener)
} }
} }
// 带时间带缓存展示
fun showAdTiming(act: Activity, placement: String, listener: LolShowListener? = null) { fun showAdTiming(act: Activity, placement: String, listener: LolShowListener? = null) {
//当前时间减去旧时间,才展示广告满足间隔时间才show广告 //当前时间减去旧时间,才展示广告满足间隔时间才show广告
if (System.currentTimeMillis() - MyApp.app.lastAdDisplayTime.get() >= AppStore(MyApp.app).showAdIntervalTime) { 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( fun loadAdShowNativeAd(
context: Activity, nativeId: String, frameAd: FrameLayout, admobLayout: Int, maxLayout: Int 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.ClipboardManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Color
import android.speech.tts.TextToSpeech import android.speech.tts.TextToSpeech
import android.speech.tts.UtteranceProgressListener import android.speech.tts.UtteranceProgressListener
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.TextPaint
import android.text.TextUtils 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.util.Log
import android.view.View
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import com.assimilate.alltrans.R import com.assimilate.alltrans.R
import com.assimilate.alltrans.model.LanguagesConstants import com.assimilate.alltrans.model.LanguagesConstants
@ -21,6 +30,55 @@ object MyTextTools {
private lateinit var tts: TextToSpeech 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?) { fun addToHistory(context: Context, rText: String, transResult: String?) {
val dbTranslation = DbTranslation(context) val dbTranslation = DbTranslation(context)

View File

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

View File

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

View File

@ -17,9 +17,6 @@ import com.google.mlkit.vision.text.TextRecognizerOptionsInterface
class TextRecognitionProcessor( class TextRecognitionProcessor(
private val context: Context, private val context: Context,
textRecognizerOptions: TextRecognizerOptionsInterface, textRecognizerOptions: TextRecognizerOptionsInterface,
private val textShow:Boolean,
private val needTrans: Boolean,
private val fbFrom:String,
private val callback: TextRecognitionCallback? = null private val callback: TextRecognitionCallback? = null
) : VisionProcessorBase<Text>(context) { ) : VisionProcessorBase<Text>(context) {
@ -29,10 +26,6 @@ class TextRecognitionProcessor(
} }
private val textRecognizer: TextRecognizer = TextRecognition.getClient(textRecognizerOptions) 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() { override fun stop() {
super.stop() super.stop()
@ -44,30 +37,15 @@ class TextRecognitionProcessor(
} }
override fun onSuccess(text: Text, graphicOverlay: GraphicOverlay) { override fun onSuccess(text: Text, graphicOverlay: GraphicOverlay) {
//
PreferenceLanguageUtils.putString("language_source", getMostFrequentLanguage(text)) PreferenceLanguageUtils.putString("language_source", getMostFrequentLanguage(text))
graphicOverlay.add( logExtrasForTesting(text)
TextGraphic(
graphicOverlay,
text,
shouldGroupRecognizedTextInBlocks,
showLanguageTag,
showConfidence,
textShow,
needTrans,
fbFrom
)
)
// 调用回调 // 调用回调
callback?.onTextRecognized(text,graphicOverlay) callback?.onTextRecognized(text,graphicOverlay)
logExtrasForTesting(text)
} }
override fun onFailure(e: Exception) { override fun onFailure(e: Exception) {
callback?.onTextFailure(e)
Log.w(TAG, "Text detection failed.$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.Handler
import android.os.Looper import android.os.Looper
import android.widget.Toast
import com.assimilate.alltrans.MyApp import com.assimilate.alltrans.MyApp
import com.assimilate.alltrans.http.GoogleTranslator import com.assimilate.alltrans.http.GoogleTranslator
import com.assimilate.alltrans.http.Translator import com.assimilate.alltrans.http.Translator
@ -18,6 +19,8 @@ class TranslationManager(
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private val executor = Executors.newSingleThreadExecutor() private val executor = Executors.newSingleThreadExecutor()
private var translatedTextBlocks: MutableList<Pair<Int, String>> = mutableListOf() private var translatedTextBlocks: MutableList<Pair<Int, String>> = mutableListOf()
private var errorShowed = false
init { init {
prepareTranslation() prepareTranslation()
@ -62,30 +65,45 @@ class TranslationManager(
translator.translate(param, object : GoogleTranslator.GoogleTranslateCallback { translator.translate(param, object : GoogleTranslator.GoogleTranslateCallback {
override fun onResponse(result: String?, errorMessage: String?) { override fun onResponse(result: String?, errorMessage: String?) {
handler.post {
if (result != null) { if (result != null) {
translatedTextBlocks.add(Pair(index, result)) translatedTextBlocks.add(Pair(index, result))
} else { } else {
translatedTextBlocks.add(Pair(index, text.textBlocks[index].text)) translatedTextBlocks.add(
Pair(
index,
text.textBlocks[index].text
)
)
} }
if (translatedTextBlocks.size == text.textBlocks.size) { if (translatedTextBlocks.size == text.textBlocks.size) {
handler.post {
callback(translatedTextBlocks.sortedBy { it.first } callback(translatedTextBlocks.sortedBy { it.first }
.map { it.second to text.textBlocks[it.first].text }) .map { it.second to text.textBlocks[it.first].text })
} }
} }
} }
override fun onFailure(errorMessage: String?) { override fun onFailure(errorMessage: String?) {
handler.post {
translatedTextBlocks.add(Pair(index, text.textBlocks[index].text)) translatedTextBlocks.add(Pair(index, text.textBlocks[index].text))
if (translatedTextBlocks.size == text.textBlocks.size) { if (translatedTextBlocks.size == text.textBlocks.size) {
handler.post {
callback(translatedTextBlocks.sortedBy { it.first } callback(translatedTextBlocks.sortedBy { it.first }
.map { it.second to text.textBlocks[it.first].text }) .map { it.second to text.textBlocks[it.first].text })
} }
if (!errorShowed) {
Toast.makeText(
MyApp.applicationContext(),
errorMessage,
Toast.LENGTH_SHORT
).show()
transFailEvent(errorMessage)
errorShowed = true
} }
transFailEvent(errorMessage) }
} }
}) })
} }

View File

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

View File

@ -117,35 +117,36 @@ class ControlView(private val context: Context) {
listener?.onCopyClick() 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.tvSusDistrict.setOnClickListener {
binding.susControlRoot.visibility = View.GONE binding.susControlRoot.visibility = View.GONE
Log.d("ControlViewManager", "District translation clicked") Log.d("ControlViewManager", "District translation clicked")
listener?.onDistrictClick() listener?.onDistrictClick()
} }
binding.ivSusHome.setOnClickListener { binding.tvSusPhoto.setOnClickListener {
Log.d("ControlViewManager", "Home clicked") val intentPh = Intent(context, PhotoImageActivity::class.java)
val intent = Intent(context, MainActivity::class.java) intentPh.putExtra("sus_ph", "sus_ph")
val pendingIntent = PendingIntent.getActivity( val pendingIntent = PendingIntent.getActivity(
context, context,
0, 0,
intent, intentPh,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
) )
pendingIntent.send() 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 package com.assimilate.alltrans.curview
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.PixelFormat import android.graphics.PixelFormat
import android.media.Image import android.media.Image
import android.media.ImageReader import android.media.ImageReader
import android.os.Build import android.os.Build
import android.text.TextUtils
import android.util.Log import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.widget.TextView
import android.widget.Toast 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.TextRecognitionProcessor
import com.assimilate.alltrans.common.VisionImageProcessor import com.assimilate.alltrans.common.VisionImageProcessor
import com.assimilate.alltrans.databinding.LayoutSusCopyBinding 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.Text
import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
import java.io.IOException import java.io.IOException
@ -39,7 +42,7 @@ class CopyTextView(private val context: Context) :
// 这里还需要调整 // 这里还需要调整
imageProcessor = TextRecognitionProcessor( imageProcessor = TextRecognitionProcessor(
context, context,
ChineseTextRecognizerOptions.Builder().build(), true, false, "", this ChineseTextRecognizerOptions.Builder().build(), this
) )
val inflater = LayoutInflater.from(context) val inflater = LayoutInflater.from(context)
@ -68,9 +71,8 @@ class CopyTextView(private val context: Context) :
removeView() removeView()
} }
binding?.btSusCopyAll?.setOnClickListener { binding?.btSusCopyAll?.setOnClickListener {
MyTextTools.copyToClipboard(context, recognizedText.toString())
Log.d("gdsfsfsadf", recognizedText.toString())
copyToClipboard(recognizedText.toString())
// removeView() // removeView()
} }
@ -124,7 +126,6 @@ class CopyTextView(private val context: Context) :
imageProcessor!!.processBitmap(bitmap, binding?.susGraphicOverlay) imageProcessor!!.processBitmap(bitmap, binding?.susGraphicOverlay)
} else { } else {
Log.e( Log.e(
"SusService", "SusService",
@ -136,29 +137,19 @@ class CopyTextView(private val context: Context) :
} }
} }
override fun onTextRecognized(text: Text, graphicOverlay: GraphicOverlay) { override fun onTextRecognized(text: Text, graphicOverlay: GraphicOverlay) {
recognizedText = text.text recognizedText = text.text
graphicOverlay.add(
TextGraphic(
graphicOverlay,
text, true, false, ""
)
)
} }
override fun onTextFailure(e: Exception) { 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.R
import com.assimilate.alltrans.common.FirebaseAnalyticsHelper import com.assimilate.alltrans.common.FirebaseAnalyticsHelper
import com.assimilate.alltrans.common.Logger import com.assimilate.alltrans.common.Logger
import com.assimilate.alltrans.common.MyTextTools
import com.assimilate.alltrans.databinding.LayoutSusDistrictBinding import com.assimilate.alltrans.databinding.LayoutSusDistrictBinding
import com.assimilate.alltrans.http.GoogleTranslator import com.assimilate.alltrans.http.GoogleTranslator
import com.assimilate.alltrans.http.Translator import com.assimilate.alltrans.http.Translator
@ -63,7 +64,10 @@ class DistrictView(
} else { } else {
WindowManager.LayoutParams.TYPE_PHONE 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 PixelFormat.TRANSLUCENT
) )
@ -128,6 +132,48 @@ class DistrictView(
} }
private fun initDistrictClick() { 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.ivTrCollect.setOnClickListener { addCollect() }
bindingSusDistrict.ivSourceClear.setOnClickListener { bindingSusDistrict.ivSourceClear.setOnClickListener {
bindingSusDistrict.tvTrSource.text = "" bindingSusDistrict.tvTrSource.text = ""
@ -205,9 +251,11 @@ class DistrictView(
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
if (!result.isNullOrEmpty()) { if (!result.isNullOrEmpty()) {
bindingSusDistrict.tvTrTarget.text = result bindingSusDistrict.tvTrTarget.text = result
} else if (!errorMessage.isNullOrEmpty()) { } else if (!errorMessage.isNullOrEmpty()) {
Log.e("TranslationError", errorMessage) Log.e("TranslationError", errorMessage)
bindingSusDistrict.tvTrTarget.text = "Translation error: $errorMessage" bindingSusDistrict.tvTrTarget.text = "Translation error: $errorMessage"
} }
} }
} }
@ -219,6 +267,7 @@ class DistrictView(
"district" + errorMessage.toString() "district" + errorMessage.toString()
) )
bindingSusDistrict.tvTrTarget.text = "Translation failed: $errorMessage" 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.TextGraphic
import com.assimilate.alltrans.common.TextRecognitionProcessor import com.assimilate.alltrans.common.TextRecognitionProcessor
import com.assimilate.alltrans.common.VisionImageProcessor import com.assimilate.alltrans.common.VisionImageProcessor
import com.google.mlkit.vision.text.Text
import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
import java.io.IOException import java.io.IOException
class FloatingView( class FloatingView(
private val context: Context private val context: Context
) { ) : TextRecognitionProcessor.TextRecognitionCallback {
private var isAttachedToWindow = false private var isAttachedToWindow = false
private var imageProcessor: VisionImageProcessor? = null private var imageProcessor: VisionImageProcessor? = null
@ -57,7 +58,7 @@ class FloatingView(
// 初始化语言识别 // 初始化语言识别
imageProcessor = TextRecognitionProcessor( imageProcessor = TextRecognitionProcessor(
context, context,
ChineseTextRecognizerOptions.Builder().build(), false, true, "float" ChineseTextRecognizerOptions.Builder().build(), this
) )
graphicOverlay = GraphicOverlay(context, null) graphicOverlay = GraphicOverlay(context, null)
@ -159,13 +160,20 @@ class FloatingView(
hasCapturedScreenshot = false hasCapturedScreenshot = false
} }
if (graphicOverlay?.isAttachedToWindow == true) {
try { try {
windowManager.removeView(graphicOverlay) windowManager.removeView(graphicOverlay)
windowManager.updateViewLayout(imageView, params)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
Log.e("FloatingView", "View not attached to window manager", e) 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 return true
} }
@ -367,4 +375,17 @@ class FloatingView(
windowManager.addView(graphicOverlay, fullScreenParams) 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.LayoutInflater
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import com.assimilate.alltrans.common.TextGraphic
import com.assimilate.alltrans.common.TextRecognitionProcessor import com.assimilate.alltrans.common.TextRecognitionProcessor
import com.assimilate.alltrans.common.VisionImageProcessor import com.assimilate.alltrans.common.VisionImageProcessor
import com.assimilate.alltrans.databinding.LayoutSusGlobalBinding import com.assimilate.alltrans.databinding.LayoutSusGlobalBinding
import com.google.mlkit.vision.text.Text
import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
import java.io.IOException import java.io.IOException
class GlobalView(private val context: Context) { class GlobalView(private val context: Context) : TextRecognitionProcessor.TextRecognitionCallback {
private var imageProcessor: VisionImageProcessor? = null private var imageProcessor: VisionImageProcessor? = null
@ -32,7 +34,7 @@ class GlobalView(private val context: Context) {
// 这里还需要调整 // 这里还需要调整
imageProcessor = TextRecognitionProcessor( imageProcessor = TextRecognitionProcessor(
context, context,
ChineseTextRecognizerOptions.Builder().build(), true, true, "global" ChineseTextRecognizerOptions.Builder().build(), this
) )
bindingSubGlobal = LayoutSusGlobalBinding.inflate(LayoutInflater.from(context)) bindingSubGlobal = LayoutSusGlobalBinding.inflate(LayoutInflater.from(context))
globalView = bindingSubGlobal.root 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 @Override
protected void onDraw(Canvas canvas) { protected void onDraw(Canvas canvas) {
super.onDraw(canvas); super.onDraw(canvas);
synchronized (lock) { synchronized (lock) {
updateTransformationIfNeeded(); updateTransformationIfNeeded();

View File

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

View File

@ -12,6 +12,7 @@ object PreferenceLanguageUtils {
private const val KEY_RECENT_LANGUAGES = "recent_languages" private const val KEY_RECENT_LANGUAGES = "recent_languages"
private const val MAX_RECENT_LANGUAGES = 5 private const val MAX_RECENT_LANGUAGES = 5
private const val PREF_KEY_FIRST_TIME = "first_time" 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 private val LANGUAGE_LIST_TYPE = object : TypeToken<List<Language>>() {}.type
@Volatile @Volatile
@ -85,4 +86,19 @@ object PreferenceLanguageUtils {
fun setNotFirstTime() { fun setNotFirstTime() {
getSharedPreferences().edit().putBoolean(PREF_KEY_FIRST_TIME, false).apply() 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 package com.assimilate.alltrans.viewui
import android.os.AsyncTask import android.content.Intent
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.widget.Button import android.view.View
import android.widget.EditText import android.view.inputmethod.EditorInfo
import android.widget.TextView 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.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 com.assimilate.alltrans.R
import org.json.JSONArray import com.assimilate.alltrans.common.FirebaseAnalyticsHelper
import org.json.JSONException import com.assimilate.alltrans.common.LolAdWrapper
import java.io.BufferedReader import com.assimilate.alltrans.databinding.ActivityDicBinding
import java.io.InputStreamReader import com.lol.apex.ok.google.adlibrary.base.listener.LolLoadError
import java.net.HttpURLConnection import com.lol.apex.ok.google.adlibrary.base.listener.LolShowError
import java.net.URL import java.util.Locale
class DicActivity : AppCompatActivity() { class DicActivity : AppCompatActivity() {
private lateinit var editTextWord: EditText private lateinit var binding: ActivityDicBinding
private lateinit var buttonSearch: Button private var isWikiIng = false
private lateinit var textViewDefinition: TextView
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dic) 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
}
editTextWord = findViewById(R.id.editTextWord) // 初始化ProgressBar
buttonSearch = findViewById(R.id.buttonSearch) binding.wikiProgressBar.visibility = View.GONE
textViewDefinition = findViewById(R.id.textViewDefinition) adLoad(MyApp.Config.directory_int_auto)
buttonSearch.setOnClickListener { intiClick()
val word = editTextWord.text.toString().trim() backPressedCall()
}
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
}
else -> false
}
}
// 显示 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
}
}
binding.ivDicBack.setOnClickListener {
showInstAdFromCache(MyApp.Config.directory_int_auto)
finish()
}
binding.buttonSearch.setOnClickListener {
val word = binding.editTextWord.text.toString().trim()
if (word.isNotEmpty()) { if (word.isNotEmpty()) {
FetchDefinitionTask().execute(word) if (!isWikiIng) {
getWeb(word)
} else {
Toast.makeText(this, R.string.dic_wikiing, Toast.LENGTH_SHORT).show()
} }
} else {
Toast.makeText(this, R.string.dic_et, Toast.LENGTH_SHORT).show()
}
FirebaseAnalyticsHelper.directoryTransClickEvent()
} }
} }
private inner class FetchDefinitionTask : AsyncTask<String, Void, String?>() {
override fun doInBackground(vararg params: String): String? { private fun backPressedCall() {
val word = params[0] val callback = object : OnBackPressedCallback(true) {
val apiUrl = "https://api.dictionaryapi.dev/api/v2/entries/en/$word" override fun handleOnBackPressed() {
return try { showInstAdFromCache(MyApp.Config.directory_int_auto)
val url = URL(apiUrl) finish()
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)
} }
inputStream.close()
response.toString()
} else {
null
} }
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) { } catch (e: Exception) {
e.printStackTrace() throw RuntimeException("Unable to retrieve the default language", e)
null
}
} }
override fun onPostExecute(result: String?) { val lowerCaseWord = try {
if (result != null) { // 将传入字符串转换为小写,若转换失败则抛出异常
try { word.lowercase(Locale.ROOT)
val jsonArray = JSONArray(result) } catch (e: Exception) {
val jsonObject = jsonArray.getJSONObject(0) throw RuntimeException("Unable to convert word to lowercase", e)
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"
} }
} else {
textViewDefinition.text = "Definition not found" 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) { private fun handleLanguageSelection(language: Language) {
Log.d("LanguageChange", language.language) // Log.d("LanguageChange", language.language)
if (lastTranslateLanguage) { if (lastTranslateLanguage) {
PreferenceLanguageUtils.putString("language_target", language.language) PreferenceLanguageUtils.putString("language_target", language.language)
FirebaseAnalyticsHelper.languageChooseEvent(
MyApp.Config.LAN_TARGET,
"target_${language.language}"
)
} else { } else {
PreferenceLanguageUtils.putString("language_source", language.language) PreferenceLanguageUtils.putString("language_source", language.language)
}
FirebaseAnalyticsHelper.languageChooseEvent( FirebaseAnalyticsHelper.languageChooseEvent(
MyApp.Config.CLICK_FROM, MyApp.Config.LAN_SOURCE,
if (lastTranslateLanguage) "target_${language.language}" else "source_${language.language}" "source_${language.language}"
) )
}
FirebaseAnalyticsHelper.languageFromEvent( FirebaseAnalyticsHelper.languageFromEvent(
MyApp.Config.CLICK_FROM, MyApp.Config.CLICK_FROM,
if (lastTranslateLanguage) "home_target" else "home_source" 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.LanguagesConstants
import com.assimilate.alltrans.model.PreferenceLanguageUtils import com.assimilate.alltrans.model.PreferenceLanguageUtils
import com.google.mlkit.nl.languageid.LanguageIdentification import com.google.mlkit.nl.languageid.LanguageIdentification
import java.util.Locale
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
@ -100,6 +101,8 @@ class MainActivity : AppCompatActivity() {
Widget.makeToast(this, "To allow floating windows for quick translation.") Widget.makeToast(this, "To allow floating windows for quick translation.")
} }
} else if (requestCode == REQUEST_CODE_MEDIA_PROJECTION) { } else if (requestCode == REQUEST_CODE_MEDIA_PROJECTION) {
// 第一次授权后将正常走hot
MyApp.app.isFirstPremisiton = false
// 处理mediaProjectionManager权限请求结果 // 处理mediaProjectionManager权限请求结果
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
serverIsStart = true serverIsStart = true
@ -128,10 +131,11 @@ class MainActivity : AppCompatActivity() {
} }
private fun initView(){ private fun initView() {
binding.chSourceLanguage.text = PreferenceLanguageUtils.getString("language_source") binding.chSourceLanguage.text = PreferenceLanguageUtils.getString("language_source")
binding.chTargetLanguage.text = PreferenceLanguageUtils.getString("language_target") binding.chTargetLanguage.text = PreferenceLanguageUtils.getString("language_target")
} }
private fun initSet() { private fun initSet() {
loadNative() loadNative()
@ -156,7 +160,8 @@ class MainActivity : AppCompatActivity() {
private fun initClick() { private fun initClick() {
binding.tvMainDic.setOnClickListener { binding.tvMainDic.setOnClickListener {
// startActivity(Intent(this,DicActivity::class.java)) startActivity(Intent(this, DicActivity::class.java))
FirebaseAnalyticsHelper.directoryClickEvent()
} }
binding.tvMainPhotoTrans.setOnClickListener { binding.tvMainPhotoTrans.setOnClickListener {
@ -206,6 +211,7 @@ class MainActivity : AppCompatActivity() {
// ) // )
} }
binding.ivQuickStart.setOnClickListener { binding.ivQuickStart.setOnClickListener {
if (!serverIsStart) { if (!serverIsStart) {
// 检查并请求悬浮窗权限 // 检查并请求悬浮窗权限
if (!Settings.canDrawOverlays(this)) { if (!Settings.canDrawOverlays(this)) {
@ -214,6 +220,7 @@ class MainActivity : AppCompatActivity() {
Uri.parse("package:$packageName") Uri.parse("package:$packageName")
) )
startActivityForResult(intent, REQUEST_CODE_OVERLAY) startActivityForResult(intent, REQUEST_CODE_OVERLAY)
MyApp.app.isFirstPremisiton = true
} else { } else {
FirebaseAnalyticsHelper.hoverLimitAgreeEvent() FirebaseAnalyticsHelper.hoverLimitAgreeEvent()
checkAndRequestMediaProjectionPermission() checkAndRequestMediaProjectionPermission()
@ -283,6 +290,7 @@ class MainActivity : AppCompatActivity() {
} }
private fun checkAndRequestMediaProjectionPermission() { private fun checkAndRequestMediaProjectionPermission() {
// 启动截图 // 启动截图
startActivityForResult( startActivityForResult(
mediaProjectionManager.createScreenCaptureIntent(), mediaProjectionManager.createScreenCaptureIntent(),
@ -427,7 +435,7 @@ class MainActivity : AppCompatActivity() {
) )
} }
private fun reconText(text:String){ private fun reconText(text: String) {
val languageIdentifier = LanguageIdentification.getClient() val languageIdentifier = LanguageIdentification.getClient()
languageIdentifier.identifyLanguage(text) languageIdentifier.identifyLanguage(text)
.addOnSuccessListener { languageCode -> .addOnSuccessListener { languageCode ->
@ -436,9 +444,11 @@ class MainActivity : AppCompatActivity() {
} else { } else {
Log.i("dsafdsf", "Language: $languageCode") Log.i("dsafdsf", "Language: $languageCode")
val lan = LanguagesConstants.getInstance().getLanguageByLanguageCode(languageCode,this) val lan = LanguagesConstants.getInstance()
PreferenceLanguageUtils.putString("language_source",lan.language) .getLanguageByLanguageCode(languageCode, this)
binding.chSourceLanguage.text = PreferenceLanguageUtils.getString("language_source") PreferenceLanguageUtils.putString("language_source", lan.language)
binding.chSourceLanguage.text =
PreferenceLanguageUtils.getString("language_source")
} }
} }
.addOnFailureListener { .addOnFailureListener {

View File

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

View File

@ -2,18 +2,25 @@ package com.assimilate.alltrans.viewui
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.Gravity
import android.view.MenuInflater
import android.view.View
import android.widget.RatingBar import android.widget.RatingBar
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import com.assimilate.alltrans.R import com.assimilate.alltrans.R
import com.assimilate.alltrans.databinding.ActivitySettingsBinding import com.assimilate.alltrans.databinding.ActivitySettingsBinding
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import java.util.Locale
class SettingsActivity class SettingsActivity
@ -22,6 +29,8 @@ class SettingsActivity
private lateinit var bottomSheetDialog: BottomSheetDialog private lateinit var bottomSheetDialog: BottomSheetDialog
private var userChoose = 1 private var userChoose = 1
private val languageCodes = mutableListOf("en", "zh")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivitySettingsBinding.inflate(layoutInflater) binding = ActivitySettingsBinding.inflate(layoutInflater)
@ -44,6 +53,9 @@ class SettingsActivity
} }
private fun initClick() { private fun initClick() {
// binding.llLanguages.setOnClickListener(this::showLanguagePopup)
binding.ivSetBack.setOnClickListener { finish() } binding.ivSetBack.setOnClickListener { finish() }
binding.llRate.setOnClickListener { binding.llRate.setOnClickListener {
bottomSheetDialog.show() bottomSheetDialog.show()
@ -96,7 +108,7 @@ class SettingsActivity
private fun setBottomSheet() { private fun setBottomSheet() {
// 设置 BottomSheetDialog // 设置 BottomSheetDialog
bottomSheetDialog = BottomSheetDialog(this,R.style.CustomBottomSheetDialogTheme) bottomSheetDialog = BottomSheetDialog(this, R.style.CustomBottomSheetDialogTheme)
bottomSheetDialog.setContentView(R.layout.bottomsheet_rate) bottomSheetDialog.setContentView(R.layout.bottomsheet_rate)
bottomSheetDialog.dismissWithAnimation = true 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() { private fun initSet() {
loadNative()
backPressedCall() backPressedCall()
adLoad(MyApp.Config.text_trans_int_auto) adLoad(MyApp.Config.text_trans_int_auto)
adLoad(MyApp.Config.text_new_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() { private fun backPressedCall() {
val callback = object : OnBackPressedCallback(true) { val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
@ -70,6 +81,8 @@ class TextResultActivity : AppCompatActivity() {
} }
private fun initClick() { private fun initClick() {
binding.ivTrBack.setOnClickListener { binding.ivTrBack.setOnClickListener {
showInstAdFromCache(MyApp.Config.text_trans_int_auto) showInstAdFromCache(MyApp.Config.text_trans_int_auto)
finish() finish()
@ -86,7 +99,7 @@ class TextResultActivity : AppCompatActivity() {
MyTextTools.copyToClipboard(this, binding.tvTrTarget.text.toString()) MyTextTools.copyToClipboard(this, binding.tvTrTarget.text.toString())
FirebaseAnalyticsHelper.textTransCopyEvent() FirebaseAnalyticsHelper.textTransCopyEvent()
} }
binding.ivSourceClear.setOnClickListener { finish() } // binding.ivSourceClear.setOnClickListener { finish() }
binding.ivSourceTts.setOnClickListener { binding.ivSourceTts.setOnClickListener {
MyTextTools.ttsReadText( MyTextTools.ttsReadText(
binding.tvTrSource.text.toString(), binding.tvTrSource.text.toString(),
@ -201,7 +214,6 @@ class TextResultActivity : AppCompatActivity() {
} }
private fun doBack() { private fun doBack() {
finish() finish()
} }
@ -247,7 +259,6 @@ class TextResultActivity : AppCompatActivity() {
doBack() doBack()
} }
} }
override fun closed() { override fun closed() {

View File

@ -2,9 +2,9 @@ package com.assimilate.alltrans.viewui
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.os.Handler
import android.view.ViewGroup import android.os.Looper
import android.widget.Button import android.os.Message
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity 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.LolLoadError
import com.lol.apex.ok.google.adlibrary.base.listener.LolShowError 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 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?) { override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge() enableEdgeToEdge()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityWelBinding.inflate(layoutInflater) binding = ActivityWelBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
//debugFirebase()
ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets -> ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
@ -35,30 +101,20 @@ class WelActivity : AppCompatActivity(){
initSet() 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() { private fun initSet() {
backPressedCall() 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() { private fun backPressedCall() {
val callback = object : OnBackPressedCallback(true) { val callback = object : OnBackPressedCallback(true) {
@ -73,83 +129,45 @@ class WelActivity : AppCompatActivity(){
FirebaseAnalyticsHelper.launchPvEvent() FirebaseAnalyticsHelper.launchPvEvent()
} }
private fun toNextPage() { private fun toNextPage() {
// 热启动关闭加载页,冷启动进入主页
if (MyApp.app.isFirstLaunch) {
startActivity(Intent(this@WelActivity, MainActivity::class.java)) startActivity(Intent(this@WelActivity, MainActivity::class.java))
} else {
finish()
}
} }
private fun adSplash(place: String) { private fun loadAd() {
// 加载广告 LolAdWrapper.shared.loadAd(
LolAdWrapper.shared.loadAdIfNotCached(
this, this,
place, place,
object : LolAdWrapper.LoLLoadListener { object : LolAdWrapper.LoLLoadListener {
override fun loadFailed(error: LolLoadError?) { override fun loadFailed(error: LolLoadError?) {
// 处理加载失败 handler.sendEmptyMessage(MSG_LOAD_AD_FAIL)
toNextPage() }
})
LolAdWrapper.shared.loadAdIfNotCached(this, MyApp.Config.backup_int_auto)
} }
override fun loaded() { private fun adCanShow(): Boolean {
// 处理加载成功 return LolAdWrapper.shared.hasCache(place)
// 如果需要立刻展示广告,可以调用展示方法 }
private fun showAd() {
LolAdWrapper.shared.showAdIfCached( 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()
}
})
}
})
}
private fun adSplashHot(place: String) {
// 加载广告
LolAdWrapper.shared.loadAdIfNotCached(
this, this,
place, place,
object : LolAdWrapper.LoLLoadListener {
override fun loadFailed(error: LolLoadError?) {
// 处理加载失败
finish()
}
override fun loaded() {
// 处理加载成功
// 如果需要立刻展示广告,可以调用展示方法
LolAdWrapper.shared.showAdIfCached(
this@WelActivity,
place,
object : LolAdWrapper.LolShowListener { object : LolAdWrapper.LolShowListener {
override fun shown() { override fun closed() {
// 处理广告展示成功 toNextPage()
} }
override fun showFailed(error: LolShowError?) { override fun showFailed(error: LolShowError?) {
// 处理广告展示失败 toNextPage()
finish()
}
override fun closed() {
// 处理广告关闭
finish()
} }
}) })
} }
})
}
} }

View File

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

View File

@ -1,25 +1,114 @@
<?xml version="1.0" encoding="utf-8"?> <?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_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/main_bg_ffe2efff"
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp"> android:padding="16dp">
<ImageView
android:id="@+id/iv_dic_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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" />
<TextView
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 <EditText
android:id="@+id/editTextWord" android:id="@+id/editTextWord"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="Enter a word" /> 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>
<Button
android:id="@+id/buttonSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Search" />
<TextView <TextView
android:id="@+id/textViewDefinition" 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_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="16dp" /> android:layout_marginTop="30dp"
</LinearLayout> 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_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:background="@drawable/button_r20_white_bg" android:background="@drawable/button_r20_white_bg" />
android:minHeight="120dp" />
<LinearLayout <LinearLayout
android:id="@+id/ll_main_quick" android:id="@+id/ll_main_quick"
@ -254,7 +253,6 @@
android:visibility="gone" android:visibility="gone"
app:drawableEndCompat="@drawable/ic_arrow_right" /> app:drawableEndCompat="@drawable/ic_arrow_right" />
</LinearLayout> </LinearLayout>
<ImageView <ImageView
@ -265,6 +263,7 @@
android:paddingTop="11dp" android:paddingTop="11dp"
android:paddingBottom="11dp" android:paddingBottom="11dp"
android:src="@drawable/main_setting_quick_def" /> android:src="@drawable/main_setting_quick_def" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -308,7 +307,6 @@
android:textColor="@color/main_text_ff1f1724" android:textColor="@color/main_text_ff1f1724"
android:textSize="14sp" android:textSize="14sp"
android:textStyle="bold" android:textStyle="bold"
android:visibility="gone"
app:drawableTopCompat="@drawable/main_dic" /> app:drawableTopCompat="@drawable/main_dic" />
</LinearLayout> </LinearLayout>

View File

@ -61,6 +61,7 @@
android:paddingEnd="10dp" android:paddingEnd="10dp"
android:src="@drawable/ic_still_pic" /> android:src="@drawable/ic_still_pic" />
<ImageView <ImageView
android:id="@+id/iv_still_take" android:id="@+id/iv_still_take"
android:layout_width="0dp" android:layout_width="0dp"
@ -69,15 +70,34 @@
android:layout_weight="1" android:layout_weight="1"
android:src="@drawable/ic_still_take" /> android:src="@drawable/ic_still_take" />
<ImageView
android:id="@+id/iv_still_buling" <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_weight="1" android:layout_weight="1"
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:paddingStart="10dp"
android:paddingEnd="10dp" android:paddingEnd="10dp"
android:src="@drawable/ic_still_notbuli" /> android:src="@drawable/ic_still_notbuli" />
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -66,13 +66,13 @@
android:textSize="16sp" android:textSize="16sp"
android:textStyle="bold" /> android:textStyle="bold" />
<ImageView <!-- <ImageView-->
android:id="@+id/iv_source_clear" <!-- android:id="@+id/iv_source_clear"-->
android:layout_width="wrap_content" <!-- android:layout_width="wrap_content"-->
android:layout_height="wrap_content" <!-- android:layout_height="wrap_content"-->
android:layout_gravity="center" <!-- android:layout_gravity="center"-->
android:padding="12dp" <!-- android:padding="12dp"-->
android:src="@drawable/ic_tr_close" /> <!-- android:src="@drawable/ic_tr_close" />-->
</LinearLayout> </LinearLayout>
<ImageView <ImageView
@ -148,6 +148,16 @@
</LinearLayout> </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 <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -8,6 +8,14 @@
android:background="@drawable/ic_wel_bg" android:background="@drawable/ic_wel_bg"
tools:context=".viewui.WelActivity"> 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 <ImageView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -28,5 +36,4 @@
app:lottie_fileName="tran_wel_1.json" app:lottie_fileName="tran_wel_1.json"
app:lottie_loop="true" /> app:lottie_loop="true" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

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

View File

@ -57,10 +57,17 @@
<!-- his_page--> <!-- his_page-->
<string name="his_delete">Delete</string> <string name="his_delete">Delete</string>
<string name="his_title">History</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_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> <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--> <!--settings_page-->
<string name="settings">Settings</string> <string name="settings">Settings</string>
@ -94,5 +101,9 @@
<string name="quick_set_kj_double">双击悬浮球</string> <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> <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> </resources>

View File

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