parent
							
								
									8cdd938fdb
								
							
						
					
					
						commit
						3aadc4cd77
					
				
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						@ -0,0 +1,124 @@ | 
				
			||||
package io.legado.app.ui.association | 
				
			||||
 | 
				
			||||
import android.annotation.SuppressLint | 
				
			||||
import android.content.Context | 
				
			||||
import android.content.DialogInterface | 
				
			||||
import android.os.Bundle | 
				
			||||
import android.view.View | 
				
			||||
import android.view.ViewGroup | 
				
			||||
import androidx.fragment.app.viewModels | 
				
			||||
import io.legado.app.R | 
				
			||||
import io.legado.app.base.BaseDialogFragment | 
				
			||||
import io.legado.app.base.adapter.ItemViewHolder | 
				
			||||
import io.legado.app.base.adapter.RecyclerAdapter | 
				
			||||
import io.legado.app.data.entities.HttpTTS | 
				
			||||
import io.legado.app.databinding.DialogRecyclerViewBinding | 
				
			||||
import io.legado.app.databinding.ItemSourceImportBinding | 
				
			||||
import io.legado.app.lib.theme.primaryColor | 
				
			||||
import io.legado.app.ui.widget.dialog.CodeDialog | 
				
			||||
import io.legado.app.utils.GSON | 
				
			||||
import io.legado.app.utils.setLayout | 
				
			||||
import io.legado.app.utils.showDialogFragment | 
				
			||||
import io.legado.app.utils.viewbindingdelegate.viewBinding | 
				
			||||
import splitties.views.onClick | 
				
			||||
 | 
				
			||||
class ImportHttpTtsDialog() : BaseDialogFragment(R.layout.dialog_recycler_view) { | 
				
			||||
 | 
				
