From 169f05e2fce77c57ebf51213ee852d04b4eecd73 Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Tue, 19 Nov 2024 14:22:47 +0530 Subject: [PATCH 1/2] Rename .java to .kt --- ...eightLimitedRecyclerView.java => HeightLimitedRecyclerView.kt} | 0 .../widget/{PicOfDayAppWidget.java => PicOfDayAppWidget.kt} | 0 .../fr/free/nrw/commons/widget/{ViewHolder.java => ViewHolder.kt} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/fr/free/nrw/commons/widget/{HeightLimitedRecyclerView.java => HeightLimitedRecyclerView.kt} (100%) rename app/src/main/java/fr/free/nrw/commons/widget/{PicOfDayAppWidget.java => PicOfDayAppWidget.kt} (100%) rename app/src/main/java/fr/free/nrw/commons/widget/{ViewHolder.java => ViewHolder.kt} (100%) diff --git a/app/src/main/java/fr/free/nrw/commons/widget/HeightLimitedRecyclerView.java b/app/src/main/java/fr/free/nrw/commons/widget/HeightLimitedRecyclerView.kt similarity index 100% rename from app/src/main/java/fr/free/nrw/commons/widget/HeightLimitedRecyclerView.java rename to app/src/main/java/fr/free/nrw/commons/widget/HeightLimitedRecyclerView.kt diff --git a/app/src/main/java/fr/free/nrw/commons/widget/PicOfDayAppWidget.java b/app/src/main/java/fr/free/nrw/commons/widget/PicOfDayAppWidget.kt similarity index 100% rename from app/src/main/java/fr/free/nrw/commons/widget/PicOfDayAppWidget.java rename to app/src/main/java/fr/free/nrw/commons/widget/PicOfDayAppWidget.kt diff --git a/app/src/main/java/fr/free/nrw/commons/widget/ViewHolder.java b/app/src/main/java/fr/free/nrw/commons/widget/ViewHolder.kt similarity index 100% rename from app/src/main/java/fr/free/nrw/commons/widget/ViewHolder.java rename to app/src/main/java/fr/free/nrw/commons/widget/ViewHolder.kt From c5f8892d05e09ecfe6180db3fd53387ef592f446 Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Tue, 19 Nov 2024 14:22:48 +0530 Subject: [PATCH 2/2] Migrated widget module to Kotlin --- .../di/CommonsApplicationComponent.java | 1 - .../widget/HeightLimitedRecyclerView.kt | 63 +++-- .../nrw/commons/widget/PicOfDayAppWidget.kt | 233 +++++++++--------- .../fr/free/nrw/commons/widget/ViewHolder.kt | 8 +- 4 files changed, 146 insertions(+), 159 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java index 1390bd8ef4..0d847b6493 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java @@ -2,7 +2,6 @@ import com.google.gson.Gson; -import fr.free.nrw.commons.actions.PageEditClient; import fr.free.nrw.commons.explore.categories.CategoriesModule; import fr.free.nrw.commons.navtab.MoreBottomSheetFragment; import fr.free.nrw.commons.navtab.MoreBottomSheetLoggedOutFragment; diff --git a/app/src/main/java/fr/free/nrw/commons/widget/HeightLimitedRecyclerView.kt b/app/src/main/java/fr/free/nrw/commons/widget/HeightLimitedRecyclerView.kt index 5c6dde5fd2..b864552435 100644 --- a/app/src/main/java/fr/free/nrw/commons/widget/HeightLimitedRecyclerView.kt +++ b/app/src/main/java/fr/free/nrw/commons/widget/HeightLimitedRecyclerView.kt @@ -1,48 +1,43 @@ -package fr.free.nrw.commons.widget; +package fr.free.nrw.commons.widget -import android.app.Activity; -import android.content.Context; -import android.util.AttributeSet; -import android.util.DisplayMetrics; +import android.app.Activity +import android.content.Context +import android.util.AttributeSet +import android.util.DisplayMetrics + +import androidx.annotation.Nullable +import androidx.recyclerview.widget.RecyclerView -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; /** * Created by Ilgaz Er on 8/7/2018. */ -public class HeightLimitedRecyclerView extends RecyclerView { - int height; - public HeightLimitedRecyclerView(Context context) { - super(context); - DisplayMetrics displayMetrics = new DisplayMetrics(); - ((Activity) getContext()).getWindowManager() - .getDefaultDisplay() - .getMetrics(displayMetrics); - height=displayMetrics.heightPixels; +class HeightLimitedRecyclerView : RecyclerView { + private var height: Int = 0 + + constructor(context: Context) : super(context) { + initializeHeight(context) + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + initializeHeight(context) } - public HeightLimitedRecyclerView(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - DisplayMetrics displayMetrics = new DisplayMetrics(); - ((Activity) getContext()).getWindowManager() - .getDefaultDisplay() - .getMetrics(displayMetrics); - height=displayMetrics.heightPixels; + constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) { + initializeHeight(context) } - public HeightLimitedRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - DisplayMetrics displayMetrics = new DisplayMetrics(); - ((Activity) getContext()).getWindowManager() - .getDefaultDisplay() - .getMetrics(displayMetrics); - height=displayMetrics.heightPixels; + private fun initializeHeight(context: Context) { + val displayMetrics = DisplayMetrics() + (context as Activity).windowManager.defaultDisplay.getMetrics(displayMetrics) + height = displayMetrics.heightPixels } - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - heightSpec = MeasureSpec.makeMeasureSpec((int) (height*0.3), MeasureSpec.AT_MOST); - super.onMeasure(widthSpec, heightSpec); + override fun onMeasure(widthSpec: Int, heightSpec: Int) { + val limitedHeightSpec = MeasureSpec.makeMeasureSpec( + (height * 0.3).toInt(), + MeasureSpec.AT_MOST + ) + super.onMeasure(widthSpec, limitedHeightSpec) } } diff --git a/app/src/main/java/fr/free/nrw/commons/widget/PicOfDayAppWidget.kt b/app/src/main/java/fr/free/nrw/commons/widget/PicOfDayAppWidget.kt index 2734520787..ab6a45b857 100644 --- a/app/src/main/java/fr/free/nrw/commons/widget/PicOfDayAppWidget.kt +++ b/app/src/main/java/fr/free/nrw/commons/widget/PicOfDayAppWidget.kt @@ -1,69 +1,65 @@ -package fr.free.nrw.commons.widget; - -import android.app.PendingIntent; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.net.Uri; -import android.os.Build; -import android.widget.RemoteViews; -import androidx.annotation.Nullable; -import com.facebook.common.executors.CallerThreadExecutor; -import com.facebook.common.references.CloseableReference; -import com.facebook.datasource.DataSource; -import com.facebook.drawee.backends.pipeline.Fresco; -import com.facebook.imagepipeline.core.ImagePipeline; -import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; -import com.facebook.imagepipeline.image.CloseableImage; -import com.facebook.imagepipeline.request.ImageRequest; -import com.facebook.imagepipeline.request.ImageRequestBuilder; -import fr.free.nrw.commons.media.MediaClient; -import javax.inject.Inject; -import fr.free.nrw.commons.R; -import fr.free.nrw.commons.contributions.MainActivity; -import fr.free.nrw.commons.di.ApplicationlessInjection; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; -import timber.log.Timber; - -import static android.content.Intent.ACTION_VIEW; +package fr.free.nrw.commons.widget + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Paint +import android.net.Uri +import android.os.Build +import android.widget.RemoteViews +import androidx.annotation.Nullable +import com.facebook.common.executors.CallerThreadExecutor +import com.facebook.common.references.CloseableReference +import com.facebook.datasource.DataSource +import com.facebook.drawee.backends.pipeline.Fresco +import com.facebook.imagepipeline.core.ImagePipeline +import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber +import com.facebook.imagepipeline.image.CloseableImage +import com.facebook.imagepipeline.request.ImageRequest +import com.facebook.imagepipeline.request.ImageRequestBuilder +import fr.free.nrw.commons.media.MediaClient +import javax.inject.Inject +import fr.free.nrw.commons.R +import fr.free.nrw.commons.contributions.MainActivity +import fr.free.nrw.commons.di.ApplicationlessInjection +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.schedulers.Schedulers +import timber.log.Timber /** * Implementation of App Widget functionality. */ -public class PicOfDayAppWidget extends AppWidgetProvider { +class PicOfDayAppWidget : AppWidgetProvider() { - private final CompositeDisposable compositeDisposable = new CompositeDisposable(); + private val compositeDisposable = CompositeDisposable() @Inject - MediaClient mediaClient; + lateinit var mediaClient: MediaClient - void updateAppWidget( - final Context context, - final AppWidgetManager appWidgetManager, - final int appWidgetId + private fun updateAppWidget( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetId: Int ) { - final RemoteViews views = new RemoteViews( - context.getPackageName(), R.layout.pic_of_day_app_widget); + val views = RemoteViews(context.packageName, R.layout.pic_of_day_app_widget) // Launch App on Button Click - final Intent viewIntent = new Intent(context, MainActivity.class); - int flags = PendingIntent.FLAG_UPDATE_CURRENT; - if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.M) { - flags |= PendingIntent.FLAG_IMMUTABLE; + val viewIntent = Intent(context, MainActivity::class.java) + var flags = PendingIntent.FLAG_UPDATE_CURRENT + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + flags = flags or PendingIntent.FLAG_IMMUTABLE } - final PendingIntent pendingIntent = PendingIntent.getActivity( - context, 0, viewIntent, flags); + val pendingIntent = PendingIntent.getActivity(context, 0, viewIntent, flags) + views.setOnClickPendingIntent(R.id.camera_button, pendingIntent) - views.setOnClickPendingIntent(R.id.camera_button, pendingIntent); - appWidgetManager.updateAppWidget(appWidgetId, views); + appWidgetManager.updateAppWidget(appWidgetId, views) - loadPictureOfTheDay(context, views, appWidgetManager, appWidgetId); + loadPictureOfTheDay(context, views, appWidgetManager, appWidgetId) } /** @@ -71,41 +67,53 @@ public class PicOfDayAppWidget extends AppWidgetProvider { * @param context The application context. * @param views The RemoteViews object used to update the App Widget UI. * @param appWidgetManager The AppWidgetManager instance for managing the widget. - * @param appWidgetId he ID of the App Widget to update. + * @param appWidgetId The ID of the App Widget to update. */ - private void loadPictureOfTheDay( - final Context context, - final RemoteViews views, - final AppWidgetManager appWidgetManager, - final int appWidgetId + private fun loadPictureOfTheDay( + context: Context, + views: RemoteViews, + appWidgetManager: AppWidgetManager, + appWidgetId: Int ) { - compositeDisposable.add(mediaClient.getPictureOfTheDay() + compositeDisposable.add( + mediaClient.getPictureOfTheDay() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( - response -> { + { response -> if (response != null) { - views.setTextViewText(R.id.appwidget_title, response.getDisplayTitle()); + views.setTextViewText(R.id.appwidget_title, response.displayTitle) // View in browser - final Intent viewIntent = new Intent(); - viewIntent.setAction(ACTION_VIEW); - viewIntent.setData(Uri.parse(response.getPageTitle().getMobileUri())); - - int flags = PendingIntent.FLAG_UPDATE_CURRENT; - if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.M) { - flags |= PendingIntent.FLAG_IMMUTABLE; + val viewIntent = Intent().apply { + action = Intent.ACTION_VIEW + data = Uri.parse(response.pageTitle.mobileUri) } - final PendingIntent pendingIntent = PendingIntent.getActivity( - context, 0, viewIntent, flags); - views.setOnClickPendingIntent(R.id.appwidget_image, pendingIntent); - loadImageFromUrl(response.getThumbUrl(), - context, views, appWidgetManager, appWidgetId); + var flags = PendingIntent.FLAG_UPDATE_CURRENT + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + flags = flags or PendingIntent.FLAG_IMMUTABLE + } + val pendingIntent = PendingIntent.getActivity( + context, + 0, + viewIntent, + flags + ) + + views.setOnClickPendingIntent(R.id.appwidget_image, pendingIntent) + loadImageFromUrl( + response.thumbUrl, + context, + views, + appWidgetManager, + appWidgetId + ) } }, - t -> Timber.e(t, "Fetching picture of the day failed") - )); + { t -> Timber.e(t, "Fetching picture of the day failed") } + ) + ) } /** @@ -114,68 +122,53 @@ public class PicOfDayAppWidget extends AppWidgetProvider { * @param context The application context. * @param views The RemoteViews object used to update the App Widget UI. * @param appWidgetManager The AppWidgetManager instance for managing the widget. - * @param appWidgetId he ID of the App Widget to update. + * @param appWidgetId The ID of the App Widget to update. */ - private void loadImageFromUrl( - final String imageUrl, - final Context context, - final RemoteViews views, - final AppWidgetManager appWidgetManager, - final int appWidgetId + private fun loadImageFromUrl( + imageUrl: String?, + context: Context, + views: RemoteViews, + appWidgetManager: AppWidgetManager, + appWidgetId: Int ) { - final ImageRequest request = ImageRequestBuilder - .newBuilderWithSource(Uri.parse(imageUrl)).build(); - final ImagePipeline imagePipeline = Fresco.getImagePipeline(); - final DataSource> dataSource = imagePipeline - .fetchDecodedImage(request, context); - - dataSource.subscribe(new BaseBitmapDataSubscriber() { - @Override - protected void onNewResultImpl(@Nullable final Bitmap tempBitmap) { - Bitmap bitmap = null; - if (tempBitmap != null) { - bitmap = Bitmap.createBitmap( - tempBitmap.getWidth(), tempBitmap.getHeight(), Bitmap.Config.ARGB_8888 - ); - final Canvas canvas = new Canvas(bitmap); - canvas.drawBitmap(tempBitmap, 0f, 0f, new Paint()); + val request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageUrl)).build() + val imagePipeline = Fresco.getImagePipeline() + val dataSource = imagePipeline.fetchDecodedImage(request, context) + + dataSource.subscribe(object : BaseBitmapDataSubscriber() { + override fun onNewResultImpl(tempBitmap: Bitmap?) { + val bitmap = tempBitmap?.let { + Bitmap.createBitmap(it.width, it.height, Bitmap.Config.ARGB_8888).apply { + Canvas(this).drawBitmap(it, 0f, 0f, Paint()) + } } - views.setImageViewBitmap(R.id.appwidget_image, bitmap); - appWidgetManager.updateAppWidget(appWidgetId, views); + views.setImageViewBitmap(R.id.appwidget_image, bitmap) + appWidgetManager.updateAppWidget(appWidgetId, views) } - @Override - protected void onFailureImpl( - final DataSource> dataSource - ) { + override fun onFailureImpl(dataSource: DataSource>) { // Ignore failure for now. } - }, CallerThreadExecutor.getInstance()); + }, CallerThreadExecutor.getInstance()) } - @Override - public void onUpdate( - final Context context, - final AppWidgetManager appWidgetManager, - final int[] appWidgetIds - ) { + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { ApplicationlessInjection - .getInstance(context.getApplicationContext()) - .getCommonsApplicationComponent() - .inject(this); + .getInstance(context.applicationContext) + .commonsApplicationComponent + .inject(this) + // There may be multiple widgets active, so update all of them - for (final int appWidgetId : appWidgetIds) { - updateAppWidget(context, appWidgetManager, appWidgetId); + for (appWidgetId in appWidgetIds) { + updateAppWidget(context, appWidgetManager, appWidgetId) } } - @Override - public void onEnabled(final Context context) { + override fun onEnabled(context: Context) { // Enter relevant functionality for when the first widget is created } - @Override - public void onDisabled(final Context context) { + override fun onDisabled(context: Context) { // Enter relevant functionality for when the last widget is disabled } } diff --git a/app/src/main/java/fr/free/nrw/commons/widget/ViewHolder.kt b/app/src/main/java/fr/free/nrw/commons/widget/ViewHolder.kt index e2dd8d680e..f9f598b3e9 100644 --- a/app/src/main/java/fr/free/nrw/commons/widget/ViewHolder.kt +++ b/app/src/main/java/fr/free/nrw/commons/widget/ViewHolder.kt @@ -1,7 +1,7 @@ -package fr.free.nrw.commons.widget; +package fr.free.nrw.commons.widget -import android.content.Context; +import android.content.Context -public interface ViewHolder { - void bindModel(Context context, T model); +interface ViewHolder { + fun bindModel(context: Context, model: T) } \ No newline at end of file