package com.keylesspalace.tusky import android.os.Bundle import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.lifecycle.lifecycleScope import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.PreferenceChangedEvent import com.keylesspalace.tusky.databinding.ActivityFiltersBinding import com.keylesspalace.tusky.databinding.DialogFilterBinding import com.keylesspalace.tusky.entity.Filter import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.util.hide import com.keylesspalace.tusky.util.show import com.keylesspalace.tusky.util.viewBinding import kotlinx.coroutines.launch import kotlinx.coroutines.rx3.await import okhttp3.ResponseBody import retrofit2.Call import retrofit2.Callback import retrofit2.Response import java.io.IOException import java.lang.Exception import javax.inject.Inject class FiltersActivity: BaseActivity() { @Inject lateinit var api: MastodonApi @Inject lateinit var eventHub: EventHub private val binding by viewBinding(ActivityFiltersBinding::inflate) private lateinit var context : String private lateinit var filters: MutableList override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) setSupportActionBar(binding.includedToolbar.toolbar) supportActionBar?.run { // Back button setDisplayHomeAsUpEnabled(true) setDisplayShowHomeEnabled(true) } binding.addFilterButton.setOnClickListener { showAddFilterDialog() } title = intent?.getStringExtra(FILTERS_TITLE) context = intent?.getStringExtra(FILTERS_CONTEXT)!! loadFilters() } private fun updateFilter(filter: Filter, itemIndex: Int) { api.updateFilter(filter.id, filter.phrase, filter.context, filter.irreversible, filter.wholeWord, filter.expiresAt) .enqueue(object: Callback{ override fun onFailure(call: Call, t: Throwable) { Toast.makeText(this@FiltersActivity, "Error updating filter '${filter.phrase}'", Toast.LENGTH_SHORT).show() } override fun onResponse(call: Call, response: Response) { val updatedFilter = response.body()!! if (updatedFilter.context.contains(context)) { filters[itemIndex] = updatedFilter } else { filters.removeAt(itemIndex) } refreshFilterDisplay() eventHub.dispatch(PreferenceChangedEvent(context)) } }) } private fun deleteFilter(itemIndex: Int) { val filter = filters[itemIndex] if (filter.context.size == 1) { // This is the only context for this filter; delete it api.deleteFilter(filters[itemIndex].id).enqueue(object: Callback { override fun onFailure(call: Call, t: Throwable) { Toast.makeText(this@FiltersActivity, "Error updating filter '${filters[itemIndex].phrase}'", Toast.LENGTH_SHORT).show() } override fun onResponse(call: Call, response: Response) { filters.removeAt(itemIndex) refreshFilterDisplay() eventHub.dispatch(PreferenceChangedEvent(context)) } }) } else { // Keep the filter, but remove it from this context val oldFilter = filters[itemIndex] val newFilter = Filter(oldFilter.id, oldFilter.phrase, oldFilter.context.filter { c -> c != context }, oldFilter.expiresAt, oldFilter.irreversible, oldFilter.wholeWord) updateFilter(newFilter, itemIndex) } } private fun createFilter(phrase: String, wholeWord: Boolean) { api.createFilter(phrase, listOf(context), false, wholeWord, "").enqueue(object: Callback { override fun onResponse(call: Call, response: Response) { val filterResponse = response.body() if(response.isSuccessful && filterResponse != null) { filters.add(filterResponse) refreshFilterDisplay() eventHub.dispatch(PreferenceChangedEvent(context)) } else { Toast.makeText(this@FiltersActivity, "Error creating filter '$phrase'", Toast.LENGTH_SHORT).show() } } override fun onFailure(call: Call, t: Throwable) { Toast.makeText(this@FiltersActivity, "Error creating filter '$phrase'", Toast.LENGTH_SHORT).show() } }) } private fun showAddFilterDialog() { val binding = DialogFilterBinding.inflate(layoutInflater) binding.phraseWholeWord.isChecked = true AlertDialog.Builder(this@FiltersActivity) .setTitle(R.string.filter_addition_dialog_title) .setView(binding.root) .setPositiveButton(android.R.string.ok){ _, _ -> createFilter(binding.phraseEditText.text.toString(), binding.phraseWholeWord.isChecked) } .setNeutralButton(android.R.string.cancel, null) .show() } private fun setupEditDialogForItem(itemIndex: Int) { val binding = DialogFilterBinding.inflate(layoutInflater) val filter = filters[itemIndex] binding.phraseEditText.setText(filter.phrase) binding.phraseWholeWord.isChecked = filter.wholeWord AlertDialog.Builder(this@FiltersActivity) .setTitle(R.string.filter_edit_dialog_title) .setView(binding.root) .setPositiveButton(R.string.filter_dialog_update_button) { _, _ -> val oldFilter = filters[itemIndex] val newFilter = Filter(oldFilter.id, binding.phraseEditText.text.toString(), oldFilter.context, oldFilter.expiresAt, oldFilter.irreversible, binding.phraseWholeWord.isChecked) updateFilter(newFilter, itemIndex) } .setNegativeButton(R.string.filter_dialog_remove_button) { _, _ -> deleteFilter(itemIndex) } .setNeutralButton(android.R.string.cancel, null) .show() } private fun refreshFilterDisplay() { binding.filtersView.adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, filters.map { filter -> filter.phrase }) binding.filtersView.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> setupEditDialogForItem(position) } } private fun loadFilters() { binding.filterMessageView.hide() binding.filtersView.hide() binding.addFilterButton.hide() binding.filterProgressBar.show() lifecycleScope.launch { val newFilters = try { api.getFilters().await() } catch (t: Exception) { binding.filterProgressBar.hide() binding.filterMessageView.show() if (t is IOException) { binding.filterMessageView.setup(R.drawable.elephant_offline, R.string.error_network) { loadFilters() } } else { binding.filterMessageView.setup(R.drawable.elephant_error, R.string.error_generic) { loadFilters() } } return@launch } filters = newFilters.filter { it.context.contains(context) }.toMutableList() refreshFilterDisplay() binding.filtersView.show() binding.addFilterButton.show() binding.filterProgressBar.hide() } } companion object { const val FILTERS_CONTEXT = "filters_context" const val FILTERS_TITLE = "filters_title" } }