refactor(mod): 重构模组相关功能

- 移除了 BottomSheet 类
- 优化了 CreationWizardActivity 的逻辑
- 更新了 ModFragment 的实现,提高了代码可读性和性能
- 简化了 WarehouseFragment 的代码
- 删除了未使用的 SettingsActivity 导入
This commit is contained in:
Cold-Mint 2025-02-11 18:01:32 +08:00
parent 7c46656e0a
commit a0baf28cd2
7 changed files with 133 additions and 297 deletions

View File

@ -1,14 +1,10 @@
package com.coldmint.rust.pro
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.coldmint.rust.core.debug.LogCat
import com.coldmint.rust.pro.adapters.GuideAdapter
import com.coldmint.rust.pro.base.BaseActivity
@ -19,10 +15,7 @@ import com.coldmint.rust.pro.ui.StableLinearLayoutManager
class CreationWizardActivity : BaseActivity<ActivityCreationWizardBinding>() {
lateinit var createMod: ActivityResultLauncher<Intent>
//创建向导类型(模组,模板包)
lateinit var type: String
private lateinit var createMod: ActivityResultLauncher<Intent>
override fun whenCreateActivity(savedInstanceState: Bundle?, canUseView: Boolean) {
setReturnButton()
title = getString(R.string.creation_assistant)
@ -34,59 +27,14 @@ class CreationWizardActivity : BaseActivity<ActivityCreationWizardBinding>() {
LogCat.d("创建单位", "没有收到数据。")
}
}
val temType = intent.getStringExtra("type")
if (temType.isNullOrBlank()) {
showToast("请传入类型")
finish()
return
}
type = temType
viewBinding.recyclerView.layoutManager = StableLinearLayoutManager(this)
when (temType) {
"mod" -> {
loadMod()
}
"template" -> {
loadTemplate()
}
}
}
/**
* 加载模板活动
*/
private fun loadTemplate() {
val dataList = ArrayList<GuideData>()
dataList.add(
GuideData(
R.string.import_template,
R.string.import_template_describe,
R.drawable.folder
)
)
val adapter = GuideAdapter(this, dataList)
adapter.setItemEvent { i, itemGuideBinding, viewHolder, guideData ->
itemGuideBinding.root.setOnClickListener {
finish()
when (guideData.titleRes) {
R.string.import_template -> {
val startIntent =
Intent(this, FileManagerActivity::class.java)
val fileBundle = Bundle()
fileBundle.putString("type", "selectFile")
startIntent.putExtra("data", fileBundle)
startActivity(startIntent)
}
}
}
}
viewBinding.recyclerView.adapter = adapter
loadMod()
}
/**
* 加载模组活动
*/
fun loadMod() {
private fun loadMod() {
val dataList = ArrayList<GuideData>()
dataList.add(
GuideData(
@ -128,6 +76,7 @@ class CreationWizardActivity : BaseActivity<ActivityCreationWizardBinding>() {
)
createMod.launch(startActivity)
}
R.string.import_mod -> {
val startIntent =
Intent(this, FileManagerActivity::class.java)
@ -137,6 +86,7 @@ class CreationWizardActivity : BaseActivity<ActivityCreationWizardBinding>() {
startActivity(startIntent)
finish()
}
R.string.import_mod_from_package_directory -> {
val startIntent =
Intent(this, FileManagerActivity::class.java)
@ -152,6 +102,7 @@ class CreationWizardActivity : BaseActivity<ActivityCreationWizardBinding>() {
startActivity(startIntent)
finish()
}
R.string.import_mod_from_recycle_bin -> {
startActivity(Intent(this, RecyclingStationActivity::class.java))
finish()

View File

@ -10,7 +10,6 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import com.bumptech.glide.Glide
import com.coldmint.rust.core.tool.FileOperator

View File

@ -2,51 +2,48 @@ package com.coldmint.rust.pro.fragments
import android.annotation.SuppressLint
import android.content.res.ColorStateList
import android.os.*
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.coldmint.rust.core.ModClass
import com.coldmint.rust.core.dataBean.ModConfigurationData
import com.coldmint.rust.core.tool.DebugHelper
import com.coldmint.rust.core.tool.FileOperator
import com.coldmint.rust.pro.R
import com.coldmint.rust.pro.adapters.ModActionAdapter
import com.coldmint.rust.pro.adapters.ModAdapter
import com.coldmint.rust.pro.base.BaseFragment
import com.coldmint.rust.pro.databinding.ModDialogBinding
import com.coldmint.rust.pro.databinding.FragmentModBinding
import com.coldmint.rust.pro.databinding.ModDialogBinding
import com.coldmint.rust.pro.databinding.ModListItemBinding
import com.coldmint.rust.pro.tool.AppSettings
import com.coldmint.rust.pro.tool.GlobalMethod
import com.coldmint.rust.pro.tool.Tools
import com.coldmint.rust.pro.ui.StableLinearLayoutManager
import com.coldmint.rust.pro.viewmodel.ModViewModel
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.isActive
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.zhanghai.android.fastscroll.FastScrollerBuilder
import java.io.File
class ModFragment : BaseFragment<FragmentModBinding>() {
val viewModel: ModViewModel by lazy {
private val viewModel: ModViewModel by lazy {
ModViewModel()
}
lateinit var modAdapter: ModAdapter
val needRecycling by lazy {
private lateinit var modAdapter: ModAdapter
private val needRecycling by lazy {
if (GlobalMethod.isActive) {
AppSettings.getValue(
AppSettings.Setting.EnableRecoveryStation,
true
AppSettings.Setting.EnableRecoveryStation,
true
)
} else {
false
@ -55,19 +52,16 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
/**
* 删除文件
* @param handler Handler
* @param modClass ModClass
*/
fun delFile(
handler: Handler,
modClass: ModClass,
index: Int? = null
private fun delFile(
modClass: ModClass,
index: Int? = null
) {
val scope = CoroutineScope(Job())
scope.launch {
lifecycleScope.launch(Dispatchers.IO) {
val targetFile = modClass.modFile
val errorFolder =
File(AppSettings.dataRootDirectory + "/modErrorReport/" + modClass.modName)
File(AppSettings.dataRootDirectory + "/modErrorReport/" + modClass.modName)
if (errorFolder.exists()) {
FileOperator.delete_files(errorFolder)
}
@ -75,7 +69,7 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
requireActivity().applicationContext.dataDir.absolutePath + "/databases/"
} else {
FileOperator.getSuperDirectory(
requireContext().cacheDir
requireContext().cacheDir
) + "/databases/"
}
val name = modClass.modName
@ -86,13 +80,13 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
shmFile.delete()
walFile.delete()
if (needRecycling) {
var result = false
val result: Boolean
val removePath: String
val removeFile: File
if (targetFile.isDirectory) {
removePath = AppSettings.getValue(
AppSettings.Setting.RecoveryStationFolder,
requireContext().filesDir.absolutePath + "/backup/"
AppSettings.Setting.RecoveryStationFolder,
requireContext().filesDir.absolutePath + "/backup/"
).toString() + targetFile.name + "/"
removeFile = File(removePath)
if (!removeFile.exists()) {
@ -100,71 +94,77 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
}
} else {
removePath = AppSettings.getValue(
AppSettings.Setting.RecoveryStationFolder,
requireContext().filesDir.absolutePath + "/backup/"
AppSettings.Setting.RecoveryStationFolder,
requireContext().filesDir.absolutePath + "/backup/"
).toString() + targetFile.name
removeFile = File(removePath)
}
if (removeFile.exists()) {
FileOperator.delete_files(removeFile)
}
handler.post {
withContext(Dispatchers.Main) {
Snackbar.make(
viewBinding.modList,
String.format(
getString(R.string.recoverying_prompt),
modClass.modName
),
Snackbar.LENGTH_INDEFINITE
viewBinding.modList,
String.format(
getString(R.string.recoverying_prompt),
modClass.modName
),
Snackbar.LENGTH_INDEFINITE
).show()
}
result = FileOperator.removeFiles(targetFile, removeFile)
if (result) {
handler.post {
withContext(Dispatchers.Main) {
Snackbar.make(
viewBinding.modList,
String.format(
requireContext().getString(R.string.recovery_prompt),
modClass.modName
),
Snackbar.LENGTH_SHORT
viewBinding.modList,
String.format(
requireContext().getString(R.string.recovery_prompt),
modClass.modName
),
Snackbar.LENGTH_SHORT
).show()
if (index != null) {
modAdapter.removeItem(index)
if (modAdapter.itemCount == 0) {
notFindMod()
}
}
}
} else {
handler.post {
withContext(Dispatchers.Main) {
Snackbar.make(
viewBinding.modList,
getString(R.string.cut_failed),
Snackbar.LENGTH_SHORT
viewBinding.modList,
getString(R.string.cut_failed),
Snackbar.LENGTH_SHORT
).show()
}
}
} else {
handler.post {
withContext(Dispatchers.Main) {
Snackbar.make(
viewBinding.modList,
String.format(
getString(R.string.del_moding_tip),
modClass.modName
),
Snackbar.LENGTH_INDEFINITE
viewBinding.modList,
String.format(
getString(R.string.del_moding_tip),
modClass.modName
),
Snackbar.LENGTH_INDEFINITE
).show()
}
FileOperator.delete_files(targetFile)
handler.post {
withContext(Dispatchers.Main) {
Snackbar.make(
viewBinding.modList,
String.format(
getString(R.string.del_completed),
modClass.modName
),
Snackbar.LENGTH_SHORT
viewBinding.modList,
String.format(
getString(R.string.del_completed),
modClass.modName
),
Snackbar.LENGTH_SHORT
).show()
if (index != null) {
modAdapter.removeItem(index)
if (modAdapter.itemCount == 0) {
notFindMod()
}
}
}
}
@ -175,53 +175,46 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
* 加载模组列表
*/
fun loadModList() {
val scope = CoroutineScope(Job())
val handler = Handler(Looper.getMainLooper())
scope.launch {
lifecycleScope.launch(Dispatchers.IO) {
val dataList = viewModel.loadMod()
handler.post {
withContext(Dispatchers.Main) {
viewBinding.progressBar.isVisible = true
viewBinding.modErrorIcon.isVisible = false
viewBinding.modError.isVisible = false
viewBinding.swipeRefreshLayout.isVisible = false
}
if (dataList == null) {
handler.post {
viewBinding.modError.setText(R.string.not_find_mod)
viewBinding.modError.isVisible = true
viewBinding.modErrorIcon.isVisible = true
viewBinding.swipeRefreshLayout.isVisible = false
viewBinding.progressBar.isVisible = false
if (dataList.isNullOrEmpty()) {
withContext(Dispatchers.Main) {
notFindMod()
}
} else {
handler.post {
withContext(Dispatchers.Main) {
viewBinding.swipeRefreshLayout.isVisible = true
viewBinding.progressBar.isVisible = false
viewBinding.modErrorIcon.isVisible = false
viewBinding.modError.isVisible = false
if (isAdded) {
modAdapter = ModAdapter(requireContext(), dataList)
FastScrollerBuilder(viewBinding.modList).useMd2Style()
.setPopupTextProvider(modAdapter).build()
modAdapter.setItemEvent { i, modListItemBinding, viewHolder, modClass ->
modListItemBinding.root.setOnClickListener {
onClickItemWork(modListItemBinding, modClass)
}
modListItemBinding.root.setOnLongClickListener {
modAdapter.showDeleteItemDialog(
modClass.modName,
viewHolder.absoluteAdapterPosition,
onClickPositiveButton = { d, b ->
delFile(handler, modClass, viewHolder.absoluteAdapterPosition)
false
})
false
}
modAdapter = ModAdapter(requireContext(), dataList)
FastScrollerBuilder(viewBinding.modList).useMd2Style()
.setPopupTextProvider(modAdapter).build()
modAdapter.setItemEvent { i, modListItemBinding, viewHolder, modClass ->
modListItemBinding.root.setOnClickListener {
onClickItemWork(modListItemBinding, modClass)
}
modListItemBinding.root.setOnLongClickListener {
modAdapter.showDeleteItemDialog(
modClass.modName,
viewHolder.absoluteAdapterPosition,
onClickPositiveButton = { d, b ->
delFile(
modClass,
viewHolder.absoluteAdapterPosition
)
false
})
false
}
viewBinding.modList.adapter = modAdapter
} else {
DebugHelper.printLog("加载模组列表", "没有附加到活动", isError = true)
}
viewBinding.modList.adapter = modAdapter
}
}
}
@ -237,16 +230,14 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
fun onClickItemWork(viewBinding: ModListItemBinding, modClass: ModClass) {
val context = requireContext()
val modDialogBinding =
ModDialogBinding.inflate(LayoutInflater.from(context))
ModDialogBinding.inflate(LayoutInflater.from(context))
val bottomSheetDialog =
BottomSheetDialog(context)
BottomSheetDialog(context)
modDialogBinding.modNameView.text = viewBinding.modNameView.text
modDialogBinding.modNameDescription.text = viewBinding.modIntroductionView.text
val configurationManager = modClass.modConfigurationManager
val configurationData: ModConfigurationData? =
configurationManager?.readData()
configurationManager?.readData()
val works: MutableList<String> = ArrayList()
if (modClass.modFile.isDirectory) {
if (GlobalMethod.isActive) {
@ -273,11 +264,11 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
}
works.add(getString(R.string.share_mod))
val modActionAdapter = ModActionAdapter(
context,
works,
modClass.modFile.path,
this@ModFragment,
bottomSheetDialog
context,
works,
modClass.modFile.path,
this@ModFragment,
bottomSheetDialog
)
if (configurationData != null) {
modActionAdapter.setModConfigurationData(configurationData)
@ -287,13 +278,13 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
if (modClass.modIcon == null) {
val drawable = context.getDrawable(R.drawable.image)
modDialogBinding.modIcon.setImageDrawable(
GlobalMethod.tintDrawable(
drawable, ColorStateList.valueOf(
GlobalMethod.getColorPrimary(
requireContext()
)
)
GlobalMethod.tintDrawable(
drawable, ColorStateList.valueOf(
GlobalMethod.getColorPrimary(
requireContext()
)
)
)
)
} else {
Glide.with(requireContext()).load(modClass.modIcon).into(modDialogBinding.modIcon)
@ -301,17 +292,18 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
} else {
val drawable = context.getDrawable(R.drawable.file)
modDialogBinding.modIcon.setImageDrawable(
GlobalMethod.tintDrawable(
drawable, ColorStateList.valueOf(
GlobalMethod.getColorPrimary(
requireContext()
)
)
GlobalMethod.tintDrawable(
drawable, ColorStateList.valueOf(
GlobalMethod.getColorPrimary(
requireContext()
)
)
)
)
}
bottomSheetDialog.setContentView(modDialogBinding.root)
val bottomSheet = bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
val bottomSheet =
bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
if (bottomSheet != null) {
val behavior = BottomSheetBehavior.from(bottomSheet)
behavior.state = BottomSheetBehavior.STATE_EXPANDED // 默认展开
@ -322,16 +314,16 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
bottomSheetDialog.show()
}
// /**
// * 显示没有找到模组
// */
// fun showNotFindMod() {
// viewBinding.modError.setText(R.string.not_find_mod)
// viewBinding.modError.isVisible = true
// viewBinding.modErrorIcon.isVisible = true
// viewBinding.modList.isVisible = false
// viewBinding.progressBar.isVisible = false
// }
/**
* 显示没有找到模组
*/
private fun notFindMod() {
viewBinding.modError.setText(R.string.not_find_mod)
viewBinding.modError.isVisible = true
viewBinding.modErrorIcon.isVisible = true
viewBinding.swipeRefreshLayout.isVisible = false
viewBinding.progressBar.isVisible = false
}
override fun getViewBindingObject(layoutInflater: LayoutInflater): FragmentModBinding {
return FragmentModBinding.inflate(layoutInflater)
@ -340,11 +332,11 @@ class ModFragment : BaseFragment<FragmentModBinding>() {
override fun whenViewCreated(inflater: LayoutInflater, savedInstanceState: Bundle?) {
viewBinding.modList.layoutManager = StableLinearLayoutManager(requireContext())
val divider = MaterialDividerItemDecoration(
requireContext(),
MaterialDividerItemDecoration.VERTICAL
requireContext(),
MaterialDividerItemDecoration.VERTICAL
)
viewBinding.modList.addItemDecoration(
divider
divider
)
viewBinding.swipeRefreshLayout.setOnRefreshListener {
loadModList()

View File

@ -31,16 +31,13 @@ class WarehouseFragment : BaseFragment<FragmentWarehouseBinding>() {
}
}.attach()
viewBinding.mainButton.setOnClickListener {
val intent = Intent(context, CreationWizardActivity::class.java)
intent.putExtra("type", "mod")
startActivity(intent)
startActivity(Intent(context, CreationWizardActivity::class.java))
}
}
}
override fun getViewBindingObject(layoutInflater: LayoutInflater): FragmentWarehouseBinding {
return FragmentWarehouseBinding.inflate(layoutInflater)
}
override fun getViewBindingObject(layoutInflater: LayoutInflater): FragmentWarehouseBinding =
FragmentWarehouseBinding.inflate(layoutInflater)
override fun whenViewCreated(inflater: LayoutInflater, savedInstanceState: Bundle?) {
viewBinding.pager.adapter = WarehouseAdapter(this)

View File

@ -1,100 +0,0 @@
package com.coldmint.rust.pro.ui
import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.animation.AccelerateDecelerateInterpolator
import androidx.core.animation.addListener
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import com.google.android.material.bottomsheet.BottomSheetDragHandleView
import android.view.MotionEvent as MotionEvent1
class BottomSheet(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : BottomSheetDragHandleView(context) {
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
private var initialX = 0f
private var lastTouchX = 0f
private var deltaX = 0f
private val maxXOffset = 50f // 最大偏移量
var isScaling = false
// 覆盖 onTouchEvent 方法以处理触摸事件
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent1?): Boolean {
event?.let {
when (it.action) {
MotionEvent1.ACTION_DOWN -> {
// 触摸开始时的逻辑
// 记录初始位置
initialX = translationX
lastTouchX = event.rawX
// 触摸开始时放大
if (!isScaling) {
animate().scaleX(1.2f).scaleY(1.2f)
.setDuration(200)
.setInterpolator(FastOutSlowInInterpolator())
.withLayer()
.start()
isScaling = true
}
}
MotionEvent1.ACTION_MOVE -> {
val dx = event.rawX - lastTouchX
val fl = initialX + dx
if (fl < maxXOffset && fl > -maxXOffset) {
translationX = fl
}
}
MotionEvent1.ACTION_UP, MotionEvent1.ACTION_CANCEL -> {
// 触摸结束时恢复大小和位置
val animatorSet = AnimatorSet()
// 恢复大小
val scaleAnimator = ObjectAnimator.ofFloat(this, "scaleX", 1f)
scaleAnimator.duration = 200
scaleAnimator.interpolator = AccelerateDecelerateInterpolator()
val scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY", 1f)
scaleYAnimator.duration = 200
scaleYAnimator.interpolator = AccelerateDecelerateInterpolator()
// 恢复到原始位置
val translationAnimator = ObjectAnimator.ofFloat(this, "translationX", 0f)
translationAnimator.duration = 200
translationAnimator.interpolator = AccelerateDecelerateInterpolator()
// 将所有动画添加到 AnimatorSet 中并启动
animatorSet.playTogether(scaleAnimator, scaleYAnimator, translationAnimator)
animatorSet.start()
animatorSet.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {}
override fun onAnimationEnd(animation: Animator) {
isScaling = false
translationX = 0f
}
override fun onAnimationCancel(animation: Animator) {}
override fun onAnimationRepeat(animation: Animator) {}
})
}
else -> {
// 其他事件处理
}
}
}
// 返回 true 表示事件已经被消费,返回 false 表示事件没有被消费
return true
}
}

View File

@ -5,10 +5,9 @@
android:orientation="vertical"
android:padding="8dp">
<com.coldmint.rust.pro.ui.BottomSheet
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"

View File

@ -1,7 +1,5 @@
<?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:id="@+id/mod_linearlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"