2019-06-11 15:56:27 +02:00
|
|
|
package com.keylesspalace.tusky.components.instancemute.fragment
|
|
|
|
|
|
|
|
import android.os.Bundle
|
|
|
|
import android.util.Log
|
|
|
|
import android.view.View
|
2021-01-31 19:34:33 +01:00
|
|
|
import androidx.fragment.app.Fragment
|
2019-06-11 15:56:27 +02:00
|
|
|
import androidx.lifecycle.Lifecycle
|
2023-03-18 10:11:47 +01:00
|
|
|
import androidx.lifecycle.lifecycleScope
|
2019-06-11 15:56:27 +02:00
|
|
|
import androidx.recyclerview.widget.DividerItemDecoration
|
|
|
|
import androidx.recyclerview.widget.LinearLayoutManager
|
|
|
|
import androidx.recyclerview.widget.RecyclerView
|
2023-03-18 10:11:47 +01:00
|
|
|
import at.connyduck.calladapter.networkresult.fold
|
2021-05-16 19:53:27 +02:00
|
|
|
import autodispose2.androidx.lifecycle.AndroidLifecycleScopeProvider.from
|
|
|
|
import autodispose2.autoDispose
|
2019-06-11 15:56:27 +02:00
|
|
|
import com.google.android.material.snackbar.Snackbar
|
|
|
|
import com.keylesspalace.tusky.R
|
|
|
|
import com.keylesspalace.tusky.components.instancemute.adapter.DomainMutesAdapter
|
|
|
|
import com.keylesspalace.tusky.components.instancemute.interfaces.InstanceActionListener
|
2021-03-13 21:27:20 +01:00
|
|
|
import com.keylesspalace.tusky.databinding.FragmentInstanceListBinding
|
2019-06-11 15:56:27 +02:00
|
|
|
import com.keylesspalace.tusky.di.Injectable
|
|
|
|
import com.keylesspalace.tusky.network.MastodonApi
|
|
|
|
import com.keylesspalace.tusky.util.HttpHeaderLink
|
|
|
|
import com.keylesspalace.tusky.util.hide
|
|
|
|
import com.keylesspalace.tusky.util.show
|
2021-03-13 21:27:20 +01:00
|
|
|
import com.keylesspalace.tusky.util.viewBinding
|
2019-06-11 15:56:27 +02:00
|
|
|
import com.keylesspalace.tusky.view.EndlessOnScrollListener
|
2021-05-16 19:53:27 +02:00
|
|
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
2023-03-18 10:11:47 +01:00
|
|
|
import kotlinx.coroutines.launch
|
2019-06-11 15:56:27 +02:00
|
|
|
import java.io.IOException
|
|
|
|
import javax.inject.Inject
|
|
|
|
|
2021-06-28 21:13:24 +02:00
|
|
|
class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectable, InstanceActionListener {
|
2021-03-13 21:27:20 +01:00
|
|
|
|
2019-06-11 15:56:27 +02:00
|
|
|
@Inject
|
|
|
|
lateinit var api: MastodonApi
|
|
|
|
|
2021-03-13 21:27:20 +01:00
|
|
|
private val binding by viewBinding(FragmentInstanceListBinding::bind)
|
|
|
|
|
2019-06-11 15:56:27 +02:00
|
|
|
private var fetching = false
|
|
|
|
private var bottomId: String? = null
|
|
|
|
private var adapter = DomainMutesAdapter(this)
|
|
|
|
private lateinit var scrollListener: EndlessOnScrollListener
|
|
|
|
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
|
|
super.onViewCreated(view, savedInstanceState)
|
|
|
|
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.recyclerView.setHasFixedSize(true)
|
|
|
|
binding.recyclerView.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL))
|
|
|
|
binding.recyclerView.adapter = adapter
|
2019-06-11 15:56:27 +02:00
|
|
|
|
|
|
|
val layoutManager = LinearLayoutManager(view.context)
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.recyclerView.layoutManager = layoutManager
|
2019-06-11 15:56:27 +02:00
|
|
|
|
|
|
|
scrollListener = object : EndlessOnScrollListener(layoutManager) {
|
|
|
|
override fun onLoadMore(totalItemsCount: Int, view: RecyclerView) {
|
|
|
|
if (bottomId != null) {
|
|
|
|
fetchInstances(bottomId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.recyclerView.addOnScrollListener(scrollListener)
|
2019-06-11 15:56:27 +02:00
|
|
|
fetchInstances()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun mute(mute: Boolean, instance: String, position: Int) {
|
2023-03-18 10:11:47 +01:00
|
|
|
viewLifecycleOwner.lifecycleScope.launch {
|
|
|
|
if (mute) {
|
|
|
|
api.blockDomain(instance).fold({
|
|
|
|
adapter.addItem(instance)
|
|
|
|
}, { e ->
|
|
|
|
Log.e(TAG, "Error muting domain $instance", e)
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
api.unblockDomain(instance).fold({
|
|
|
|
adapter.removeItem(position)
|
|
|
|
Snackbar.make(binding.recyclerView, getString(R.string.confirmation_domain_unmuted, instance), Snackbar.LENGTH_LONG)
|
|
|
|
.setAction(R.string.action_undo) {
|
|
|
|
mute(true, instance, position)
|
|
|
|
}
|
|
|
|
.show()
|
|
|
|
}, { e ->
|
|
|
|
Log.e(TAG, "Error unmuting domain $instance", e)
|
|
|
|
})
|
|
|
|
}
|
2019-06-11 15:56:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun fetchInstances(id: String? = null) {
|
|
|
|
if (fetching) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fetching = true
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.instanceProgressBar.show()
|
2019-06-11 15:56:27 +02:00
|
|
|
|
|
|
|
if (id != null) {
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.recyclerView.post { adapter.bottomLoading = true }
|
2019-06-11 15:56:27 +02:00
|
|
|
}
|
|
|
|
|
2019-09-22 08:18:44 +02:00
|
|
|
api.domainBlocks(id, bottomId)
|
2021-06-28 21:13:24 +02:00
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.autoDispose(from(this, Lifecycle.Event.ON_DESTROY))
|
|
|
|
.subscribe(
|
|
|
|
{ response ->
|
2019-06-11 15:56:27 +02:00
|
|
|
val instances = response.body()
|
|
|
|
|
|
|
|
if (response.isSuccessful && instances != null) {
|
2021-03-13 21:27:20 +01:00
|
|
|
onFetchInstancesSuccess(instances, response.headers()["Link"])
|
2019-06-11 15:56:27 +02:00
|
|
|
} else {
|
|
|
|
onFetchInstancesFailure(Exception(response.message()))
|
|
|
|
}
|
2021-06-28 21:13:24 +02:00
|
|
|
},
|
|
|
|
{ throwable ->
|
2019-06-11 15:56:27 +02:00
|
|
|
onFetchInstancesFailure(throwable)
|
2021-06-28 21:13:24 +02:00
|
|
|
}
|
|
|
|
)
|
2019-06-11 15:56:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun onFetchInstancesSuccess(instances: List<String>, linkHeader: String?) {
|
|
|
|
adapter.bottomLoading = false
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.instanceProgressBar.hide()
|
2019-06-11 15:56:27 +02:00
|
|
|
|
|
|
|
val links = HttpHeaderLink.parse(linkHeader)
|
|
|
|
val next = HttpHeaderLink.findByRelationType(links, "next")
|
|
|
|
val fromId = next?.uri?.getQueryParameter("max_id")
|
|
|
|
adapter.addItems(instances)
|
|
|
|
bottomId = fromId
|
|
|
|
fetching = false
|
|
|
|
|
|
|
|
if (adapter.itemCount == 0) {
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.messageView.show()
|
|
|
|
binding.messageView.setup(
|
2021-06-28 21:13:24 +02:00
|
|
|
R.drawable.elephant_friend_empty,
|
|
|
|
R.string.message_empty,
|
|
|
|
null
|
2019-06-11 15:56:27 +02:00
|
|
|
)
|
|
|
|
} else {
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.messageView.hide()
|
2019-06-11 15:56:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun onFetchInstancesFailure(throwable: Throwable) {
|
|
|
|
fetching = false
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.instanceProgressBar.hide()
|
2019-06-11 15:56:27 +02:00
|
|
|
Log.e(TAG, "Fetch failure", throwable)
|
|
|
|
|
|
|
|
if (adapter.itemCount == 0) {
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.messageView.show()
|
2019-06-11 15:56:27 +02:00
|
|
|
if (throwable is IOException) {
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.messageView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
|
|
|
binding.messageView.hide()
|
2019-06-11 15:56:27 +02:00
|
|
|
this.fetchInstances(null)
|
|
|
|
}
|
|
|
|
} else {
|
2021-03-13 21:27:20 +01:00
|
|
|
binding.messageView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
|
|
|
binding.messageView.hide()
|
2019-06-11 15:56:27 +02:00
|
|
|
this.fetchInstances(null)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
private const val TAG = "InstanceList" // logging tag
|
|
|
|
}
|
2021-06-28 21:13:24 +02:00
|
|
|
}
|