Migrate from Kotlin synthetics to Jetpack view binding (#5546)

This commit is contained in:
Adam Jones 2024-02-14 09:29:06 +00:00 committed by GitHub
parent b18117bc07
commit 1cbce77d5f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 73 additions and 68 deletions

View file

@ -5,7 +5,7 @@ apply from: '../gitutils.gradle'
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-parcelize'
apply from: "$rootDir/jacoco.gradle" apply from: "$rootDir/jacoco.gradle"
def isRunningOnTravisAndIsNotPRBuild = System.getenv("CI") == "true" && file('../play.p12').exists() def isRunningOnTravisAndIsNotPRBuild = System.getenv("CI") == "true" && file('../play.p12').exists()
@ -357,6 +357,9 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
kotlinOptions {
jvmTarget = "1.8"
}
buildToolsVersion buildToolsVersion buildToolsVersion buildToolsVersion
@ -397,7 +400,3 @@ if (isRunningOnTravisAndIsNotPRBuild) {
} }
} }
} }
androidExtensions {
experimental = true
}

View file

@ -2,7 +2,7 @@ package fr.free.nrw.commons
import android.os.Parcelable import android.os.Parcelable
import fr.free.nrw.commons.location.LatLng import fr.free.nrw.commons.location.LatLng
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
import fr.free.nrw.commons.wikidata.model.page.PageTitle import fr.free.nrw.commons.wikidata.model.page.PageTitle
import java.util.* import java.util.*

View file

