This commit is contained in:
Horis
2025-02-15 18:08:08 +08:00
parent 8c7ef5620b
commit af27b4e570
11 changed files with 268 additions and 175 deletions

View File

@@ -340,7 +340,11 @@
<activity
android:name=".ui.association.VerificationCodeActivity"
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:exported="true"
android:theme="@style/AppTheme.Transparent" />
<!-- 跳转确认 -->
<activity
android:name=".ui.association.OpenUrlConfirmActivity"
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:theme="@style/AppTheme.Transparent" />
<!-- 打开文件 -->
<activity
@@ -433,13 +437,6 @@
</intent-filter>
</activity>
<activity
android:name=".ui.javascript.ConfirmationDialogActivity"
android:theme="@style/Theme.Translucent.NoTitleBar"
android:excludeFromRecents="true"
android:taskAffinity=""
android:launchMode="singleInstance"/>
<service
android:name=".service.CheckSourceService"
android:foregroundServiceType="dataSync" />

View File

@@ -1,6 +1,5 @@
package io.legado.app.help
import android.content.Intent
import android.net.Uri
import android.webkit.WebSettings
import androidx.annotation.Keep
@@ -22,7 +21,7 @@ import io.legado.app.help.source.SourceVerificationHelp
import io.legado.app.model.Debug
import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.model.analyzeRule.QueryTTF
import io.legado.app.ui.javascript.ConfirmationDialogActivity
import io.legado.app.ui.association.OpenUrlConfirmActivity
import io.legado.app.utils.ArchiveUtils
import io.legado.app.utils.ChineseUtils
import io.legado.app.utils.EncoderUtils
@@ -45,6 +44,7 @@ import io.legado.app.utils.longToastOnUi
import io.legado.app.utils.readBytes
import io.legado.app.utils.readText
import io.legado.app.utils.stackTraceStr
import io.legado.app.utils.startActivity
import io.legado.app.utils.toStringArray
import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.Dispatchers.IO
@@ -966,23 +966,12 @@ interface JsExtensions : JsEncodeUtils {
// 新增 mimeType 参数,默认为 null保持兼容性
fun openUrl(url: String, mimeType: String? = null) {
try {
val intent = Intent(appCtx, ConfirmationDialogActivity::class.java).apply {
// 同时设置 Data 和 Type避免单独设置 data/type 导致冲突)
if (mimeType != null) {
setDataAndType(Uri.parse(url), mimeType)
} else {
data = Uri.parse(url)
}
putExtra("sourceTag", getSource()?.getTag() ?: "")
// 可选:添加 MIME 类型到 Extra 供后续逻辑使用
putExtra("mimeType", mimeType)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
appCtx.startActivity(intent)
} catch (e: Exception) {
AppLog.put("启动跳转对话框失败", e)
appCtx.toastOnUi("启动跳转确认失败")
val source = getSource() ?: throw NoStackTraceException("openUrl source cannot be null")
appCtx.startActivity<OpenUrlConfirmActivity> {
putExtra("uri", url)
putExtra("mimeType", mimeType)
putExtra("sourceOrigin", source.getKey())
putExtra("sourceName", source.getTag())
}
}

View File

@@ -0,0 +1,23 @@
package io.legado.app.ui.association
import android.os.Bundle
import io.legado.app.base.BaseActivity
import io.legado.app.databinding.ActivityTranslucenceBinding
import io.legado.app.utils.showDialogFragment
import io.legado.app.utils.viewbindingdelegate.viewBinding
class OpenUrlConfirmActivity :
BaseActivity<ActivityTranslucenceBinding>() {
override val binding by viewBinding(ActivityTranslucenceBinding::inflate)
override fun onActivityCreated(savedInstanceState: Bundle?) {
intent.getStringExtra("uri")?.let {
val mimeType = intent.getStringExtra("mimeType")
val sourceOrigin = intent.getStringExtra("sourceOrigin")
val sourceName = intent.getStringExtra("sourceName")
showDialogFragment(OpenUrlConfirmDialog(it, mimeType, sourceOrigin, sourceName))
} ?: finish()
}
}

View File

@@ -0,0 +1,130 @@
package io.legado.app.ui.association
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar
import androidx.core.net.toUri
import androidx.fragment.app.viewModels
import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
import io.legado.app.constant.AppLog
import io.legado.app.databinding.DialogOpenUrlConfirmBinding
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.theme.primaryColor
import io.legado.app.utils.applyTint
import io.legado.app.utils.setLayout
import io.legado.app.utils.toastOnUi
import io.legado.app.utils.viewbindingdelegate.viewBinding
import splitties.init.appCtx
class OpenUrlConfirmDialog() : BaseDialogFragment(R.layout.dialog_open_url_confirm),
Toolbar.OnMenuItemClickListener {
constructor(
uri: String,
mimeType: String?,
sourceOrigin: String? = null,
sourceName: String? = null
) : this() {
arguments = Bundle().apply {
putString("uri", uri)
putString("mimeType", mimeType)
putString("sourceOrigin", sourceOrigin)
putString("sourceName", sourceName)
}
}
val binding by viewBinding(DialogOpenUrlConfirmBinding::bind)
val viewModel by viewModels<OpenUrlConfirmViewModel>()
override fun onStart() {
super.onStart()
setLayout(1f, ViewGroup.LayoutParams.WRAP_CONTENT)
}
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
initMenu()
val arguments = arguments ?: return
viewModel.initData(arguments)
if (viewModel.uri.isBlank()) {
dismiss()
return
}
binding.toolBar.setBackgroundColor(primaryColor)
binding.toolBar.subtitle = viewModel.sourceName
initView()
}
private fun initMenu() {
binding.toolBar.setOnMenuItemClickListener(this)
binding.toolBar.inflateMenu(R.menu.open_url_confirm)
binding.toolBar.menu.applyTint(requireContext())
}
private fun initView() {
binding.message.text = "${viewModel.sourceName} 正在请求跳转链接/应用,是否跳转?"
binding.btnNegative.setOnClickListener { dismiss() }
binding.btnPositive.setOnClickListener {
openUrl()
dismiss()
}
}
private fun openUrl() {
try {
val uri = viewModel.uri.toUri()
val mimeType = viewModel.mimeType
// 创建目标 Intent 并设置类型
val targetIntent = Intent(Intent.ACTION_VIEW).apply {
// 同时设置 Data 和 Type
if (!mimeType.isNullOrBlank()) {
setDataAndType(uri, mimeType)
} else {
data = uri
}
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
// 验证是否有应用可以处理
if (targetIntent.resolveActivity(appCtx.packageManager) != null) {
startActivity(targetIntent)
} else {
toastOnUi(R.string.can_not_open)
}
} catch (e: Exception) {
AppLog.put("打开链接失败", e, true)
}
}
override fun onMenuItemClick(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_disable_source -> {
viewModel.disableSource {
dismiss()
}
}
R.id.menu_delete_source -> {
alert(R.string.draw) {
setMessage(getString(R.string.sure_del) + "\n" + viewModel.sourceName)
noButton()
yesButton {
viewModel.deleteSource {
dismiss()
}
}
}
}
}
return false
}
override fun onDestroy() {
super.onDestroy()
activity?.finish()
}
}

View File

@@ -0,0 +1,38 @@
package io.legado.app.ui.association
import android.app.Application
import android.os.Bundle
import io.legado.app.base.BaseViewModel
import io.legado.app.data.appDb
class OpenUrlConfirmViewModel(app: Application): BaseViewModel(app) {
var uri = ""
var mimeType: String? = null
var sourceOrigin = ""
var sourceName = ""
fun initData(arguments: Bundle) {
uri = arguments.getString("uri") ?: ""
mimeType = arguments.getString("mimeType")
sourceName = arguments.getString("sourceName") ?: ""
sourceOrigin = arguments.getString("sourceOrigin") ?: ""
}
fun disableSource(block: () -> Unit) {
execute {
appDb.bookSourceDao.enable(sourceOrigin, false)
}.onSuccess {
block.invoke()
}
}
fun deleteSource(block: () -> Unit) {
execute {
appDb.bookSourceDao.delete(sourceOrigin)
}.onSuccess {
block.invoke()
}
}
}

View File

@@ -1,72 +0,0 @@
package io.legado.app.ui.javascript
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.widget.Toolbar
import androidx.appcompat.app.AppCompatActivity
import io.legado.app.R
import io.legado.app.constant.AppLog
import io.legado.app.ui.widget.text.AccentTextView
import io.legado.app.utils.toastOnUi
class ConfirmationDialogActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.confirmation_dialog)
val messageView = findViewById<TextView>(R.id.message)
val toolbar = findViewById<Toolbar>(R.id.tool_bar)
val btnNegative = findViewById<AccentTextView>(R.id.btn_negative)
val btnPositive = findViewById<AccentTextView>(R.id.btn_positive)
// 获取原始 Intent 的数据和 MIME 类型
val uri = intent?.data
val mimeType = intent?.getStringExtra("mimeType")
if (uri == null) {
finish()
return
}
// 处理来源标签显示
val sourceTag = intent.getStringExtra("sourceTag").takeIf { !it.isNullOrBlank() } ?: "当前来源"
messageView.text = "$sourceTag 正在请求跳转外部链接/应用,是否跳转?"
toolbar.setNavigationOnClickListener { finish() }
btnNegative.setOnClickListener { finish() }
btnPositive.setOnClickListener {
try {
// 创建目标 Intent 并设置类型
val targetIntent = Intent(Intent.ACTION_VIEW).apply {
// 同时设置 Data 和 Type
if (!mimeType.isNullOrBlank()) {
setDataAndType(uri, mimeType)
} else {
data = uri
}
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
// 验证是否有应用可以处理
if (targetIntent.resolveActivity(packageManager) != null) {
startActivity(targetIntent)
} else {
toastOnUi(R.string.can_not_open)
}
} catch (e: ActivityNotFoundException) {
toastOnUi(R.string.can_not_open)
} catch (e: Exception) {
AppLog.put("打开链接失败", e)
toastOnUi(R.string.error_occurred)
}
finish()
}
}
override fun onBackPressed() {
super.onBackPressed()
finish()
}
}

