Skip to content

Commit 72c8a42

Browse files
committed
Fix 'nearby' image thumbnails
1 parent 7207730 commit 72c8a42

File tree

3 files changed

+104
-13
lines changed

3 files changed

+104
-13
lines changed

app/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ dependencies {
134134
exclude group: 'com.android.support', module: 'support-core-utils'
135135
exclude group: 'com.android.support', module: 'exifinterface'
136136
}
137+
// OkHttp client and Picasso OkHttp3 downloader for custom headers on image requests
138+
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
139+
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
137140
playImplementation 'com.google.android.gms:play-services-ads:24.7.0'
138141
playImplementation 'com.google.android.ump:user-messaging-platform:3.2.0'
139142
testImplementation 'junit:junit:4.13.2'

app/src/main/java/org/nitri/opentopo/nearby/NearbyFragment.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import org.nitri.opentopo.nearby.viewmodel.NearbyViewModelFactory
3030
import org.nitri.opentopo.util.DistanceCalculator
3131
import retrofit2.Retrofit
3232
import retrofit2.converter.gson.GsonConverterFactory
33+
import kotlin.math.roundToInt
3334

3435
class NearbyFragment : Fragment(), NearbyAdapter.OnItemClickListener {
3536
private var mListener: OnFragmentInteractionListener? = null
@@ -89,7 +90,8 @@ class NearbyFragment : Fragment(), NearbyAdapter.OnItemClickListener {
8990
for (item in mNearbyItems) {
9091
item?.apply {
9192
distance =
92-
Math.round(DistanceCalculator.distance(mLatitude, mLongitude, item.lat, item.lon)).toInt()
93+
DistanceCalculator.distance(mLatitude, mLongitude, item.lat, item.lon)
94+
.roundToInt()
9395
}
9496
}
9597
}

app/src/main/java/org/nitri/opentopo/nearby/adapter/NearbyAdapter.kt

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
package org.nitri.opentopo.nearby.adapter
22

3+
import android.util.Log
34
import android.view.LayoutInflater
45
import android.view.View
56
import android.view.ViewGroup
67
import android.widget.ImageView
78
import android.widget.TextView
89
import androidx.recyclerview.widget.RecyclerView
10+
import com.squareup.picasso.Callback
11+
import com.squareup.picasso.OkHttp3Downloader
912
import com.squareup.picasso.Picasso
13+
import okhttp3.Interceptor
14+
import okhttp3.OkHttpClient
15+
import okhttp3.Request
16+
import org.nitri.opentopo.BuildConfig
1017
import org.nitri.opentopo.R
1118
import org.nitri.opentopo.nearby.adapter.NearbyAdapter.ItemViewHolder
1219
import org.nitri.opentopo.nearby.entity.NearbyItem
@@ -15,6 +22,10 @@ class NearbyAdapter(
1522
private val mItems: MutableList<NearbyItem?>,
1623
private val mListener: OnItemClickListener
1724
) : RecyclerView.Adapter<ItemViewHolder>() {
25+
26+
@Volatile
27+
private var picassoInstance: Picasso? = null
28+
1829
override fun onCreateViewHolder(viewGroup: ViewGroup, type: Int): ItemViewHolder {
1930
val view = LayoutInflater
2031
.from(viewGroup.context)
@@ -23,12 +34,54 @@ class NearbyAdapter(
2334
}
2435

2536
override fun onBindViewHolder(viewHolder: ItemViewHolder, position: Int) {
26-
val item = mItems[position] ?: return
27-
Picasso.get().load(item.thumbnail).placeholder(R.drawable.ic_place).resize(60, 60)
28-
.centerCrop().into(viewHolder.ivThumb)
37+
val currentPos = viewHolder.bindingAdapterPosition.takeIf { it != RecyclerView.NO_POSITION } ?: position
38+
val item = mItems.getOrNull(currentPos) ?: return
39+
val originalUrl = item.thumbnail
40+
val thumbUrl = originalUrl?.let {
41+
when {
42+
it.startsWith("http://") -> it.replaceFirst("http://", "https://")
43+
it.startsWith("//") -> "https:$it"
44+
else -> it
45+
}
46+
}
47+
48+
val picasso = getPicasso(viewHolder.itemView.context)
49+
50+
if (BuildConfig.DEBUG && !loggingConfigured) {
51+
try {
52+
picasso.setIndicatorsEnabled(false)
53+
picasso.isLoggingEnabled = true
54+
loggingConfigured = true
55+
} catch (t: Throwable) {
56+
// ignore – these methods are debug helpers and may not exist on some builds
57+
}
58+
}
59+
60+
// if (BuildConfig.DEBUG) {
61+
// Log.d(TAG, "Binding position=$currentPos pageId=${item.pageid} title=${item.title}")
62+
// Log.d(TAG, "Thumbnail URL original=$originalUrl normalized=$thumbUrl")
63+
// }
64+
65+
picasso
66+
.load(thumbUrl)
67+
.placeholder(R.drawable.ic_place)
68+
.error(R.drawable.ic_place)
69+
.resize(60, 60)
70+
.centerCrop()
71+
.into(viewHolder.ivThumb, object : Callback {
72+
override fun onSuccess() {
73+
if (BuildConfig.DEBUG) {
74+
Log.d(TAG, "Picasso load SUCCESS for pageId=${item.pageid}")
75+
}
76+
}
77+
78+
override fun onError(e: Exception?) {
79+
Log.w(TAG, "Picasso load FAILED for pageId=${item.pageid} url=$thumbUrl", e)
80+
}
81+
})
2982
viewHolder.tvTitle.text = item.title
3083
viewHolder.tvDescription.text = item.description
31-
if (position == mItems.size - 1) viewHolder.divider.visibility = View.GONE
84+
if (currentPos == mItems.size - 1) viewHolder.divider.visibility = View.GONE
3285
}
3386

3487
override fun getItemCount(): Int {
@@ -42,17 +95,13 @@ class NearbyAdapter(
4295

4396
inner class ItemViewHolder internal constructor(itemView: View) :
4497
RecyclerView.ViewHolder(itemView), View.OnClickListener {
45-
var ivThumb: ImageView
46-
var tvTitle: TextView
47-
var tvDescription: TextView
48-
private var ivMap: ImageView
98+
var ivThumb: ImageView = itemView.findViewById(R.id.ivThumb)
99+
var tvTitle: TextView = itemView.findViewById(R.id.tvTitle)
100+
var tvDescription: TextView = itemView.findViewById(R.id.tvDescription)
101+
private var ivMap: ImageView = itemView.findViewById(R.id.ivMap)
49102
var divider: View
50103

51104
init {
52-
ivThumb = itemView.findViewById(R.id.ivThumb)
53-
tvTitle = itemView.findViewById(R.id.tvTitle)
54-
tvDescription = itemView.findViewById(R.id.tvDescription)
55-
ivMap = itemView.findViewById(R.id.ivMap)
56105
ivMap.setOnClickListener(this)
57106
divider = itemView.findViewById(R.id.divider)
58107
itemView.setOnClickListener(this)
@@ -71,4 +120,41 @@ class NearbyAdapter(
71120
fun onItemClick(index: Int)
72121
fun onMapItemClick(index: Int)
73122
}
123+
124+
private fun getPicasso(context: android.content.Context): Picasso {
125+
val cached = picassoInstance
126+
if (cached != null) return cached
127+
128+
synchronized(this) {
129+
val again = picassoInstance
130+
if (again != null) return again
131+
132+
val ua = "OpenTopoMapViewer/${BuildConfig.VERSION_NAME} (Android; ${BuildConfig.APPLICATION_ID})"
133+
val referer = "https://www.wikipedia.org/"
134+
135+
val headerInterceptor = Interceptor { chain ->
136+
val req: Request = chain.request().newBuilder()
137+
.header("User-Agent", ua)
138+
.header("Accept", "image/*")
139+
.header("Referer", referer)
140+
.build()
141+
chain.proceed(req)
142+
}
143+
144+
val okHttpClient = OkHttpClient.Builder()
145+
.addInterceptor(headerInterceptor)
146+
.build()
147+
148+
val p = Picasso.Builder(context.applicationContext)
149+
.downloader(OkHttp3Downloader(okHttpClient))
150+
.build()
151+
picassoInstance = p
152+
return p
153+
}
154+
}
155+
156+
companion object {
157+
private val TAG = NearbyAdapter::class.java.simpleName
158+
private var loggingConfigured = false
159+
}
74160
}

0 commit comments

Comments
 (0)