11package org.nitri.opentopo.nearby.adapter
22
3+ import android.util.Log
34import android.view.LayoutInflater
45import android.view.View
56import android.view.ViewGroup
67import android.widget.ImageView
78import android.widget.TextView
89import androidx.recyclerview.widget.RecyclerView
10+ import com.squareup.picasso.Callback
11+ import com.squareup.picasso.OkHttp3Downloader
912import com.squareup.picasso.Picasso
13+ import okhttp3.Interceptor
14+ import okhttp3.OkHttpClient
15+ import okhttp3.Request
16+ import org.nitri.opentopo.BuildConfig
1017import org.nitri.opentopo.R
1118import org.nitri.opentopo.nearby.adapter.NearbyAdapter.ItemViewHolder
1219import 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