Migrated widget module to Kotlin

This commit is contained in:
Saifuddin 2024-11-19 14:22:48 +05:30
parent 169f05e2fc
commit c5f8892d05
4 changed files with 144 additions and 157 deletions

View file

@ -2,7 +2,6 @@ package fr.free.nrw.commons.di;
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;

View file

@ -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)
}
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?) : super(context, attrs) {
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;
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {
initializeHeight(context)
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
heightSpec = MeasureSpec.makeMeasureSpec((int) (height*0.3), MeasureSpec.AT_MOST);
super.onMeasure(widthSpec, heightSpec);
private fun initializeHeight(context: Context) {
val displayMetrics = DisplayMetrics()
(context as Activity).windowManager.defaultDisplay.getMetrics(displayMetrics)
height = displayMetrics.heightPixels
}
override fun onMeasure(widthSpec: Int, heightSpec: Int) {
val limitedHeightSpec = MeasureSpec.makeMeasureSpec(
(height * 0.3).toInt(),
MeasureSpec.AT_MOST
)
super.onMeasure(widthSpec, limitedHeightSpec)
}
}

View file

@ -1,69 +1,65 @@
package fr.free.nrw.commons.widget;
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;
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<CloseableReference<CloseableImage>> dataSource = imagePipeline
.fetchDecodedImage(request, context);
val request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageUrl)).build()
val imagePipeline = Fresco.getImagePipeline()
val 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());
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<CloseableReference<CloseableImage>> dataSource
) {
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
// 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
}
}

View file

@ -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<T> {
void bindModel(Context context, T model);
interface ViewHolder<T> {
fun bindModel(context: Context, model: T)
}