Initial support for using API size values for single photos

This commit is contained in:
Matthieu 2021-02-08 18:01:48 +01:00
parent f66475bbdb
commit c88f4a4cec
8 changed files with 55 additions and 21 deletions

View File

@ -11,6 +11,7 @@ import com.h.pixeldroid.utils.api.objects.Status.Companion.DOMAIN_TAG
import com.h.pixeldroid.utils.api.objects.Status.Companion.POST_TAG
import com.h.pixeldroid.utils.BaseFragment
import com.h.pixeldroid.utils.bindingLifecycleAware
import com.h.pixeldroid.utils.displayDimensionsInPx
class PostFragment : BaseFragment() {
@ -43,7 +44,9 @@ class PostFragment : BaseFragment() {
val holder = StatusViewHolder(binding)
holder.bind(currentStatus, api, db, lifecycleScope)
holder.bind(currentStatus, api, db, lifecycleScope, requireContext().displayDimensionsInPx())
}
}

View File

@ -10,10 +10,7 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupMenu
import android.widget.Toast
import android.widget.*
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.recyclerview.widget.RecyclerView
@ -31,6 +28,7 @@ import com.h.pixeldroid.utils.api.PixelfedAPI
import com.h.pixeldroid.utils.api.objects.Attachment
import com.h.pixeldroid.utils.api.objects.Status
import com.h.pixeldroid.utils.db.AppDatabase
import com.h.pixeldroid.utils.displayDimensionsInPx
import com.karumi.dexter.Dexter
import com.karumi.dexter.listener.PermissionDeniedResponse
import com.karumi.dexter.listener.PermissionGrantedResponse
@ -38,6 +36,7 @@ import com.karumi.dexter.listener.single.BasePermissionListener
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.io.IOException
import kotlin.math.roundToInt
/**
@ -47,14 +46,26 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
private var status: Status? = null
fun bind(status: Status?, pixelfedAPI: PixelfedAPI, db: AppDatabase, lifecycleScope: LifecycleCoroutineScope) {
fun bind(status: Status?, pixelfedAPI: PixelfedAPI, db: AppDatabase, lifecycleScope: LifecycleCoroutineScope, displayDimensionsInPx: Pair<Int, Int>) {
this.itemView.visibility = View.VISIBLE
this.status = status
val metrics = itemView.context.resources.displayMetrics
//Limit the height of the different images
binding.postPicture.maxHeight = metrics.heightPixels * 3/4
val maxImageRatio: Float = status?.media_attachments?.map {
if (it.meta?.original?.width == null || it.meta.original.height == null) {
1f
} else {
it.meta.original.width.toFloat() / it.meta.original.height.toFloat()
}
}?.maxOrNull() ?: 1f
val (displayWidth, displayHeight) = displayDimensionsInPx
val height = if (displayWidth / maxImageRatio > displayHeight * 3/4f) {
binding.postPicture.layoutParams.width = ((displayHeight * 3 / 4f) * maxImageRatio).roundToInt()
displayHeight * 3 / 4f
} else displayWidth / maxImageRatio
binding.postPicture.layoutParams.height = height.toInt()
//Setup the post layout
val picRequest = Glide.with(itemView)

View File

@ -19,6 +19,7 @@ import com.h.pixeldroid.posts.feeds.cachedFeeds.CachedFeedFragment
import com.h.pixeldroid.posts.feeds.cachedFeeds.ViewModelFactory
import com.h.pixeldroid.utils.api.objects.FeedContentDatabase
import com.h.pixeldroid.utils.api.objects.Status
import com.h.pixeldroid.utils.displayDimensionsInPx
/**
@ -35,7 +36,7 @@ class PostFeedFragment<T: FeedContentDatabase>: CachedFeedFragment<T>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
adapter = PostsAdapter()
adapter = PostsAdapter(requireContext().displayDimensionsInPx())
@Suppress("UNCHECKED_CAST")
if (requireArguments().get("home") as Boolean){
@ -67,7 +68,7 @@ class PostFeedFragment<T: FeedContentDatabase>: CachedFeedFragment<T>() {
return view
}
inner class PostsAdapter : PagingDataAdapter<T, RecyclerView.ViewHolder>(
inner class PostsAdapter(private val displayDimensionsInPx: Pair<Int, Int>) : PagingDataAdapter<T, RecyclerView.ViewHolder>(
object : DiffUtil.ItemCallback<T>() {
override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
return oldItem.id == newItem.id
@ -89,7 +90,7 @@ class PostFeedFragment<T: FeedContentDatabase>: CachedFeedFragment<T>() {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val uiModel = getItem(position) as Status
uiModel.let {
(holder as StatusViewHolder).bind(it, apiHolder.setDomainToCurrentUser(db), db, lifecycleScope)
(holder as StatusViewHolder).bind(it, apiHolder.setDomainToCurrentUser(db), db, lifecycleScope, displayDimensionsInPx)
}
}
}

View File

@ -15,6 +15,7 @@ import com.h.pixeldroid.posts.StatusViewHolder
import com.h.pixeldroid.posts.feeds.uncachedFeeds.*
import com.h.pixeldroid.utils.api.objects.Results
import com.h.pixeldroid.utils.api.objects.Status
import com.h.pixeldroid.utils.displayDimensionsInPx
/**
* Fragment to show a list of [Status]es, as a result of a search.
@ -25,7 +26,7 @@ class SearchPostsFragment : UncachedFeedFragment<Status>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
adapter = PostsAdapter()
adapter = PostsAdapter(requireContext().displayDimensionsInPx())
query = arguments?.getSerializable("searchFeed") as String
@ -57,7 +58,7 @@ class SearchPostsFragment : UncachedFeedFragment<Status>() {
return view
}
inner class PostsAdapter : PagingDataAdapter<Status, RecyclerView.ViewHolder>(
inner class PostsAdapter(private val displayDimensionsInPx: Pair<Int, Int>) : PagingDataAdapter<Status, RecyclerView.ViewHolder>(
object : DiffUtil.ItemCallback<Status>() {
override fun areItemsTheSame(oldItem: Status, newItem: Status): Boolean {
return oldItem.id == newItem.id
@ -79,7 +80,7 @@ class SearchPostsFragment : UncachedFeedFragment<Status>() {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val uiModel = getItem(position) as Status
uiModel.let {
(holder as StatusViewHolder).bind(it, apiHolder.setDomainToCurrentUser(db), db, lifecycleScope)
(holder as StatusViewHolder).bind(it, apiHolder.setDomainToCurrentUser(db), db, lifecycleScope, displayDimensionsInPx)
}
}
}

View File

@ -20,10 +20,13 @@ import kotlin.math.withSign
object BlurHashDecoder {
fun blurHashBitmap(resources: Resources, attachment: Attachment?): BitmapDrawable {
val ratioOr0 = (attachment?.meta?.original?.width?.toFloat() ?: 1f) / (attachment?.meta?.original?.height?.toFloat() ?: 1f)
val ratio = if (ratioOr0 == 0f) 1f else ratioOr0
return BitmapDrawable(resources,
decode(attachment?.blurhash,
(32 * (attachment?.meta?.original?.aspect ?: 1.0)).toInt(),
32)
(32f * ratio).toInt().coerceAtLeast(32),
(32f / ratio).toInt().coerceAtLeast(32))
)
}

View File

@ -8,6 +8,8 @@ import android.content.res.Resources
import android.net.ConnectivityManager
import android.net.Uri
import android.os.Build
import android.util.DisplayMetrics
import android.view.WindowManager
import androidx.appcompat.app.AppCompatDelegate
import androidx.browser.customtabs.CustomTabsIntent
import androidx.fragment.app.Fragment
@ -38,6 +40,20 @@ fun validDomain(domain: String?): Boolean {
return true
}
fun Context.displayDimensionsInPx(): Pair<Int, Int> {
val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Pair(windowManager.currentWindowMetrics.bounds.width(), windowManager.currentWindowMetrics.bounds.height())
} else {
val metrics = DisplayMetrics()
@Suppress("DEPRECATION")
windowManager.defaultDisplay.getMetrics(metrics)
Pair(metrics.widthPixels, metrics.heightPixels)
}
}
fun normalizeDomain(domain: String): String {
return "https://" + domain
.replace("http://", "")

View File

@ -28,8 +28,8 @@ data class Attachment(
{
data class Focus(
val x: Int?,
val y: Int?
val x: Double?,
val y: Double?
) : Serializable
data class Image(
val width: Int?,

View File

@ -76,8 +76,7 @@
<ImageView
android:id="@+id/postPicture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:layout_height="200dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"