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 |
package io.legado.app.data.entities |
||||||
|
|
||||||
import androidx.room.Entity |
import androidx.room.Entity |
||||||
import androidx.room.PrimaryKey |
|
||||||
|
|
||||||
@Entity(tableName = "readRecord") |
@Entity(tableName = "readRecord", primaryKeys = ["androidId", "bookName"]) |
||||||
data class ReadRecord( |
data class ReadRecord( |
||||||
@PrimaryKey |
var androidId: String = "", |
||||||
var bookName: String = "", |
var bookName: String = "", |
||||||
var readTime: Long = 0L |
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.RssArticle |
||||||
import io.legado.app.data.entities.RssSource |
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