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? = 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 = 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)) } } }