			||||
    constructor(source: String, finishOnDismiss: Boolean = false) : this() { | 
				
			||||
        arguments = Bundle().apply { | 
				
			||||
            putString("source", source) | 
				
			||||
            putBoolean("finishOnDismiss", finishOnDismiss) | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    private val binding by viewBinding(DialogRecyclerViewBinding::bind) | 
				
			||||
    private val viewModel by viewModels<ImportHttpTtsViewModel>() | 
				
			||||
 | 
				
			||||
    override fun onStart() { | 
				
			||||
        super.onStart() | 
				
			||||
        setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    override fun onDismiss(dialog: DialogInterface) { | 
				
			||||
        super.onDismiss(dialog) | 
				
			||||
        if (arguments?.getBoolean("finishOnDismiss") == true) { | 
				
			||||
            activity?.finish() | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    @SuppressLint("NotifyDataSetChanged") | 
				
			||||
    override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { | 
				
			||||
        binding.toolBar.setBackgroundColor(primaryColor) | 
				
			||||
        binding.toolBar.setTitle(R.string.import_book_source) | 
				
			||||
        binding.rotateLoading.show() | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    private fun upSelectText() { | 
				
			||||
        if (viewModel.isSelectAll) { | 
				
			||||
            binding.tvFooterLeft.text = getString( | 
				
			||||
                R.string.select_cancel_count, | 
				
			||||
                viewModel.selectCount, | 
				
			||||
                viewModel.allSources.size | 
				
			||||
            ) | 
				
			||||
        } else { | 
				
			||||
            binding.tvFooterLeft.text = getString( | 
				
			||||
                R.string.select_all_count, | 
				
			||||
                viewModel.selectCount, | 
				
			||||
                viewModel.allSources.size | 
				
			||||
            ) | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    inner class SourcesAdapter(context: Context) : | 
				
			||||
        RecyclerAdapter<HttpTTS, ItemSourceImportBinding>(context) { | 
				
			||||
 | 
				
			||||
        override fun getViewBinding(parent: ViewGroup): ItemSourceImportBinding { | 
				
			||||
            return ItemSourceImportBinding.inflate(inflater, parent, false) | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        override fun convert( | 
				
			||||
            holder: ItemViewHolder, | 
				
			||||
            binding: ItemSourceImportBinding, | 
				
			||||
            item: HttpTTS, | 
				
			||||
            payloads: MutableList<Any> | 
				
			||||
        ) { | 
				
			||||
            binding.apply { | 
				
			||||
                cbSourceName.isChecked = viewModel.selectStatus[holder.layoutPosition] | 
				
			||||
                cbSourceName.text = item.name | 
				
			||||
                val localSource = viewModel.checkSources[holder.layoutPosition] | 
				
			||||
                tvSourceState.text = when { | 
				
			||||
                    localSource == null -> "新增" | 
				
			||||
                    item.lastUpdateTime > localSource.lastUpdateTime -> "更新" | 
				
			||||
                    else -> "已有" | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        override fun registerListener(holder: ItemViewHolder, binding: ItemSourceImportBinding) { | 
				
			||||
            binding.apply { | 
				
			||||
                cbSourceName.setOnCheckedChangeListener { buttonView, isChecked -> | 
				
			||||
                    if (buttonView.isPressed) { | 
				
			||||
                        viewModel.selectStatus[holder.layoutPosition] = isChecked | 
				
			||||
                        upSelectText() | 
				
			||||
                    } | 
				
			||||
                } | 
				
			||||
                root.onClick { | 
				
			||||
                    cbSourceName.isChecked = !cbSourceName.isChecked | 
				
			||||
                    viewModel.selectStatus[holder.layoutPosition] = cbSourceName.isChecked | 
				
			||||
                    upSelectText() | 
				
			||||
                } | 
				
			||||
                tvOpen.setOnClickListener { | 
				
			||||
                    val source = viewModel.allSources[holder.layoutPosition] | 
				
			||||
                    showDialogFragment( | 
				
			||||
                        CodeDialog( | 
				
			||||
                            GSON.toJson(source), | 
				
			||||
                            disableEdit = false, | 
				
			||||
                            requestId = holder.layoutPosition.toString() | 
				
			||||
                        ) | 
				
			||||
                    ) | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,116 @@ | 
				
			||||
package io.legado.app.ui.association | 
				
			||||
 | 
				
			||||
import android.app.Application | 
				
			||||
import androidx.lifecycle.MutableLiveData | 
				
			||||
import com.jayway.jsonpath.JsonPath | 
				
			||||
import io.legado.app.R | 
				
			||||
import io.legado.app.base.BaseViewModel | 
				
			||||
import io.legado.app.data.appDb | 
				
			||||
import io.legado.app.data.entities.BookSource | 
				
			||||
import io.legado.app.data.entities.HttpTTS | 
				
			||||
import io.legado.app.exception.NoStackTraceException | 
				
			||||
import io.legado.app.help.ContentProcessor | 
				
			||||
import io.legado.app.help.SourceHelp | 
				
			||||
import io.legado.app.help.config.AppConfig | 
				
			||||
import io.legado.app.help.http.newCallResponseBody | 
				
			||||
import io.legado.app.help.http.okHttpClient | 
				
			||||
import io.legado.app.help.http.text | 
				
			||||
import io.legado.app.utils.isAbsUrl | 
				
			||||
import io.legado.app.utils.isJsonArray | 
				
			||||
import io.legado.app.utils.isJsonObject | 
				
			||||
import io.legado.app.utils.printOnDebug | 
				
			||||
 | 
				
			||||
class ImportHttpTtsViewModel(app: Application) : BaseViewModel(app) { | 
				
			||||
 | 
				
			||||
    val errorLiveData = MutableLiveData<String>() | 
				
			||||
    val successLiveData = MutableLiveData<Int>() | 
				
			||||
 | 
				
			||||
    val allSources = arrayListOf<HttpTTS>() | 
				
			||||
    val checkSources = arrayListOf<HttpTTS?>() | 
				
			||||
    val selectStatus = arrayListOf<Boolean>() | 
				
			||||
 | 
				
			||||
    val isSelectAll: Boolean | 
				
			||||
        get() { | 
				
			||||
            selectStatus.forEach { | 
				
			||||
                if (!it) { | 
				
			||||
                    return false | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
            return true | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
    val selectCount: Int | 
				
			||||
        get() { | 
				
			||||
            var count = 0 | 
				
			||||
            selectStatus.forEach { | 
				
			||||
                if (it) { | 
				
			||||
                    count++ | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
            return count | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
    fun importSelect(finally: () -> Unit) { | 
				
			||||
        execute { | 
				
			||||
            val keepName = AppConfig.importKeepName | 
				
			||||
            val selectSource = arrayListOf<BookSource>() | 
				
			||||
            SourceHelp.insertBookSource(*selectSource.toTypedArray()) | 
				
			||||
            ContentProcessor.upReplaceRules() | 
				
			||||
        }.onFinally { | 
				
			||||
            finally.invoke() | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    fun importSource(text: String) { | 
				
			||||
        execute { | 
				
			||||
            val mText = text.trim() | 
				
			||||
            when { | 
				
			||||
                mText.isJsonObject() -> { | 
				
			||||
                    val json = JsonPath.parse(mText) | 
				
			||||
                    val urls = json.read<List<String>>("$.sourceUrls") | 
				
			||||
                    if (!urls.isNullOrEmpty()) { | 
				
			||||
                        urls.forEach { | 
				
			||||
                            importSourceUrl(it) | 
				
			||||
                        } | 
				
			||||
                    } else { | 
				
			||||
                        HttpTTS.fromJson(mText).getOrThrow().let { | 
				
			||||
                            allSources.add(it) | 
				
			||||
                        } | 
				
			||||
                    } | 
				
			||||
                } | 
				
			||||
                mText.isJsonArray() -> HttpTTS.fromJsonArray(mText).getOrThrow().let { items -> | 
				
			||||
                    allSources.addAll(items) | 
				
			||||
                } | 
				
			||||
                mText.isAbsUrl() -> { | 
				
			||||
                    importSourceUrl(mText) | 
				
			||||
                } | 
				
			||||
                else -> throw NoStackTraceException(context.getString(R.string.wrong_format)) | 
				
			||||
            } | 
				
			||||
        }.onError { | 
				
			||||
            it.printOnDebug() | 
				
			||||
            errorLiveData.postValue(it.localizedMessage ?: "") | 
				
			||||
        }.onSuccess { | 
				
			||||
            comparisonSource() | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    private suspend fun importSourceUrl(url: String) { | 
				
			||||
        okHttpClient.newCallResponseBody { | 
				
			||||
            url(url) | 
				
			||||
        }.text().let { | 
				
			||||
            allSources.addAll(HttpTTS.fromJsonArray(it).getOrThrow()) | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    private fun comparisonSource() { | 
				
			||||
        execute { | 
				
			||||
            allSources.forEach { | 
				
			||||
                val source = appDb.httpTTSDao.get(it.id) | 
				
			||||
                checkSources.add(source) | 
				
			||||
                selectStatus.add(source == null || source.lastUpdateTime < it.lastUpdateTime) | 
				
			||||
            } | 
				
			||||
            successLiveData.postValue(allSources.size) | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue