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 com.google.gson.Gson;
import fr.free.nrw.commons.actions.PageEditClient;
import fr.free.nrw.commons.explore.categories.CategoriesModule; import fr.free.nrw.commons.explore.categories.CategoriesModule;
import fr.free.nrw.commons.navtab.MoreBottomSheetFragment; import fr.free.nrw.commons.navtab.MoreBottomSheetFragment;
import fr.free.nrw.commons.navtab.MoreBottomSheetLoggedOutFragment; 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.app.Activity
import android.content.Context; import android.content.Context
import android.util.AttributeSet; import android.util.AttributeSet
import android.util.DisplayMetrics; 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. * Created by Ilgaz Er on 8/7/2018.
*/ */
public class HeightLimitedRecyclerView extends RecyclerView { class HeightLimitedRecyclerView : RecyclerView {
int height; private var height: Int = 0
public HeightLimitedRecyclerView(Context context) {
super(context); constructor(context: Context) : super(context) {
DisplayMetrics displayMetrics = new DisplayMetrics(); initializeHeight(context)
((Activity) getContext()).getWindowManager()
.getDefaultDisplay()
.getMetrics(displayMetrics);
height=displayMetrics.heightPixels;
} }
public HeightLimitedRecyclerView(Context context, @Nullable AttributeSet attrs) { constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
super(context, attrs); initializeHeight(context)
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager()
.getDefaultDisplay()
.getMetrics(displayMetrics);
height=displayMetrics.heightPixels;
} }
public HeightLimitedRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {
super(context, attrs, defStyle); initializeHeight(context)
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager()
.getDefaultDisplay()
.getMetrics(displayMetrics);
height=displayMetrics.heightPixels;
} }
@Override private fun initializeHeight(context: Context) {
protected void onMeasure(int widthSpec, int heightSpec) { val displayMetrics = DisplayMetrics()
heightSpec = MeasureSpec.makeMeasureSpec((int) (height*0.3), MeasureSpec.AT_MOST); (context as Activity).windowManager.defaultDisplay.getMetrics(displayMetrics)
super.onMeasure(widthSpec, heightSpec); 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.app.PendingIntent
import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider; import android.appwidget.AppWidgetProvider
import android.content.Context; import android.content.Context
import android.content.Intent; import android.content.Intent
import android.graphics.Bitmap; import android.graphics.Bitmap
import android.graphics.Canvas; import android.graphics.Canvas
import android.graphics.Paint; import android.graphics.Paint
import android.net.Uri; import android.net.Uri
import android.os.Build; import android.os.Build
import android.widget.RemoteViews; import android.widget.RemoteViews
import androidx.annotation.Nullable; import androidx.annotation.Nullable
import com.facebook.common.executors.CallerThreadExecutor; import com.facebook.common.executors.CallerThreadExecutor
import com.facebook.common.references.CloseableReference; import com.facebook.common.references.CloseableReference
import com.facebook.datasource.DataSource; import com.facebook.datasource.DataSource
import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.core.ImagePipeline; import com.facebook.imagepipeline.core.ImagePipeline
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
import com.facebook.imagepipeline.image.CloseableImage; import com.facebook.imagepipeline.image.CloseableImage
import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequest
import com.facebook.imagepipeline.request.ImageRequestBuilder; import com.facebook.imagepipeline.request.ImageRequestBuilder
import fr.free.nrw.commons.media.MediaClient; import fr.free.nrw.commons.media.MediaClient
import javax.inject.Inject; import javax.inject.Inject
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R
import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.contributions.MainActivity
import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.di.ApplicationlessInjection
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers
import timber.log.Timber; import timber.log.Timber
import static android.content.Intent.ACTION_VIEW;
/** /**
* Implementation of App Widget functionality. * Implementation of App Widget functionality.
*/ */
public class PicOfDayAppWidget extends AppWidgetProvider { class PicOfDayAppWidget : AppWidgetProvider() {
private final CompositeDisposable compositeDisposable = new CompositeDisposable(); private val compositeDisposable = CompositeDisposable()
@Inject @Inject
MediaClient mediaClient; lateinit var mediaClient: MediaClient
void updateAppWidget( private fun updateAppWidget(
final Context context, context: Context,
final AppWidgetManager appWidgetManager, appWidgetManager: AppWidgetManager,
final int appWidgetId appWidgetId: Int
) { ) {
final RemoteViews views = new RemoteViews( val views = RemoteViews(context.packageName, R.layout.pic_of_day_app_widget)
context.getPackageName(), R.layout.pic_of_day_app_widget);
// Launch App on Button Click // Launch App on Button Click
final Intent viewIntent = new Intent(context, MainActivity.class); val viewIntent = Intent(context, MainActivity::class.java)
int flags = PendingIntent.FLAG_UPDATE_CURRENT; var flags = PendingIntent.FLAG_UPDATE_CURRENT
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
flags |= PendingIntent.FLAG_IMMUTABLE; flags = flags or PendingIntent.FLAG_IMMUTABLE
} }
final PendingIntent pendingIntent = PendingIntent.getActivity( val pendingIntent = PendingIntent.getActivity(context, 0, viewIntent, flags)
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 context The application context.
* @param views The RemoteViews object used to update the App Widget UI. * @param views The RemoteViews object used to update the App Widget UI.
* @param appWidgetManager The AppWidgetManager instance for managing the widget. * @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( private fun loadPictureOfTheDay(
final Context context, context: Context,
final RemoteViews views, views: RemoteViews,
final AppWidgetManager appWidgetManager, appWidgetManager: AppWidgetManager,
final int appWidgetId appWidgetId: Int
) { ) {
compositeDisposable.add(mediaClient.getPictureOfTheDay() compositeDisposable.add(
mediaClient.getPictureOfTheDay()
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
response -> { { response ->
if (response != null) { if (response != null) {
views.setTextViewText(R.id.appwidget_title, response.getDisplayTitle()); views.setTextViewText(R.id.appwidget_title, response.displayTitle)
// View in browser // View in browser
final Intent viewIntent = new Intent(); val viewIntent = Intent().apply {
viewIntent.setAction(ACTION_VIEW); action = Intent.ACTION_VIEW
viewIntent.setData(Uri.parse(response.getPageTitle().getMobileUri())); data = Uri.parse(response.pageTitle.mobileUri)
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.M) {
flags |= PendingIntent.FLAG_IMMUTABLE;
} }
final PendingIntent pendingIntent = PendingIntent.getActivity(
context, 0, viewIntent, flags);
views.setOnClickPendingIntent(R.id.appwidget_image, pendingIntent); var flags = PendingIntent.FLAG_UPDATE_CURRENT
loadImageFromUrl(response.getThumbUrl(), if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
context, views, appWidgetManager, appWidgetId); 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 context The application context.
* @param views The RemoteViews object used to update the App Widget UI. * @param views The RemoteViews object used to update the App Widget UI.
* @param appWidgetManager The AppWidgetManager instance for managing the widget. * @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( private fun loadImageFromUrl(
final String imageUrl, imageUrl: String?,
final Context context, context: Context,
final RemoteViews views, views: RemoteViews,
final AppWidgetManager appWidgetManager, appWidgetManager: AppWidgetManager,
final int appWidgetId appWidgetId: Int
) { ) {
final ImageRequest request = ImageRequestBuilder val request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageUrl)).build()
.newBuilderWithSource(Uri.parse(imageUrl)).build(); val imagePipeline = Fresco.getImagePipeline()
final ImagePipeline imagePipeline = Fresco.getImagePipeline(); val dataSource = imagePipeline.fetchDecodedImage(request, context)
final DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline
.fetchDecodedImage(request, context);
dataSource.subscribe(new BaseBitmapDataSubscriber() { dataSource.subscribe(object : BaseBitmapDataSubscriber() {
@Override override fun onNewResultImpl(tempBitmap: Bitmap?) {
protected void onNewResultImpl(@Nullable final Bitmap tempBitmap) { val bitmap = tempBitmap?.let {
Bitmap bitmap = null; Bitmap.createBitmap(it.width, it.height, Bitmap.Config.ARGB_8888).apply {
if (tempBitmap != null) { Canvas(this).drawBitmap(it, 0f, 0f, Paint())
bitmap = Bitmap.createBitmap( }
tempBitmap.getWidth(), tempBitmap.getHeight(), Bitmap.Config.ARGB_8888
);
final Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(tempBitmap, 0f, 0f, new Paint());
} }
views.setImageViewBitmap(R.id.appwidget_image, bitmap); views.setImageViewBitmap(R.id.appwidget_image, bitmap)
appWidgetManager.updateAppWidget(appWidgetId, views); appWidgetManager.updateAppWidget(appWidgetId, views)
} }
@Override override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
protected void onFailureImpl(
final DataSource<CloseableReference<CloseableImage>> dataSource
) {
// Ignore failure for now. // Ignore failure for now.
} }
}, CallerThreadExecutor.getInstance()); }, CallerThreadExecutor.getInstance())
} }
@Override override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
public void onUpdate(
final Context context,
final AppWidgetManager appWidgetManager,
final int[] appWidgetIds
) {
ApplicationlessInjection ApplicationlessInjection
.getInstance(context.getApplicationContext()) .getInstance(context.applicationContext)
.getCommonsApplicationComponent() .commonsApplicationComponent
.inject(this); .inject(this)
// There may be multiple widgets active, so update all of them // There may be multiple widgets active, so update all of them
for (final int appWidgetId : appWidgetIds) { for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId); updateAppWidget(context, appWidgetManager, appWidgetId)
} }
} }
@Override override fun onEnabled(context: Context) {
public void onEnabled(final Context context) {
// Enter relevant functionality for when the first widget is created // Enter relevant functionality for when the first widget is created
} }
@Override override fun onDisabled(context: Context) {
public void onDisabled(final Context context) {
// Enter relevant functionality for when the last widget is disabled // 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> { interface ViewHolder<T> {
void bindModel(Context context, T model); fun bindModel(context: Context, model: T)
} }