ariane/app/src/main/java/oppen/tva/ui/TvaActivity.kt

194 lines
7.6 KiB
Kotlin

package oppen.tva.ui
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.inputmethod.EditorInfo
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
import oppen.tva.R
import oppen.tva.Tva
import oppen.tva.databinding.ActivityTvaBinding
import oppen.tva.io.GeminiResponse
import oppen.tva.io.RuntimeCache
import oppen.tva.io.TvaState
import oppen.tva.io.history.tabs.TabHistoryInterface
import oppen.tva.io.history.uris.HistoryInterface
import oppen.tva.ui.modals_menus.about.AboutDialog
import oppen.tva.ui.modals_menus.history.HistoryDialog
import oppen.tva.ui.modals_menus.input.InputDialog
import oppen.tva.ui.modals_menus.overflow.OverflowPopup
import oppen.tva.ui.modals_menus.set_home.SetHomeDialog
import oppen.tva.ui.modals_menus.tabs.NewTabPopup
import oppen.tva.ui.modals_menus.tabs.TabsDialog
import oppen.visibleRetainingSpace
class TvaActivity : AppCompatActivity() {
private val model by viewModels<TvaViewModel>()
private lateinit var binding: ActivityTvaBinding
private lateinit var history: HistoryInterface
private val adapter = GemtextAdapter { uri, longTap, view ->
if(longTap){
NewTabPopup.show(view){ menuId ->
when (menuId) {
R.id.link_menu_open_in_new_tab -> {
model.newTab(uri)
}
}
}
}else{
model.request(uri)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_tva)
binding.viewmodel = model
binding.lifecycleOwner = this
binding.gemtextRecycler.layoutManager = LinearLayoutManager(this)
binding.gemtextRecycler.adapter = adapter
history = HistoryInterface.default(this)
model.initialise(TabHistoryInterface.default(this)){ state ->
when(state){
is TvaState.AppQuery -> runOnUiThread{ showAlert("App backdoor/query not implemented yet") }
is TvaState.ResponseInput -> runOnUiThread { InputDialog.show(this, state){ queryAddress ->
model.request(queryAddress)
}
}
is TvaState.Requesting -> loadingView(true)
is TvaState.NotGeminiRequest -> externalProtocol(state)
is TvaState.ResponseError -> showAlert("${GeminiResponse.getCodeString(state.header.code)}: ${state.header.meta}")
is TvaState.ResponseGemtext -> renderGemtext(state)
is TvaState.ResponseText -> runOnUiThread{ showAlert("Plain text display not implemented") }
is TvaState.TabChange -> binding.tabCount.text = "${state.count}"
is TvaState.Blank -> {
binding.addressEdit.setText("")
adapter.render(arrayListOf())
}
}
}
binding.addressEdit.setOnEditorActionListener { _, actionId, _ ->
when (actionId) {
EditorInfo.IME_ACTION_GO -> {
model.request(binding.addressEdit.text.toString())
return@setOnEditorActionListener true
}
else -> return@setOnEditorActionListener false
}
}
binding.more.setOnClickListener {
OverflowPopup.show(binding.more){menuId ->
when (menuId) {
R.id.overflow_menu_share -> {
Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, binding.addressEdit.text.toString())
type = "text/plain"
startActivity(Intent.createChooser(this, null))
}
}
R.id.overflow_menu_reload -> {
val address = binding.addressEdit.text.toString()
RuntimeCache.remove(address)
model.request(address)
}
R.id.overflow_menu_history -> HistoryDialog.show(this){ historyAddress ->
model.request(historyAddress)
}
R.id.overflow_menu_about -> AboutDialog.show(this)
R.id.overflow_menu_set_home -> {
SetHomeDialog.show(this, binding.addressEdit.text.toString()){
showAlert("Home capsule updated")
}
}
R.id.overflow_menu_copy -> {
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.gemini_address), binding.addressEdit.text.toString())
clipboard.setPrimaryClip(clip)
Snackbar.make(binding.root, getString(R.string.address_copied_to_clipboard), Snackbar.LENGTH_SHORT).setAction(R.string.share) {
Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, binding.addressEdit.text.toString())
type = "text/plain"
startActivity(Intent.createChooser(this, null))
}
}.show()
}
}
}
}
binding.home.setOnClickListener {
val prefs = getSharedPreferences("oppen.tva.ui.dialogs.set_home", Context.MODE_PRIVATE)
val home = prefs.getString("home", Tva.DEFAULT_HOME_CAPSULE)
model.request(home!!)
}
binding.tabs.setOnClickListener {
TabsDialog().show(this, model)
}
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
intent?.data.toString().let{model.request(it)}
}
private fun showAlert(message: String) = runOnUiThread{
loadingView(false)
if(message.length > 40){
AlertDialog.Builder(this)
.setMessage(message)
.show()
}else {
Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show()
}
}
private fun externalProtocol(state: TvaState.NotGeminiRequest) = runOnUiThread {
loadingView(false)
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(state.uri.toString()))
startActivity(browserIntent)
}
private fun renderGemtext(state: TvaState.ResponseGemtext) = runOnUiThread {
loadingView(false)
binding.addressEdit.setText(state.uri.toString())
adapter.render(state.lines)
history.add(state.uri.toString())
}
private fun loadingView(visible: Boolean) = runOnUiThread {
binding.progressBar.visibleRetainingSpace(visible)
if(visible) binding.appBar.setExpanded(true)
}
@ExperimentalStdlibApi
override fun onBackPressed() {
if(model.canGoBack()){
model.goBack()
}else{
super.onBackPressed()
}
}
override fun onDestroy() {
super.onDestroy()
model.persistTabState()
}
}