SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/ActHighlightWordList.kt

231 lines
7.3 KiB
Kotlin

package jp.juggler.subwaytooter
import android.content.Context
import android.media.Ringtone
import android.media.RingtoneManager
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.BaseAdapter
import androidx.appcompat.app.AppCompatActivity
import jp.juggler.subwaytooter.databinding.ActHighlightListBinding
import jp.juggler.subwaytooter.databinding.LvHighlightWordBinding
import jp.juggler.subwaytooter.dialog.DlgConfirm.confirm
import jp.juggler.subwaytooter.table.HighlightWord
import jp.juggler.subwaytooter.table.daoHighlightWord
import jp.juggler.util.coroutine.AppDispatchers
import jp.juggler.util.coroutine.launchAndShowError
import jp.juggler.util.data.cast
import jp.juggler.util.data.mayUri
import jp.juggler.util.data.notBlank
import jp.juggler.util.data.notZero
import jp.juggler.util.log.LogCategory
import jp.juggler.util.ui.*
import kotlinx.coroutines.withContext
import java.lang.ref.WeakReference
class ActHighlightWordList : AppCompatActivity() {
companion object {
private val log = LogCategory("ActHighlightWordList")
private var lastRingtone: WeakReference<Ringtone>? = null
private fun stopLastRingtone() {
try {
lastRingtone?.get()?.stop()
} catch (ex: Throwable) {
log.e(ex, "stopLastRingtone failed.")
} finally {
lastRingtone = null
}
}
private fun tryRingTone(context: Context, uri: Uri?): Boolean {
try {
uri?.let { RingtoneManager.getRingtone(context, it) }
?.let { ringtone ->
stopLastRingtone()
lastRingtone = WeakReference(ringtone)
ringtone.play()
return true
}
} catch (ex: Throwable) {
log.e(ex, "tryRingTone failed.")
}
// fall null case
return false
}
fun sound(context: Context, item: HighlightWord?) {
if (lastRingtone?.get()?.isPlaying == true) {
stopLastRingtone()
return
}
item ?: return
val soundType = item.sound_type
when {
// サウンドなし
soundType == HighlightWord.SOUND_TYPE_NONE -> Unit
// カスタムサウンドを鳴らせた
soundType == HighlightWord.SOUND_TYPE_CUSTOM && tryRingTone(
context,
item.sound_uri.mayUri()
) -> Unit
// 失敗した場合も通常の音を鳴らす
else -> tryRingTone(
context,
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
)
}
}
}
private val views by lazy {
ActHighlightListBinding.inflate(layoutInflater)
}
private lateinit var listAdapter: MyListAdapter
private val arEdit = ActivityResultHandler(log) { r ->
if (r.isNotOk) return@ActivityResultHandler
loadData()
}
// @Override public void onBackPressed(){
// setResult( RESULT_OK );
// super.onBackPressed();
// }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arEdit.register(this)
App1.setActivityTheme(this)
initUI()
loadData()
}
override fun onDestroy() {
super.onDestroy()
stopLastRingtone()
}
private fun initUI() {
setContentView(views.root)
setSupportActionBar(views.toolbar)
setNavigationBack(views.toolbar)
fixHorizontalMargin(views.llContent)
// リストのアダプター
listAdapter = MyListAdapter()
// ハンドル部分をドラッグで並べ替えできるRecyclerView
views.listView.adapter = listAdapter
views.listView.onItemClickListener = listAdapter
views.btnAdd.setOnClickListener { create() }
}
private fun loadData() {
launchAndShowError {
listAdapter.items = withContext(AppDispatchers.IO) {
daoHighlightWord.listAll()
}
}
}
private fun create() {
arEdit.launch(ActHighlightWordEdit.createIntent(this, ""))
}
private fun edit(item: HighlightWord?) {
item ?: return
arEdit.launch(ActHighlightWordEdit.createIntent(this, item.id))
}
private fun delete(item: HighlightWord?) {
item ?: return
val activity = this
launchAndShowError {
confirm(getString(R.string.delete_confirm, item.name))
daoHighlightWord.delete(applicationContext, item)
listAdapter.remove(item)
App1.getAppState(activity).enableSpeech()
}
}
private fun speech(item: HighlightWord?) {
item?.name?.notBlank()?.let {
App1.getAppState(this@ActHighlightWordList)
.addSpeech(it, dedupMode = DedupMode.None)
}
}
// リスト要素のViewHolder
private inner class MyViewHolder(
parent: ViewGroup?,
) {
val views = LvHighlightWordBinding.inflate(layoutInflater, parent, false)
private var lastItem: HighlightWord? = null
init {
views.root.tag = this
views.btnSound.setOnClickListener { sound(this@ActHighlightWordList, lastItem) }
views.btnSpeech.setOnClickListener { speech(lastItem) }
views.btnDelete.setOnClickListener { delete(lastItem) }
}
fun bind(item: HighlightWord?) {
item ?: return
lastItem = item
views.tvName.text = item.name
views.tvName.setBackgroundColor(item.color_bg)
views.tvName.setTextColor(
item.color_fg.notZero()
?: attrColor(android.R.attr.textColorPrimary)
)
views.btnSound.isEnabledAlpha = item.sound_type != HighlightWord.SOUND_TYPE_NONE
views.btnSpeech.isEnabledAlpha = item.speech != 0
}
}
private inner class MyListAdapter : BaseAdapter(), AdapterView.OnItemClickListener {
var items: List<HighlightWord> = emptyList()
set(value) {
field = value
notifyDataSetChanged()
}
fun remove(item: HighlightWord) {
items = items.filter { it != item }
}
override fun getCount() = items.size
override fun getItem(position: Int) = items.elementAtOrNull(position)
override fun getItemId(position: Int) = 0L
override fun getView(position: Int, convertView: View?, parent: ViewGroup?) =
(convertView?.tag?.cast() ?: MyViewHolder(parent))
.also { it.bind(items.elementAtOrNull(position)) }
.views.root
override fun onItemClick(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long,
) {
edit(items.elementAtOrNull(position))
}
}
}