View File

@@ -1,57 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#80000000"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/shape_card_view"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarStyle"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:title="跳转确认"
app:titleTextAppearance="@style/ToolbarTitleX" />
<TextView
android:id="@+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:textSize="16sp"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textColor="@color/primaryText" />
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
app:flexDirection="row"
app:justifyContent="flex_end">
<io.legado.app.ui.widget.text.AccentTextView
android:id="@+id/btn_negative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/cancel"/>
<io.legado.app.ui.widget.text.AccentTextView
android:id="@+id/btn_positive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/ok"/>
</com.google.android.flexbox.FlexboxLayout>
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_card_view"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarStyle"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:title="跳转确认"
app:titleTextAppearance="@style/ToolbarTitle" />
<TextView
android:id="@+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:textColor="@color/primaryText"
android:textSize="16sp" />
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:flexDirection="row"
app:justifyContent="flex_end">
<io.legado.app.ui.widget.text.AccentTextView
android:id="@+id/btn_negative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/cancel" />
<io.legado.app.ui.widget.text.AccentTextView
android:id="@+id/btn_positive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/ok" />
</com.google.android.flexbox.FlexboxLayout>
</LinearLayout>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AlwaysShowAction">
<item
android:id="@+id/menu_disable_source"
android:title="@string/disable_source"
app:showAsAction="never" />
<item
android:id="@+id/menu_delete_source"
android:title="@string/delete_source"
app:showAsAction="never" />
</menu>

View File

@@ -1185,6 +1185,4 @@
<string name="theme_config">主题配置</string>
<string name="menu_download_after">Download the chapter after</string>
<string name="menu_download_all">Download all chapter</string>
<string name="error_occurred" translatable="false">打开失败</string>
<string name="confirmation_message" translatable="false">%s正在请求跳转外部链接/应用,是否跳转?</string>
</resources>

View File

@@ -127,21 +127,4 @@
<item name="android:layout_width">wrap_content</item>
</style>
<!-- 基础透明主题 -->
<style name="Theme.Translucent" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
</style>
<!-- 无标题栏变体 -->
<style name="Theme.Translucent.NoTitleBar" parent="Theme.Translucent">
<item name="windowNoTitle">true</item>
</style>
<style name="ToolbarTitleX" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
<item name="android:textSize">20sp</item>
<item name="android:textColor">@color/primaryText</item>
</style>
</resources>