More coroutinification
This commit is contained in:
parent
3a91b02e55
commit
1254a3566d
@ -12,10 +12,13 @@ import android.view.View
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.core.text.toSpanned
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.h.pixeldroid.R
|
||||
import com.h.pixeldroid.utils.api.PixelfedAPI
|
||||
import com.h.pixeldroid.utils.api.objects.Account.Companion.getAccountFromId
|
||||
import com.h.pixeldroid.utils.api.objects.Account.Companion.openAccountFromId
|
||||
import com.h.pixeldroid.utils.api.objects.Mention
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import java.net.URI
|
||||
import java.net.URISyntaxException
|
||||
import java.text.ParseException
|
||||
@ -51,7 +54,8 @@ fun parseHTMLText(
|
||||
mentions: List<Mention>?,
|
||||
api : PixelfedAPI,
|
||||
context: Context,
|
||||
credential: String
|
||||
credential: String,
|
||||
lifecycleScope: LifecycleCoroutineScope
|
||||
) : Spanned {
|
||||
//Convert text to spannable
|
||||
val content = fromHtml(text)
|
||||
@ -103,7 +107,9 @@ fun parseHTMLText(
|
||||
override fun onClick(widget: View) {
|
||||
Log.e("MENTION", "CLICKED")
|
||||
//Retrieve the account for the given profile
|
||||
getAccountFromId(accountId, api, context, credential)
|
||||
lifecycleScope.launchWhenCreated {
|
||||
openAccountFromId(accountId, api, context, credential)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.h.pixeldroid.posts
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.h.pixeldroid.R
|
||||
import com.h.pixeldroid.utils.api.objects.Report
|
||||
import com.h.pixeldroid.utils.api.objects.Status
|
||||
@ -10,7 +11,9 @@ import com.h.pixeldroid.utils.BaseActivity
|
||||
import kotlinx.android.synthetic.main.activity_report.*
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.HttpException
|
||||
import retrofit2.Response
|
||||
import java.io.IOException
|
||||
|
||||
class ReportActivity : BaseActivity() {
|
||||
|
||||
@ -37,34 +40,35 @@ class ReportActivity : BaseActivity() {
|
||||
|
||||
val accessToken = user?.accessToken.orEmpty()
|
||||
val api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db)
|
||||
|
||||
lifecycleScope.launchWhenCreated {
|
||||
try {
|
||||
api.report("Bearer $accessToken", status?.account?.id!!, listOf(status), textInputLayout.editText?.text.toString())
|
||||
.enqueue(object : Callback<Report> {
|
||||
override fun onResponse(
|
||||
call: Call<Report>,
|
||||
response: Response<Report>
|
||||
) {
|
||||
if (response.body() == null || !response.isSuccessful) {
|
||||
textInputLayout.error = getString(R.string.report_error)
|
||||
reportButton.visibility = View.VISIBLE
|
||||
textInputLayout.editText?.isEnabled = true
|
||||
reportProgressBar.visibility = View.GONE
|
||||
} else {
|
||||
|
||||
reportStatus(true)
|
||||
} catch (exception: IOException) {
|
||||
reportStatus(false)
|
||||
} catch (exception: HttpException) {
|
||||
reportStatus(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportStatus(success: Boolean){
|
||||
if(success){
|
||||
reportProgressBar.visibility = View.GONE
|
||||
reportButton.isEnabled = false
|
||||
reportButton.text = getString(R.string.reported)
|
||||
reportButton.visibility = View.VISIBLE
|
||||
} else {
|
||||
textInputLayout.error = getString(R.string.report_error)
|
||||
reportButton.visibility = View.VISIBLE
|
||||
textInputLayout.editText?.isEnabled = true
|
||||
reportProgressBar.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<Report>, t: Throwable) {
|
||||
Log.e("REPORT:", t.toString())
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
onBackPressed()
|
||||
return true
|
||||
|
@ -206,12 +206,24 @@ class StatusViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||
}.attach()
|
||||
}
|
||||
|
||||
private fun setDescription(rootView: View, api: PixelfedAPI, credential: String) {
|
||||
private fun setDescription(
|
||||
rootView: View,
|
||||
api: PixelfedAPI,
|
||||
credential: String,
|
||||
lifecycleScope: LifecycleCoroutineScope
|
||||
) {
|
||||
rootView.findViewById<TextView>(R.id.description).apply {
|
||||
if (status?.content.isNullOrBlank()) {
|
||||
visibility = View.GONE
|
||||
} else {
|
||||
text = parseHTMLText(status?.content.orEmpty(), status?.mentions, api, rootView.context, credential)
|
||||
text = parseHTMLText(
|
||||
status?.content.orEmpty(),
|
||||
status?.mentions,
|
||||
api,
|
||||
rootView.context,
|
||||
credential,
|
||||
lifecycleScope
|
||||
)
|
||||
movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
}
|
||||
@ -222,7 +234,7 @@ class StatusViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
val credential = "Bearer ${user.accessToken}"
|
||||
//Set the special HTML text
|
||||
setDescription(holder.view, api, credential)
|
||||
setDescription(holder.view, api, credential, lifecycleScope)
|
||||
|
||||
//Activate onclickListeners
|
||||
activateLiker(
|
||||
|
@ -10,7 +10,9 @@ import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
@ -53,7 +55,10 @@ class NotificationsFragment : CachedFeedFragment<Notification>() {
|
||||
|
||||
// get the view model
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
viewModel = ViewModelProvider(this, ViewModelFactory(db, db.notificationDao(), NotificationsRemoteMediator(apiHolder, db)))
|
||||
viewModel = ViewModelProvider(
|
||||
this,
|
||||
ViewModelFactory(db, db.notificationDao(), NotificationsRemoteMediator(apiHolder, db))
|
||||
)
|
||||
.get(FeedViewModel::class.java) as FeedViewModel<Notification>
|
||||
|
||||
launch()
|
||||
@ -62,7 +67,6 @@ class NotificationsFragment : CachedFeedFragment<Notification>() {
|
||||
return view
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* View Holder for a [Notification] RecyclerView list item.
|
||||
@ -105,25 +109,42 @@ class NotificationViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
}
|
||||
|
||||
|
||||
private fun setNotificationType(type: Notification.NotificationType,
|
||||
private fun setNotificationType(
|
||||
type: Notification.NotificationType,
|
||||
username: String,
|
||||
textView: TextView
|
||||
) {
|
||||
val context = textView.context
|
||||
val (format: String, drawable: Drawable?) = when (type) {
|
||||
Notification.NotificationType.follow -> {
|
||||
getStringAndDrawable(context, R.string.followed_notification, R.drawable.ic_follow)
|
||||
getStringAndDrawable(
|
||||
context,
|
||||
R.string.followed_notification,
|
||||
R.drawable.ic_follow
|
||||
)
|
||||
}
|
||||
Notification.NotificationType.mention -> {
|
||||
getStringAndDrawable(context, R.string.mention_notification, R.drawable.mention_at_24dp)
|
||||
getStringAndDrawable(
|
||||
context,
|
||||
R.string.mention_notification,
|
||||
R.drawable.mention_at_24dp
|
||||
)
|
||||
}
|
||||
|
||||
Notification.NotificationType.reblog -> {
|
||||
getStringAndDrawable(context, R.string.shared_notification, R.drawable.ic_reblog_blue)
|
||||
getStringAndDrawable(
|
||||
context,
|
||||
R.string.shared_notification,
|
||||
R.drawable.ic_reblog_blue
|
||||
)
|
||||
}
|
||||
|
||||
Notification.NotificationType.favourite -> {
|
||||
getStringAndDrawable(context, R.string.liked_notification, R.drawable.ic_like_full)
|
||||
getStringAndDrawable(
|
||||
context,
|
||||
R.string.liked_notification,
|
||||
R.drawable.ic_like_full
|
||||
)
|
||||
}
|
||||
Notification.NotificationType.poll -> {
|
||||
getStringAndDrawable(context, R.string.poll_notification, R.drawable.poll)
|
||||
@ -135,16 +156,25 @@ class NotificationViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
)
|
||||
}
|
||||
|
||||
private fun getStringAndDrawable(context: Context, stringToFormat: Int, drawable: Int): Pair<String, Drawable?>
|
||||
= Pair(context.getString(stringToFormat), ContextCompat.getDrawable(context, drawable))
|
||||
private fun getStringAndDrawable(
|
||||
context: Context,
|
||||
stringToFormat: Int,
|
||||
drawable: Int
|
||||
): Pair<String, Drawable?> =
|
||||
Pair(context.getString(stringToFormat), ContextCompat.getDrawable(context, drawable))
|
||||
|
||||
|
||||
|
||||
fun bind(notification: Notification?, api: PixelfedAPI, accessToken: String) {
|
||||
fun bind(
|
||||
notification: Notification?,
|
||||
api: PixelfedAPI,
|
||||
accessToken: String,
|
||||
lifecycleScope: LifecycleCoroutineScope
|
||||
) {
|
||||
|
||||
this.notification = notification
|
||||
|
||||
Glide.with(itemView).load(notification?.account?.avatar_static).circleCrop().into(avatar)
|
||||
Glide.with(itemView).load(notification?.account?.avatar_static).circleCrop()
|
||||
.into(avatar)
|
||||
|
||||
val previewUrl = notification?.status?.media_attachments?.getOrNull(0)?.preview_url
|
||||
if (!previewUrl.isNullOrBlank()) {
|
||||
@ -154,8 +184,23 @@ class NotificationViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
photoThumbnail.visibility = View.GONE
|
||||
}
|
||||
|
||||
notification?.type?.let { notification.account?.username?.let { username -> setNotificationType(it, username, notificationType) } }
|
||||
notification?.created_at?.let { setTextViewFromISO8601(it, notificationTime, false, itemView.context) }
|
||||
notification?.type?.let {
|
||||
notification.account?.username?.let { username ->
|
||||
setNotificationType(
|
||||
it,
|
||||
username,
|
||||
notificationType
|
||||
)
|
||||
}
|
||||
}
|
||||
notification?.created_at?.let {
|
||||
setTextViewFromISO8601(
|
||||
it,
|
||||
notificationTime,
|
||||
false,
|
||||
itemView.context
|
||||
)
|
||||
}
|
||||
|
||||
//Convert HTML to clickable text
|
||||
postDescription.text =
|
||||
@ -164,7 +209,8 @@ class NotificationViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
notification?.status?.mentions,
|
||||
api,
|
||||
itemView.context,
|
||||
"Bearer $accessToken"
|
||||
"Bearer $accessToken",
|
||||
lifecycleScope
|
||||
)
|
||||
}
|
||||
|
||||
@ -178,8 +224,24 @@ class NotificationViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
}
|
||||
|
||||
|
||||
class NotificationsAdapter(private val apiHolder: PixelfedAPIHolder, private val db: AppDatabase) : PagingDataAdapter<Notification, RecyclerView.ViewHolder>(
|
||||
UIMODEL_COMPARATOR
|
||||
inner class NotificationsAdapter(
|
||||
private val apiHolder: PixelfedAPIHolder,
|
||||
private val db: AppDatabase
|
||||
) : PagingDataAdapter<Notification, RecyclerView.ViewHolder>(
|
||||
object : DiffUtil.ItemCallback<Notification>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: Notification,
|
||||
newItem: Notification
|
||||
): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: Notification,
|
||||
newItem: Notification
|
||||
): Boolean =
|
||||
oldItem == newItem
|
||||
}
|
||||
) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
@ -193,18 +255,13 @@ class NotificationsAdapter(private val apiHolder: PixelfedAPIHolder, private val
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val uiModel = getItem(position)
|
||||
uiModel.let {
|
||||
(holder as NotificationViewHolder).bind(it, apiHolder.setDomainToCurrentUser(db), db.userDao().getActiveUser()!!.accessToken)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val UIMODEL_COMPARATOR = object : DiffUtil.ItemCallback<Notification>() {
|
||||
override fun areItemsTheSame(oldItem: Notification, newItem: Notification): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: Notification, newItem: Notification): Boolean =
|
||||
oldItem == newItem
|
||||
(holder as NotificationViewHolder).bind(
|
||||
it,
|
||||
apiHolder.setDomainToCurrentUser(db),
|
||||
db.userDao().getActiveUser()!!.accessToken,
|
||||
lifecycleScope
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -107,25 +107,19 @@ class ProfileActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun getAndSetAccount(id: String){
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val account = try{
|
||||
pixelfedAPI.getAccount("Bearer $accessToken", id)
|
||||
.enqueue(object : Callback<Account> {
|
||||
override fun onResponse(call: Call<Account>, response: Response<Account>) {
|
||||
if (response.code() == 200) {
|
||||
val account = response.body()!!
|
||||
|
||||
} catch (exception: IOException) {
|
||||
Log.e("ProfileActivity:", exception.toString())
|
||||
return@launchWhenCreated showError()
|
||||
} catch (exception: HttpException) {
|
||||
return@launchWhenCreated showError()
|
||||
}
|
||||
setContent(account)
|
||||
} else {
|
||||
showError()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<Account>, t: Throwable) {
|
||||
Log.e("ProfileActivity:", t.toString())
|
||||
showError()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun showError(@StringRes errorText: Int = R.string.loading_toast, show: Boolean = true){
|
||||
val motionLayout = findViewById<MotionLayout>(R.id.motionLayout)
|
||||
if(show){
|
||||
@ -151,7 +145,8 @@ class ProfileActivity : BaseActivity() {
|
||||
val description = findViewById<TextView>(R.id.descriptionTextView)
|
||||
description.text = parseHTMLText(
|
||||
account.note ?: "", emptyList(), pixelfedAPI,
|
||||
applicationContext, "Bearer $accessToken"
|
||||
applicationContext, "Bearer $accessToken",
|
||||
lifecycleScope
|
||||
)
|
||||
|
||||
val accountName = findViewById<TextView>(R.id.accountNameTextView)
|
||||
|
@ -12,6 +12,7 @@ import android.widget.*
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
@ -32,7 +33,9 @@ import com.mikepenz.iconics.utils.paddingDp
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.HttpException
|
||||
import retrofit2.Response
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* This fragment lets you search and use Pixelfed's Discover feature
|
||||
@ -107,25 +110,17 @@ class SearchDiscoverFragment : BaseFragment() {
|
||||
|
||||
private fun getDiscover() {
|
||||
|
||||
api.discover("Bearer $accessToken")
|
||||
.enqueue(object : Callback<DiscoverPosts> {
|
||||
|
||||
override fun onFailure(call: Call<DiscoverPosts>, t: Throwable) {
|
||||
showError()
|
||||
Log.e("SearchDiscoverFragment:", t.toString())
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call<DiscoverPosts>, response: Response<DiscoverPosts>) {
|
||||
if(response.code() == 200) {
|
||||
val discoverPosts = response.body()!!
|
||||
lifecycleScope.launchWhenCreated {
|
||||
try {
|
||||
val discoverPosts = api.discover("Bearer $accessToken")
|
||||
adapter.addPosts(discoverPosts.posts)
|
||||
showError(show = false)
|
||||
}
|
||||
else {
|
||||
} catch (exception: IOException) {
|
||||
showError()
|
||||
} catch (exception: HttpException) {
|
||||
showError()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -245,10 +245,10 @@ interface PixelfedAPI {
|
||||
) : Response<List<Account>>
|
||||
|
||||
@GET("/api/v1/accounts/{id}")
|
||||
fun getAccount(
|
||||
suspend fun getAccount(
|
||||
@Header("Authorization") authorization: String,
|
||||
@Path("id") accountId : String
|
||||
): Call<Account>
|
||||
): Account
|
||||
|
||||
@GET("/api/v1/statuses/{id}")
|
||||
suspend fun getStatus(
|
||||
@ -266,19 +266,19 @@ interface PixelfedAPI {
|
||||
|
||||
// get discover
|
||||
@GET("/api/v2/discover/posts")
|
||||
fun discover(
|
||||
suspend fun discover(
|
||||
@Header("Authorization") authorization: String
|
||||
) : Call<DiscoverPosts>
|
||||
) : DiscoverPosts
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/reports")
|
||||
@JvmSuppressWildcards
|
||||
fun report(
|
||||
suspend fun report(
|
||||
@Header("Authorization") authorization: String,
|
||||
@Field("account_id") account_id: String,
|
||||
@Field("status_ids") status_ids: List<Status>,
|
||||
@Field("comment") comment: String,
|
||||
@Field("forward") forward: Boolean = true
|
||||
) : Call<Report>
|
||||
) : Report
|
||||
|
||||
}
|
@ -6,9 +6,14 @@ import android.util.Log
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import com.h.pixeldroid.profile.ProfileActivity
|
||||
import com.h.pixeldroid.utils.api.PixelfedAPI
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.HttpException
|
||||
import retrofit2.Response
|
||||
import java.io.IOException
|
||||
import java.io.Serializable
|
||||
|
||||
/*
|
||||
@ -52,28 +57,19 @@ data class Account(
|
||||
/**
|
||||
* @brief Opens an activity of the profile with the given id
|
||||
*/
|
||||
fun getAccountFromId(id: String, api : PixelfedAPI, context: Context, credential: String) {
|
||||
Log.e("ACCOUNT_ID", id)
|
||||
api.getAccount(credential, id).enqueue( object : Callback<Account> {
|
||||
override fun onFailure(call: Call<Account>, t: Throwable) {
|
||||
Log.e("GET ACCOUNT ERROR", t.toString())
|
||||
suspend fun openAccountFromId(id: String, api : PixelfedAPI, context: Context, credential: String) {
|
||||
val account = try {
|
||||
api.getAccount(credential, id)
|
||||
} catch (exception: IOException) {
|
||||
Log.e("GET ACCOUNT ERROR", exception.toString())
|
||||
return
|
||||
} catch (exception: HttpException) {
|
||||
Log.e("ERROR CODE", exception.code().toString())
|
||||
return
|
||||
}
|
||||
|
||||
override fun onResponse(
|
||||
call: Call<Account>,
|
||||
response: Response<Account>
|
||||
) {
|
||||
if(response.code() == 200) {
|
||||
val account = response.body()!!
|
||||
|
||||
//Open the account page in a separate activity
|
||||
account.openProfile(context)
|
||||
} else {
|
||||
Log.e("ERROR CODE", response.code().toString())
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,11 +77,6 @@ open class Status(
|
||||
fun getProfilePicUrl() : String? = account?.avatar
|
||||
fun getPostPreviewURL() : String? = media_attachments?.firstOrNull()?.preview_url
|
||||
|
||||
/**
|
||||
* @brief returns the parsed version of the HTML description
|
||||
*/
|
||||
private fun getDescription(api: PixelfedAPI, context: Context, credential: String) : Spanned =
|
||||
parseHTMLText(content ?: "", mentions, api, context, credential)
|
||||
|
||||
fun getNLikes(context: Context) : CharSequence {
|
||||
return context.getString(R.string.likes).format(favourites_count.toString())
|
||||
|
Loading…
x
Reference in New Issue
Block a user