@ -1,7 +1,7 @@
package fr.free.nrw.commons.category package fr.free.nrw.commons.category
import android.os.Parcelable import android.os.Parcelable
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
data class CategoryItem(val name: String, val description: String?, data class CategoryItem(val name: String, val description: String?,

View file

@ -12,7 +12,7 @@ import fr.free.nrw.commons.upload.UploadMediaDetail
import fr.free.nrw.commons.upload.WikidataPlace import fr.free.nrw.commons.upload.WikidataPlace
import fr.free.nrw.commons.upload.WikidataPlace.Companion.from import fr.free.nrw.commons.upload.WikidataPlace.Companion.from
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
import java.util.* import java.util.*
@Entity(tableName = "contribution") @Entity(tableName = "contribution")

View file

@ -6,7 +6,6 @@ import android.animation.ValueAnimator
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Matrix import android.graphics.Matrix
import android.graphics.drawable.BitmapDrawable
import android.media.ExifInterface import android.media.ExifInterface
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
@ -18,10 +17,7 @@ import androidx.core.graphics.rotationMatrix
import androidx.core.graphics.scaleMatrix import androidx.core.graphics.scaleMatrix
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import fr.free.nrw.commons.R import fr.free.nrw.commons.databinding.ActivityEditBinding
import kotlinx.android.synthetic.main.activity_edit.btn_save
import kotlinx.android.synthetic.main.activity_edit.iv
import kotlinx.android.synthetic.main.activity_edit.rotate_btn
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
@ -37,10 +33,12 @@ class EditActivity : AppCompatActivity() {
private var imageUri = "" private var imageUri = ""
private lateinit var vm: EditViewModel private lateinit var vm: EditViewModel
private val sourceExifAttributeList = mutableListOf<Pair<String, String?>>() private val sourceExifAttributeList = mutableListOf<Pair<String, String?>>()
private lateinit var binding: ActivityEditBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_edit) binding = ActivityEditBinding.inflate(layoutInflater)
setContentView(binding.root)
supportActionBar?.title = "" supportActionBar?.title = ""
val intent = intent val intent = intent
imageUri = intent.getStringExtra("image") ?: "" imageUri = intent.getStringExtra("image") ?: ""
@ -87,9 +85,9 @@ class EditActivity : AppCompatActivity() {
* for the "Rotate" and "Save" buttons. * for the "Rotate" and "Save" buttons.
*/ */
private fun init() { private fun init() {
iv.adjustViewBounds = true binding.iv.adjustViewBounds = true
iv.scaleType = ImageView.ScaleType.MATRIX binding.iv.scaleType = ImageView.ScaleType.MATRIX
iv.post(Runnable { binding.iv.post(Runnable {
val options = BitmapFactory.Options() val options = BitmapFactory.Options()
options.inJustDecodeBounds = true options.inJustDecodeBounds = true
BitmapFactory.decodeFile(imageUri, options) BitmapFactory.decodeFile(imageUri, options)
@ -104,26 +102,26 @@ class EditActivity : AppCompatActivity() {
options.inSampleSize = scaleFactor options.inSampleSize = scaleFactor
options.inJustDecodeBounds = false options.inJustDecodeBounds = false
val scaledBitmap = BitmapFactory.decodeFile(imageUri, options) val scaledBitmap = BitmapFactory.decodeFile(imageUri, options)
iv.setImageBitmap(scaledBitmap) binding.iv.setImageBitmap(scaledBitmap)
// Update the ImageView with the scaled bitmap // Update the ImageView with the scaled bitmap
val scale = iv.measuredWidth.toFloat() / scaledBitmap.width.toFloat() val scale = binding.iv.measuredWidth.toFloat() / scaledBitmap.width.toFloat()
iv.layoutParams.height = (scale * scaledBitmap.height).toInt() binding.iv.layoutParams.height = (scale * scaledBitmap.height).toInt()
iv.imageMatrix = scaleMatrix(scale, scale) binding.iv.imageMatrix = scaleMatrix(scale, scale)
} else { } else {
options.inJustDecodeBounds = false options.inJustDecodeBounds = false
val bitmap = BitmapFactory.decodeFile(imageUri, options) val bitmap = BitmapFactory.decodeFile(imageUri, options)
iv.setImageBitmap(bitmap) binding.iv.setImageBitmap(bitmap)
val scale = iv.measuredWidth.toFloat() / bitmapWidth.toFloat() val scale = binding.iv.measuredWidth.toFloat() / bitmapWidth.toFloat()
iv.layoutParams.height = (scale * bitmapHeight).toInt() binding.iv.layoutParams.height = (scale * bitmapHeight).toInt()
iv.imageMatrix = scaleMatrix(scale, scale) binding.iv.imageMatrix = scaleMatrix(scale, scale)
} }
}) })
rotate_btn.setOnClickListener { binding.rotateBtn.setOnClickListener {
animateImageHeight() animateImageHeight()
} }
btn_save.setOnClickListener { binding.btnSave.setOnClickListener {
getRotatedImage() getRotatedImage()
} }
} }
@ -140,10 +138,10 @@ class EditActivity : AppCompatActivity() {
* further rotation actions. * further rotation actions.
*/ */
private fun animateImageHeight() { private fun animateImageHeight() {
val drawableWidth: Float = iv.getDrawable().getIntrinsicWidth().toFloat() val drawableWidth: Float = binding.iv.getDrawable().getIntrinsicWidth().toFloat()
val drawableHeight: Float = iv.getDrawable().getIntrinsicHeight().toFloat() val drawableHeight: Float = binding.iv.getDrawable().getIntrinsicHeight().toFloat()
val viewWidth: Float = iv.getMeasuredWidth().toFloat() val viewWidth: Float = binding.iv.getMeasuredWidth().toFloat()
val viewHeight: Float = iv.getMeasuredHeight().toFloat() val viewHeight: Float = binding.iv.getMeasuredHeight().toFloat()
val rotation = imageRotation % 360 val rotation = imageRotation % 360
val newRotation = rotation + 90 val newRotation = rotation + 90
@ -173,12 +171,12 @@ class EditActivity : AppCompatActivity() {
animator.addListener(object : AnimatorListener { animator.addListener(object : AnimatorListener {
override fun onAnimationStart(animation: Animator) { override fun onAnimationStart(animation: Animator) {
rotate_btn.setEnabled(false) binding.rotateBtn.setEnabled(false)
} }
override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) {
imageRotation = newRotation % 360 imageRotation = newRotation % 360
rotate_btn.setEnabled(true) binding.rotateBtn.setEnabled(true)
} }
override fun onAnimationCancel(animation: Animator) { override fun onAnimationCancel(animation: Animator) {
@ -196,7 +194,7 @@ class EditActivity : AppCompatActivity() {
(complementaryAnimVal * viewHeight + animVal * newViewHeight).toInt() (complementaryAnimVal * viewHeight + animVal * newViewHeight).toInt()
val animatedScale = complementaryAnimVal * imageScale + animVal * newImageScale val animatedScale = complementaryAnimVal * imageScale + animVal * newImageScale
val animatedRotation = complementaryAnimVal * rotation + animVal * newRotation val animatedRotation = complementaryAnimVal * rotation + animVal * newRotation
iv.getLayoutParams().height = animatedHeight binding.iv.getLayoutParams().height = animatedHeight
val matrix: Matrix = rotationMatrix( val matrix: Matrix = rotationMatrix(
animatedRotation, animatedRotation,
drawableWidth / 2, drawableWidth / 2,
@ -209,11 +207,11 @@ class EditActivity : AppCompatActivity() {
drawableHeight / 2 drawableHeight / 2
) )
matrix.postTranslate( matrix.postTranslate(
-(drawableWidth - iv.getMeasuredWidth()) / 2, -(drawableWidth - binding.iv.getMeasuredWidth()) / 2,
-(drawableHeight - iv.getMeasuredHeight()) / 2 -(drawableHeight - binding.iv.getMeasuredHeight()) / 2
) )
iv.setImageMatrix(matrix) binding.iv.setImageMatrix(matrix)
iv.requestLayout() binding.iv.requestLayout()
} }
animator.start() animator.start()

View file

@ -18,7 +18,7 @@ abstract class PageableMediaFragment : BasePagingFragment<Media>(), MediaDetailP
* ViewBinding * ViewBinding
*/ */
private var _binding: FragmentSearchPaginatedBinding? = null private var _binding: FragmentSearchPaginatedBinding? = null
private val binding get() = _binding private val binding get() = _binding!!
override val pagedListAdapter by lazy { override val pagedListAdapter by lazy {
PagedMediaAdapter(categoryImagesCallback::onMediaClicked) PagedMediaAdapter(categoryImagesCallback::onMediaClicked)
@ -43,9 +43,9 @@ abstract class PageableMediaFragment : BasePagingFragment<Media>(), MediaDetailP
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View {
_binding = FragmentSearchPaginatedBinding.inflate(inflater, container, false) _binding = FragmentSearchPaginatedBinding.inflate(inflater, container, false)
return binding?.root return binding.root
} }
private val simpleDataObserver = private val simpleDataObserver =
@ -66,7 +66,7 @@ abstract class PageableMediaFragment : BasePagingFragment<Media>(), MediaDetailP
pagedListAdapter.currentList?.get(position)?.takeIf { it.filename != null } pagedListAdapter.currentList?.get(position)?.takeIf { it.filename != null }
.also { .also {
pagedListAdapter.currentList?.loadAround(position) pagedListAdapter.currentList?.loadAround(position)
binding?.paginatedSearchResultsList?.scrollToPosition(position) binding.paginatedSearchResultsList.scrollToPosition(position)
} }
override fun getTotalMediaCount(): Int = pagedListAdapter.itemCount override fun getTotalMediaCount(): Int = pagedListAdapter.itemCount

View file

@ -6,9 +6,9 @@ import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import fr.free.nrw.commons.Media import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.databinding.LayoutCategoryImagesBinding
import fr.free.nrw.commons.explore.paging.BaseViewHolder import fr.free.nrw.commons.explore.paging.BaseViewHolder
import fr.free.nrw.commons.explore.paging.inflate import fr.free.nrw.commons.explore.paging.inflate
import kotlinx.android.synthetic.main.layout_category_images.*
class PagedMediaAdapter(private val onImageClicked: (Int) -> Unit) : class PagedMediaAdapter(private val onImageClicked: (Int) -> Unit) :
PagedListAdapter<Media, SearchImagesViewHolder>(object : DiffUtil.ItemCallback<Media>() { PagedListAdapter<Media, SearchImagesViewHolder>(object : DiffUtil.ItemCallback<Media>() {
@ -32,17 +32,19 @@ class PagedMediaAdapter(private val onImageClicked: (Int) -> Unit) :
class SearchImagesViewHolder(containerView: View, val onImageClicked: (Int) -> Unit) : class SearchImagesViewHolder(containerView: View, val onImageClicked: (Int) -> Unit) :
BaseViewHolder<Pair<Media, Int>>(containerView) { BaseViewHolder<Pair<Media, Int>>(containerView) {
val binding = LayoutCategoryImagesBinding.bind(itemView)
override fun bind(item: Pair<Media, Int>) { override fun bind(item: Pair<Media, Int>) {
val media = item.first val media = item.first
categoryImageView.setOnClickListener { onImageClicked(item.second) } binding.categoryImageView.setOnClickListener { onImageClicked(item.second) }
categoryImageTitle.text = media.mostRelevantCaption binding.categoryImageTitle.text = media.mostRelevantCaption
categoryImageView.setImageURI(media.thumbUrl) binding.categoryImageView.setImageURI(media.thumbUrl)
if (media.author?.isNotEmpty() == true) { if (media.author?.isNotEmpty() == true) {
categoryImageAuthor.visibility = View.VISIBLE binding.categoryImageAuthor.visibility = View.VISIBLE
categoryImageAuthor.text = binding.categoryImageAuthor.text =
containerView.context.getString(R.string.image_uploaded_by, media.user) containerView.context.getString(R.string.image_uploaded_by, media.user)
} else { } else {
categoryImageAuthor.visibility = View.GONE binding.categoryImageAuthor.visibility = View.GONE
} }
} }

View file

@ -5,7 +5,8 @@ import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.View.* import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
@ -14,11 +15,9 @@ import androidx.paging.PagedList
import androidx.paging.PagedListAdapter import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.MergeAdapter import androidx.recyclerview.widget.MergeAdapter
import fr.free.nrw.commons.R import fr.free.nrw.commons.databinding.FragmentSearchPaginatedBinding
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
import fr.free.nrw.commons.utils.ViewUtil import fr.free.nrw.commons.utils.ViewUtil
import kotlinx.android.synthetic.main.fragment_search_paginated.*
abstract class BasePagingFragment<T> : CommonsDaggerSupportFragment(), abstract class BasePagingFragment<T> : CommonsDaggerSupportFragment(),
PagingContract.View<T> { PagingContract.View<T> {
@ -30,15 +29,21 @@ abstract class BasePagingFragment<T> : CommonsDaggerSupportFragment(),
private val mergeAdapter by lazy { MergeAdapter(pagedListAdapter, loadingAdapter) } private val mergeAdapter by lazy { MergeAdapter(pagedListAdapter, loadingAdapter) }
private var searchResults: LiveData<PagedList<T>>? = null private var searchResults: LiveData<PagedList<T>>? = null
private var _binding: FragmentSearchPaginatedBinding? = null
private val binding get() = _binding!!
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
) = inflater.inflate(R.layout.fragment_search_paginated, container, false) ): View {
_binding = FragmentSearchPaginatedBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
paginatedSearchResultsList.apply { binding.paginatedSearchResultsList.apply {
layoutManager = GridLayoutManager(context, if (isPortrait) 1 else 2) layoutManager = GridLayoutManager(context, if (isPortrait) 1 else 2)
adapter = mergeAdapter adapter = mergeAdapter
} }
@ -53,7 +58,7 @@ abstract class BasePagingFragment<T> : CommonsDaggerSupportFragment(),
*/ */
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
paginatedSearchResultsList.apply { binding.paginatedSearchResultsList.apply {
layoutManager = GridLayoutManager(context, if (isPortrait) 1 else 2) layoutManager = GridLayoutManager(context, if (isPortrait) 1 else 2)
} }
} }
@ -77,15 +82,15 @@ abstract class BasePagingFragment<T> : CommonsDaggerSupportFragment(),
} }
override fun hideInitialLoadProgress() { override fun hideInitialLoadProgress() {
paginatedSearchInitialLoadProgress.visibility = GONE binding.paginatedSearchInitialLoadProgress.visibility = GONE
} }
override fun showInitialLoadInProgress() { override fun showInitialLoadInProgress() {
paginatedSearchInitialLoadProgress.visibility = VISIBLE binding.paginatedSearchInitialLoadProgress.visibility = VISIBLE
} }
override fun showSnackbar() { override fun showSnackbar() {
ViewUtil.showShortSnackbar(paginatedSearchResultsList, errorTextId) ViewUtil.showShortSnackbar(binding.paginatedSearchResultsList, errorTextId)
} }
fun onQueryUpdated(query: String) { fun onQueryUpdated(query: String) {
@ -93,14 +98,14 @@ abstract class BasePagingFragment<T> : CommonsDaggerSupportFragment(),
} }
override fun showEmptyText(query: String) { override fun showEmptyText(query: String) {
contentNotFound.text = getEmptyText(query) binding.contentNotFound.text = getEmptyText(query)
contentNotFound.visibility = VISIBLE binding.contentNotFound.visibility = VISIBLE
} }
abstract fun getEmptyText(query: String): String abstract fun getEmptyText(query: String): String
override fun hideEmptyText() { override fun hideEmptyText() {
contentNotFound.visibility = GONE binding.contentNotFound.visibility = GONE
} }
} }

View file

@ -8,8 +8,8 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.databinding.ListItemLoadMoreBinding
import kotlinx.android.extensions.LayoutContainer import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.list_item_load_more.*
class FooterAdapter(private val onRefreshClicked: () -> Unit) : class FooterAdapter(private val onRefreshClicked: () -> Unit) :
ListAdapter<FooterItem, FooterViewHolder>(object : ListAdapter<FooterItem, FooterViewHolder>(object :
@ -45,8 +45,10 @@ open class FooterViewHolder(override val containerView: View) :
class LoadingViewHolder(containerView: View) : FooterViewHolder(containerView) class LoadingViewHolder(containerView: View) : FooterViewHolder(containerView)
class RefreshViewHolder(containerView: View, onRefreshClicked: () -> Unit) : class RefreshViewHolder(containerView: View, onRefreshClicked: () -> Unit) :
FooterViewHolder(containerView) { FooterViewHolder(containerView) {
val binding = ListItemLoadMoreBinding.bind(itemView)
init { init {
listItemLoadMoreButton.setOnClickListener { onRefreshClicked() } binding.listItemLoadMoreButton.setOnClickListener { onRefreshClicked() }
} }
} }

View file

@ -2,7 +2,7 @@ package fr.free.nrw.commons.upload
import android.os.Parcelable import android.os.Parcelable
import fr.free.nrw.commons.nearby.Place import fr.free.nrw.commons.nearby.Place
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
/** /**
* Holds a description of an item being uploaded by [UploadActivity] * Holds a description of an item being uploaded by [UploadActivity]

View file

@ -3,7 +3,7 @@ package fr.free.nrw.commons.upload
import android.os.Parcelable import android.os.Parcelable
import fr.free.nrw.commons.location.LatLng import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.nearby.Place import fr.free.nrw.commons.nearby.Place
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
data class WikidataPlace( data class WikidataPlace(

View file

@ -11,7 +11,7 @@ import fr.free.nrw.commons.wikidata.WikidataProperties.*
import fr.free.nrw.commons.wikidata.model.DataValue import fr.free.nrw.commons.wikidata.model.DataValue
import fr.free.nrw.commons.wikidata.model.Entities import fr.free.nrw.commons.wikidata.model.Entities
import fr.free.nrw.commons.wikidata.model.Statement_partial import fr.free.nrw.commons.wikidata.model.Statement_partial
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
import java.math.BigInteger import java.math.BigInteger
import java.security.MessageDigest import java.security.MessageDigest
import java.security.NoSuchAlgorithmException import java.security.NoSuchAlgorithmException

View file

@ -5,7 +5,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import fr.free.nrw.commons.TestCommonsApplication import fr.free.nrw.commons.TestCommonsApplication
import kotlinx.android.synthetic.main.row_item_languages_spinner.view.*
import org.junit.Assert import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test