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

239 lines
7.8 KiB
Kotlin

package jp.juggler.subwaytooter
import android.app.SearchManager
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import jp.juggler.subwaytooter.api.entity.TootAccount
import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.subwaytooter.auth.AuthRepo
import jp.juggler.subwaytooter.databinding.ActTextBinding
import jp.juggler.subwaytooter.dialog.pickAccount
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.daoMutedWord
import jp.juggler.subwaytooter.table.daoSavedAccount
import jp.juggler.subwaytooter.util.CustomShare
import jp.juggler.subwaytooter.util.CustomShareTarget
import jp.juggler.subwaytooter.util.TootTextEncoder
import jp.juggler.subwaytooter.util.copyToClipboard
import jp.juggler.util.*
import jp.juggler.util.coroutine.launchAndShowError
import jp.juggler.util.coroutine.launchMain
import jp.juggler.util.data.*
import jp.juggler.util.log.LogCategory
import jp.juggler.util.log.showToast
import jp.juggler.util.ui.*
class ActText : AppCompatActivity() {
companion object {
internal val log = LogCategory("ActText")
// internal const val RESULT_SEARCH_MSP = RESULT_FIRST_USER + 1
// internal const val RESULT_SEARCH_TS = RESULT_FIRST_USER + 2
internal const val RESULT_SEARCH_NOTESTOCK = RESULT_FIRST_USER + 3
internal const val EXTRA_TEXT = "text"
internal const val EXTRA_CONTENT_START = "content_start"
internal const val EXTRA_CONTENT_END = "content_end"
internal const val EXTRA_ACCOUNT_DB_ID = "account_db_id"
fun createIntent(
activity: ActMain,
accessInfo: SavedAccount,
status: TootStatus,
) = Intent(activity, ActText::class.java).apply {
putExtra(EXTRA_ACCOUNT_DB_ID, accessInfo.db_id)
TootTextEncoder.encodeStatus(this, activity, accessInfo, status)
}
fun createIntent(
activity: ActMain,
accessInfo: SavedAccount,
who: TootAccount,
) = Intent(activity, ActText::class.java).apply {
putExtra(EXTRA_ACCOUNT_DB_ID, accessInfo.db_id)
TootTextEncoder.encodeAccount(this, activity, accessInfo, who)
}
}
private var account: SavedAccount? = null
private val views by lazy {
ActTextBinding.inflate(layoutInflater)
}
private val selection: String
get() {
val et = views.etText
val s = et.selectionStart
val e = et.selectionEnd
val text = et.text.toString()
return if (s == e) {
text
} else {
text.substring(s, e)
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.btnCopy -> selection.copyToClipboard(this)
R.id.btnSearch -> search()
R.id.btnSend -> send()
R.id.btnMuteWord -> muteWord()
R.id.btnTranslate -> CustomShare.invokeText(
CustomShareTarget.Translate,
this,
selection,
)
// MSP検索ボタン -> searchToot(RESULT_SEARCH_MSP)
// R.id.btnSearchTS -> searchToot(RESULT_SEARCH_TS)
R.id.btnSearchNotestock -> searchToot(RESULT_SEARCH_NOTESTOCK)
R.id.btnKeywordFilter -> keywordFilter()
R.id.btnHighlight -> highlight()
// If we got here, the user's action was not recognized.
// Invoke the superclass to handle it.
else -> return super.onOptionsItemSelected(item)
}
return true
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.act_text, menu)
return super.onCreateOptionsMenu(menu)
}
private val authRepo by lazy {
AuthRepo(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
App1.setActivityTheme(this)
initUI()
launchAndShowError {
account = intent.long(EXTRA_ACCOUNT_DB_ID)
?.let { daoSavedAccount.loadAccount(it) }
if (savedInstanceState == null) {
val sv = intent.string(EXTRA_TEXT) ?: ""
val contentStart = intent.int(EXTRA_CONTENT_START) ?: 0
val contentEnd = intent.int(EXTRA_CONTENT_END) ?: sv.length
views.etText.setText(sv)
// Android 9 以降ではフォーカスがないとsetSelectionできない
if (Build.VERSION.SDK_INT >= 28) {
views.etText.requestFocus()
views.etText.hideKeyboard()
}
views.etText.setSelection(contentStart, contentEnd)
}
}
}
internal fun initUI() {
setContentView(views.root)
setSupportActionBar(views.toolbar)
setNavigationBack(views.toolbar)
fixHorizontalMargin(views.etText)
}
private fun send() {
selection.trim().notEmpty()?.let {
try {
val intent = Intent()
intent.action = Intent.ACTION_SEND
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_TEXT, it)
startActivity(intent)
} catch (ex: Throwable) {
log.e(ex, "send failed.")
showToast(ex, "send failed.")
}
}
}
private fun search() {
selection.trim().notEmpty()?.also {
try {
val intent = Intent(Intent.ACTION_WEB_SEARCH)
intent.putExtra(SearchManager.QUERY, it)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
} catch (ex: Throwable) {
log.e(ex, "search failed.")
showToast(ex, "search failed.")
}
}
}
private fun searchToot(@Suppress("SameParameterValue") resultCode: Int) {
selection.trim().notEmpty()?.let {
try {
val data = Intent()
data.putExtra(Intent.EXTRA_TEXT, it)
setResult(resultCode, data)
finish()
} catch (ex: Throwable) {
log.e(ex, "searchToot failed.")
showToast(ex, "searchToot failed.")
}
}
}
private fun muteWord() {
launchAndShowError {
selection.trim().notEmpty()?.let {
daoMutedWord.save(it)
App1.getAppState(this@ActText).onMuteUpdated()
showToast(false, R.string.word_was_muted)
}
}
}
private fun keywordFilter() {
selection.trim().notEmpty()?.let { text ->
val account = this.account
if (account?.isPseudo == false && account.isMastodon) {
ActKeywordFilter.open(this, account, initialPhrase = text)
} else {
launchMain {
pickAccount(
bAllowPseudo = false,
bAllowMisskey = false,
bAllowMastodon = true,
bAuto = false,
)?.let {
ActKeywordFilter.open(this@ActText, it, initialPhrase = text)
}
}
}
}
}
private fun highlight() {
selection.trim().notEmpty()?.let {
startActivity(ActHighlightWordEdit.createIntent(this, it))
}
}
}