commit
0aa6ee9803
@ -0,0 +1,62 @@ |
||||
[ |
||||
{ |
||||
"id": 1598233029304, |
||||
"name": "度小美", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=0&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029305, |
||||
"name": "度小宇", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=1&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029306, |
||||
"name": "度逍遥", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=3&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029307, |
||||
"name": "度丫丫", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=4&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029308, |
||||
"name": "度小娇", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=5&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029309, |
||||
"name": "度米朵", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=103&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029310, |
||||
"name": "度博文", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=106&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029311, |
||||
"name": "度小童", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=110&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029312, |
||||
"name": "度小萌", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=111&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029313, |
||||
"name": "百度骚男", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=11&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029314, |
||||
"name": "百度评书", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=6&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029315, |
||||
"name": "百度主持", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=9&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
} |
||||
] |
@ -0,0 +1,31 @@ |
||||
package io.legado.app.data.dao |
||||
|
||||
import androidx.lifecycle.LiveData |
||||
import androidx.room.* |
||||
import io.legado.app.data.entities.HttpTTS |
||||
|
||||
@Dao |
||||
interface HttpTTSDao { |
||||
|
||||
@get:Query("select * from httpTTS order by name") |
||||
val all: List<HttpTTS> |
||||
|
||||
@Query("select * from httpTTS order by name") |
||||
fun observeAll(): LiveData<List<HttpTTS>> |
||||
|
||||
@get:Query("select count(*) from httpTTS") |
||||
val count: Int |
||||
|
||||
@Query("select * from httpTTS where id = :id") |
||||
fun get(id: Long): HttpTTS? |
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE) |
||||
fun insert(vararg httpTTS: HttpTTS) |
||||
|
||||
@Delete |
||||
fun delete(vararg httpTTS: HttpTTS) |
||||
|
||||
@Update |
||||
fun update(vararg httpTTS: HttpTTS) |
||||
|
||||
} |
@ -0,0 +1,12 @@ |
||||
package io.legado.app.data.entities |
||||
|
||||
import androidx.room.Entity |
||||
import androidx.room.PrimaryKey |
||||
|
||||
@Entity(tableName = "httpTTS") |
||||
data class HttpTTS( |
||||
@PrimaryKey |
||||
val id: Long = System.currentTimeMillis(), |
||||
var name: String = "", |
||||
var url: String = "" |
||||
) |
@ -1,11 +1,10 @@ |
||||
package io.legado.app.data.entities |
||||
|
||||
import androidx.room.Entity |
||||
import androidx.room.PrimaryKey |
||||
|
||||
@Entity(tableName = "readRecord") |
||||
@Entity(tableName = "readRecord", primaryKeys = ["androidId", "bookName"]) |
||||
data class ReadRecord( |
||||
@PrimaryKey |
||||
var androidId: String = "", |
||||
var bookName: String = "", |
||||
var readTime: Long = 0L |
||||
) |
@ -0,0 +1,6 @@ |
||||
package io.legado.app.data.entities |
||||
|
||||
data class ReadRecordShow( |
||||
var bookName: String = "", |
||||
var readTime: Long = 0L |
||||
) |
@ -0,0 +1,19 @@ |
||||
package io.legado.app.help |
||||
|
||||
import io.legado.app.App |
||||
import io.legado.app.data.entities.HttpTTS |
||||
import io.legado.app.utils.GSON |
||||
import io.legado.app.utils.fromJsonArray |
||||
|
||||
object DefaultValueHelp { |
||||
|
||||
|
||||
fun initHttpTTS() { |
||||
val json = String(App.INSTANCE.assets.open("httpTTS.json").readBytes()) |
||||
GSON.fromJsonArray<HttpTTS>(json)?.let { |
||||
App.db.httpTTSDao().insert(*it.toTypedArray()) |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -1,93 +0,0 @@ |
||||
package io.legado.app.model |
||||
|
||||
import io.legado.app.App |
||||
import io.legado.app.data.entities.SearchBook |
||||
import io.legado.app.help.AppConfig |
||||
import io.legado.app.help.coroutine.Coroutine |
||||
import io.legado.app.utils.getPrefString |
||||
import kotlinx.coroutines.CoroutineScope |
||||
import kotlinx.coroutines.Dispatchers.IO |
||||
import kotlinx.coroutines.asCoroutineDispatcher |
||||
import java.util.concurrent.Executors |
||||
|
||||
class SearchBookModel(private val scope: CoroutineScope, private val callBack: CallBack) { |
||||
private var searchPool = |
||||
Executors.newFixedThreadPool(AppConfig.threadCount).asCoroutineDispatcher() |
||||
private var mSearchId = System.currentTimeMillis() |
||||
private var searchPage = 1 |
||||
private var searchKey: String = "" |
||||
private var task: Coroutine<*>? = null |
||||
|
||||
private fun initSearchPool() { |
||||
searchPool = |
||||
Executors.newFixedThreadPool(AppConfig.threadCount).asCoroutineDispatcher() |
||||
} |
||||
|
||||
fun search(searchId: Long, key: String) { |
||||
if (searchId != mSearchId) { |
||||
task?.cancel() |
||||
searchPool.close() |
||||
initSearchPool() |
||||
mSearchId = searchId |
||||
searchPage = 1 |
||||
if (key.isEmpty()) { |
||||
return |
||||
} else { |
||||
this.searchKey = key |
||||
} |
||||
} else { |
||||
searchPage++ |
||||
} |
||||
task = Coroutine.async(scope, searchPool) { |
||||
val searchGroup = App.INSTANCE.getPrefString("searchGroup") ?: "" |
||||
val bookSourceList = if (searchGroup.isBlank()) { |
||||
App.db.bookSourceDao().allEnabled |
||||
} else { |
||||
App.db.bookSourceDao().getEnabledByGroup(searchGroup) |
||||
} |
||||
for (item in bookSourceList) { |
||||
//task取消时自动取消 by (scope = this@execute) |
||||
WebBook(item).searchBook( |
||||
searchKey, |
||||
searchPage, |
||||
scope = this, |
||||
context = searchPool |
||||
) |
||||
.timeout(30000L) |
||||
.onSuccess(IO) { |
||||
if (searchId == mSearchId) { |
||||
callBack.onSearchSuccess(it) |
||||
} |
||||
} |
||||
} |
||||
}.onStart { |
||||
callBack.onSearchStart() |
||||
} |
||||
|
||||
task?.invokeOnCompletion { |
||||
if (searchId == mSearchId) { |
||||
callBack.onSearchFinish() |
||||
} |
||||
} |
||||
} |
||||
|
||||
fun cancelSearch() { |
||||
task?.cancel() |
||||
mSearchId = 0 |
||||
callBack.onSearchCancel() |
||||
} |
||||
|
||||
fun close() { |
||||
task?.cancel() |
||||
mSearchId = 0 |
||||
searchPool.close() |
||||
} |
||||
|
||||
interface CallBack { |
||||
fun onSearchStart() |
||||
fun onSearchSuccess(searchBooks: ArrayList<SearchBook>) |
||||
fun onSearchFinish() |
||||
fun onSearchCancel() |
||||
} |
||||
|
||||
} |
@ -1,4 +1,4 @@ |
||||
package io.legado.app.model |
||||
package io.legado.app.model.rss |
||||
|
||||
import io.legado.app.data.entities.RssArticle |
||||
import io.legado.app.data.entities.RssSource |
@ -0,0 +1,117 @@ |
||||
package io.legado.app.model.webBook |
||||
|
||||
import io.legado.app.App |
||||
import io.legado.app.data.entities.BookSource |
||||
import io.legado.app.data.entities.SearchBook |
||||
import io.legado.app.help.AppConfig |
||||
import io.legado.app.help.coroutine.CompositeCoroutine |
||||
import io.legado.app.utils.getPrefString |
||||
import kotlinx.coroutines.CoroutineScope |
||||
import kotlinx.coroutines.Dispatchers.IO |
||||
import kotlinx.coroutines.ExecutorCoroutineDispatcher |
||||
import kotlinx.coroutines.asCoroutineDispatcher |
||||
import java.util.concurrent.Executors |
||||
import kotlin.math.min |
||||
|
||||
class SearchBookModel(private val scope: CoroutineScope, private val callBack: CallBack) { |
||||
val threadCount = AppConfig.threadCount |
||||
private var searchPool: ExecutorCoroutineDispatcher? = null |
||||
private var mSearchId = 0L |
||||
private var searchPage = 1 |
||||
private var searchKey: String = "" |
||||
private var tasks = CompositeCoroutine() |
||||
private var bookSourceList = arrayListOf<BookSource>() |
||||
|
||||
@Volatile |
||||
private var searchIndex = -1 |
||||
|
||||
private fun initSearchPool() { |
||||
searchPool = Executors.newFixedThreadPool(threadCount).asCoroutineDispatcher() |
||||
} |
||||
|
||||
fun search(searchId: Long, key: String) { |
||||
callBack.onSearchStart() |
||||
if (searchId != mSearchId) { |
||||
if (key.isEmpty()) { |
||||
callBack.onSearchCancel() |
||||
return |
||||
} else { |
||||
this.searchKey = key |
||||
} |
||||
if (mSearchId != 0L) { |
||||
close() |
||||
} |
||||
initSearchPool() |
||||
mSearchId = searchId |
||||
searchPage = 1 |
||||
val searchGroup = App.INSTANCE.getPrefString("searchGroup") ?: "" |
||||
bookSourceList.clear() |
||||
if (searchGroup.isBlank()) { |
||||
bookSourceList.addAll(App.db.bookSourceDao().allEnabled) |
||||
} else { |
||||
bookSourceList.addAll(App.db.bookSourceDao().getEnabledByGroup(searchGroup)) |
||||
} |
||||
} else { |
||||
searchPage++ |
||||
} |
||||
searchIndex = -1 |
||||
for (i in 0 until threadCount) { |
||||
search(searchId) |
||||
} |
||||
} |
||||
|
||||
private fun search(searchId: Long) { |
||||
synchronized(this) { |
||||
if (searchIndex >= bookSourceList.lastIndex) { |
||||
return |
||||
} |
||||
searchIndex++ |
||||
val source = bookSourceList[searchIndex] |
||||
val task = WebBook(source).searchBook( |
||||
searchKey, |
||||
searchPage, |
||||
scope = scope, |
||||
context = searchPool!! |
||||
).timeout(30000L) |
||||
.onSuccess(IO) { |
||||
if (searchId == mSearchId) { |
||||
callBack.onSearchSuccess(it) |
||||
} |
||||
} |
||||
.onFinally { |
||||
synchronized(this) { |
||||
if (searchIndex < bookSourceList.lastIndex) { |
||||
search(searchId) |
||||
} else { |
||||
searchIndex++ |
||||
} |
||||
if (searchIndex >= bookSourceList.lastIndex + min(bookSourceList.size, |
||||
threadCount) |
||||
) { |
||||
callBack.onSearchFinish() |
||||
} |
||||
} |
||||
} |
||||
tasks.add(task) |
||||
} |
||||
} |
||||
|
||||
fun cancelSearch() { |
||||
close() |
||||
callBack.onSearchCancel() |
||||
} |
||||
|
||||
fun close() { |
||||
tasks.clear() |
||||
searchPool?.close() |
||||
mSearchId = 0L |
||||
} |
||||
|
||||
interface CallBack { |
||||
fun onSearchStart() |
||||
fun onSearchSuccess(searchBooks: ArrayList<SearchBook>) |
||||
fun onSearchFinish() |
||||
fun onSearchCancel() |
||||
} |
||||
|
||||
} |
@ -0,0 +1,164 @@ |
||||
package io.legado.app.ui.book.read.config |
||||
|
||||
import android.annotation.SuppressLint |
||||
import android.content.Context |
||||
import android.os.Bundle |
||||
import android.util.DisplayMetrics |
||||
import android.view.LayoutInflater |
||||
import android.view.MenuItem |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import androidx.appcompat.widget.Toolbar |
||||
import androidx.lifecycle.LiveData |
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import io.legado.app.App |
||||
import io.legado.app.R |
||||
import io.legado.app.base.BaseDialogFragment |
||||
import io.legado.app.base.adapter.ItemViewHolder |
||||
import io.legado.app.base.adapter.SimpleRecyclerAdapter |
||||
import io.legado.app.constant.PreferKey |
||||
import io.legado.app.data.entities.HttpTTS |
||||
import io.legado.app.lib.dialogs.alert |
||||
import io.legado.app.lib.dialogs.cancelButton |
||||
import io.legado.app.lib.dialogs.customView |
||||
import io.legado.app.lib.dialogs.okButton |
||||
import io.legado.app.lib.theme.primaryColor |
||||
import io.legado.app.service.help.ReadAloud |
||||
import io.legado.app.utils.* |
||||
import kotlinx.android.synthetic.main.dialog_http_tts_edit.view.* |
||||
import kotlinx.android.synthetic.main.dialog_recycler_view.* |
||||
import kotlinx.android.synthetic.main.item_http_tts.view.* |
||||
import org.jetbrains.anko.sdk27.listeners.onClick |
||||
|
||||
class SpeakEngineDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { |
||||
|
||||
override fun onStart() { |
||||
super.onStart() |
||||
val dm = DisplayMetrics() |
||||
activity?.windowManager?.defaultDisplay?.getMetrics(dm) |
||||
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) |
||||
} |
||||
|
||||
lateinit var adapter: Adapter |
||||
lateinit var viewModel: SpeakEngineViewModel |
||||
private var httpTTSData: LiveData<List<HttpTTS>>? = null |
||||
var engineId = App.INSTANCE.getPrefLong(PreferKey.speakEngine) |
||||
|
||||
override fun onCreateView( |
||||
inflater: LayoutInflater, |
||||
container: ViewGroup?, |
||||
savedInstanceState: Bundle? |
||||
): View? { |
||||
viewModel = getViewModel(SpeakEngineViewModel::class.java) |
||||
return inflater.inflate(R.layout.dialog_recycler_view, container) |
||||
} |
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { |
||||
initView() |
||||
initMenu() |
||||
initData() |
||||
} |
||||
|
||||
private fun initView() { |
||||
tool_bar.setBackgroundColor(primaryColor) |
||||
tool_bar.setTitle(R.string.speak_engine) |
||||
recycler_view.layoutManager = LinearLayoutManager(requireContext()) |
||||
adapter = Adapter(requireContext()) |
||||
recycler_view.adapter = adapter |
||||
tv_footer_left.setText(R.string.local_tts) |
||||
tv_footer_left.visible() |
||||
tv_footer_left.onClick { |
||||
removePref(PreferKey.speakEngine) |
||||
dismiss() |
||||
} |
||||
tv_ok.visible() |
||||
tv_ok.onClick { |
||||
putPrefLong(PreferKey.speakEngine, engineId) |
||||
dismiss() |
||||
} |
||||
tv_cancel.visible() |
||||
tv_cancel.onClick { |
||||
dismiss() |
||||
} |
||||
} |
||||
|
||||
private fun initMenu() { |
||||
tool_bar.inflateMenu(R.menu.speak_engine) |
||||
tool_bar.menu.applyTint(requireContext()) |
||||
tool_bar.setOnMenuItemClickListener(this) |
||||
} |
||||
|
||||
private fun initData() { |
||||
httpTTSData?.removeObservers(this) |
||||
httpTTSData = App.db.httpTTSDao().observeAll() |
||||
httpTTSData?.observe(this, { |
||||
adapter.setItems(it) |
||||
}) |
||||
} |
||||
|
||||
override fun onMenuItemClick(item: MenuItem?): Boolean { |
||||
when (item?.itemId) { |
||||
R.id.menu_add -> editHttpTTS() |
||||
R.id.menu_default -> viewModel.importDefault() |
||||
} |
||||
return true |
||||
} |
||||
|
||||
@SuppressLint("InflateParams") |
||||
private fun editHttpTTS(v: HttpTTS? = null) { |
||||
val httpTTS = v?.copy() ?: HttpTTS() |
||||
requireContext().alert(titleResource = R.string.speak_engine) { |
||||
var rootView: View? = null |
||||
customView { |
||||
LayoutInflater.from(requireContext()) |
||||
.inflate(R.layout.dialog_http_tts_edit, null).apply { |
||||
rootView = this |
||||
tv_name.setText(httpTTS.name) |
||||
tv_url.setText(httpTTS.url) |
||||
} |
||||
} |
||||
cancelButton() |
||||
okButton { |
||||
rootView?.apply { |
||||
httpTTS.name = tv_name.text.toString() |
||||
httpTTS.url = tv_url.text.toString() |
||||
App.db.httpTTSDao().insert(httpTTS) |
||||
ReadAloud.upReadAloudClass() |
||||
} |
||||
} |
||||
}.show().applyTint() |
||||
} |
||||
|
||||
inner class Adapter(context: Context) : |
||||
SimpleRecyclerAdapter<HttpTTS>(context, R.layout.item_http_tts) { |
||||
|
||||
override fun convert(holder: ItemViewHolder, item: HttpTTS, payloads: MutableList<Any>) { |
||||
holder.itemView.apply { |
||||
cb_name.text = item.name |
||||
cb_name.isChecked = item.id == engineId |
||||
} |
||||
} |
||||
|
||||
override fun registerListener(holder: ItemViewHolder) { |
||||
holder.itemView.apply { |
||||
cb_name.onClick { |
||||
getItem(holder.layoutPosition)?.let { httpTTS -> |
||||
engineId = httpTTS.id |
||||
notifyItemRangeChanged(0, getActualItemCount()) |
||||
} |
||||
} |
||||
iv_edit.onClick { |
||||
editHttpTTS(getItem(holder.layoutPosition)) |
||||
} |
||||
iv_menu_delete.onClick { |
||||
getItem(holder.layoutPosition)?.let { httpTTS -> |
||||
App.db.httpTTSDao().delete(httpTTS) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,34 @@ |
||||
package io.legado.app.ui.book.read.config |
||||
|
||||
import android.app.Application |
||||
import io.legado.app.App |
||||
import io.legado.app.base.BaseViewModel |
||||
import io.legado.app.data.entities.TxtTocRule |
||||
import io.legado.app.help.DefaultValueHelp |
||||
import io.legado.app.help.http.HttpHelper |
||||
import io.legado.app.utils.GSON |
||||
import io.legado.app.utils.fromJsonArray |
||||
|
||||
class SpeakEngineViewModel(application: Application) : BaseViewModel(application) { |
||||
|
||||
fun importDefault() { |
||||
execute { |
||||
DefaultValueHelp.initHttpTTS() |
||||
} |
||||
} |
||||
|
||||
fun importOnLine(url: String, finally: (msg: String) -> Unit) { |
||||
execute { |
||||
HttpHelper.simpleGetAsync(url)?.let { json -> |
||||
GSON.fromJsonArray<TxtTocRule>(json)?.let { |
||||
App.db.txtTocRule().insert(*it.toTypedArray()) |
||||
} |
||||
} |
||||
}.onSuccess { |
||||
finally("导入成功") |
||||
}.onError { |
||||
finally("导入失败") |
||||
} |
||||
} |
||||
|
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue