Add background color option for media detail page (#5394)

* feat: add backgroundColor property on media

* feat: add optional menu items for media backgroundColor

* fix: test pass when running in batch

* refactor: remove backgroundColor from media

* refactor: add string for background color menu

* chore: remove useless change

* feat: change media image background color

* feat: pass backgroundColor to ZoomableActivity

* chore: remove extra space
This commit is contained in:
Pierre Monier 2023-11-30 02:07:53 +01:00 committed by GitHub
parent 9028e0ed32
commit e1e4f9329a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 260 additions and 15 deletions

View file

@ -17,6 +17,7 @@ import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.drawable.Animatable;
import android.net.Uri;
@ -78,6 +79,7 @@ import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.explore.depictions.WikidataItemDetailsActivity;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.media.ZoomableActivity.ZoomableActivityConstants;
import fr.free.nrw.commons.profile.ProfileActivity;
import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.ui.widget.HtmlTextView;
@ -111,8 +113,11 @@ import timber.log.Timber;
public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
CategoryEditHelper.Callback {
private static final int REQUEST_CODE = 1001 ;
private static final int REQUEST_CODE_EDIT_DESCRIPTION = 1002 ;
private static final int REQUEST_CODE = 1001;
private static final int REQUEST_CODE_EDIT_DESCRIPTION = 1002;
private static final String IMAGE_BACKGROUND_COLOR = "image_background_color";
static final int DEFAULT_IMAGE_BACKGROUND_COLOR = 0;
private boolean editable;
private boolean isCategoryImage;
private MediaDetailPagerFragment.MediaDetailProvider detailProvider;
@ -388,6 +393,15 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
zoomableIntent.setData(Uri.parse(media.getImageUrl()));
zoomableIntent.putExtra(
ZoomableActivity.ZoomableActivityConstants.ORIGIN, "MediaDetails");
int backgroundColor = getImageBackgroundColor();
if (backgroundColor != DEFAULT_IMAGE_BACKGROUND_COLOR) {
zoomableIntent.putExtra(
ZoomableActivity.ZoomableActivityConstants.PHOTO_BACKGROUND_COLOR,
backgroundColor
);
}
ctx.startActivity(
zoomableIntent
);
@ -599,6 +613,10 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
* - when the high resolution image is available, it replaces the low resolution image
*/
private void setupImageView() {
int imageBackgroundColor = getImageBackgroundColor();
if (imageBackgroundColor != DEFAULT_IMAGE_BACKGROUND_COLOR) {
image.setBackgroundColor(imageBackgroundColor);
}
image.getHierarchy().setPlaceholderImage(R.drawable.image_placeholder);
image.getHierarchy().setFailureImage(R.drawable.image_placeholder);
@ -1472,4 +1490,28 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
public interface Callback {
void nominatingForDeletion(int index);
}
/**
* Called when the image background color is changed.
* You should pass a useable color, not a resource id.
* @param color
*/
public void onImageBackgroundChanged(int color) {
int currentColor = getImageBackgroundColor();
if (currentColor == color) {
return;
}
image.setBackgroundColor(color);
getImageBackgroundColorPref().edit().putInt(IMAGE_BACKGROUND_COLOR, color).apply();
}
private SharedPreferences getImageBackgroundColorPref() {
return getContext().getSharedPreferences(IMAGE_BACKGROUND_COLOR + media.getPageId(), Context.MODE_PRIVATE);
}
private int getImageBackgroundColor() {
SharedPreferences imageBackgroundColorPref = this.getImageBackgroundColorPref();
return imageBackgroundColorPref.getInt(IMAGE_BACKGROUND_COLOR, DEFAULT_IMAGE_BACKGROUND_COLOR);
}
}

View file

@ -5,6 +5,8 @@ import static fr.free.nrw.commons.Utils.handleWebUrl;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
@ -18,6 +20,7 @@ import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
@ -41,9 +44,16 @@ import fr.free.nrw.commons.utils.DownloadUtils;
import fr.free.nrw.commons.utils.ImageUtils;
import fr.free.nrw.commons.utils.NetworkUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.Callable;
import javax.inject.Inject;
import timber.log.Timber;
@ -190,6 +200,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
}
Media m = provider.getMediaAtPosition(pager.getCurrentItem());
MediaDetailFragment mediaDetailFragment = this.adapter.getCurrentMediaDetailFragment();
switch (item.getItemId()) {
case R.id.menu_bookmark_current_image:
boolean bookmarkExists = bookmarkDao.updateBookmark(bookmark);
@ -243,6 +254,16 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
return true;
case R.id.menu_view_report:
showReportDialog(m);
case R.id.menu_view_set_white_background:
if (mediaDetailFragment != null) {
mediaDetailFragment.onImageBackgroundChanged(ContextCompat.getColor(getContext(), R.color.white));
}
return true;
case R.id.menu_view_set_black_background:
if (mediaDetailFragment != null) {
mediaDetailFragment.onImageBackgroundChanged(ContextCompat.getColor(getContext(), R.color.black));
}
return true;
default:
return super.onOptionsItemSelected(item);
}
@ -372,6 +393,17 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
if (m.getUser() != null) {
menu.findItem(R.id.menu_view_user_page).setEnabled(true).setVisible(true);
}
try {
URL mediaUrl = new URL(m.getImageUrl());
this.handleBackgroundColorMenuItems(
() -> BitmapFactory.decodeStream(mediaUrl.openConnection().getInputStream()),
menu
);
} catch (Exception e) {
Timber.e("Cant detect media transparency");
}
// Initialize bookmark object
bookmark = new Bookmark(
m.getFilename(),
@ -422,6 +454,25 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
}
}
/**
* Decide wether or not we should display the background color menu items
* We display them if the image is transparent
* @param getBitmap
* @param menu
*/
private void handleBackgroundColorMenuItems(Callable<Bitmap> getBitmap, Menu menu) {
Observable.fromCallable(
getBitmap
).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(image -> {
if (image.hasAlpha()) {
menu.findItem(R.id.menu_view_set_white_background).setVisible(true).setEnabled(true);
menu.findItem(R.id.menu_view_set_black_background).setVisible(true).setEnabled(true);
}
});
}
private void updateBookmarkState(MenuItem item) {
boolean isBookmarked = bookmarkDao.findBookmark(bookmark);
if(isBookmarked) {
@ -567,6 +618,18 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
return mCurrentFragment;
}
/**
* If current fragment is of type MediaDetailFragment, return it, otherwise return null.
* @return MediaDetailFragment
*/
public MediaDetailFragment getCurrentMediaDetailFragment() {
if (mCurrentFragment instanceof MediaDetailFragment) {
return (MediaDetailFragment) mCurrentFragment;
}
return null;
}
/**
* Called to inform the adapter of which item is currently considered to be the "primary",
* that is the one show to the user as the current page.

View file

@ -13,6 +13,7 @@ import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider
import butterknife.BindView
import butterknife.ButterKnife
@ -69,6 +70,8 @@ class ZoomableActivity : BaseActivity() {
@JvmField
@BindView(R.id.zoomable)
var photo: ZoomableDraweeView? = null
var photoBackgroundColor: Int? = null
@JvmField
@BindView(R.id.zoom_progress_bar)
@ -180,6 +183,13 @@ class ZoomableActivity : BaseActivity() {
).apply()
}
}
val backgroundColor = intent.getIntExtra(ZoomableActivityConstants.PHOTO_BACKGROUND_COLOR,
MediaDetailFragment.DEFAULT_IMAGE_BACKGROUND_COLOR);
if (backgroundColor != MediaDetailFragment.DEFAULT_IMAGE_BACKGROUND_COLOR) {
photoBackgroundColor = backgroundColor
}
}
/**
@ -196,7 +206,7 @@ class ZoomableActivity : BaseActivity() {
/**
* Handle view model result.
*/
private fun handleResult(result: Result){
private fun handleResult(result: Result) {
if(result.status is CallbackStatus.SUCCESS){
val images = result.images
if(images.isNotEmpty()) {
@ -608,6 +618,10 @@ class ZoomableActivity : BaseActivity() {
.setControllerListener(loadingListener)
.build()
photo!!.controller = controller
if (photoBackgroundColor != null) {
photo!!.setBackgroundColor(photoBackgroundColor!!)
}
if (!images.isNullOrEmpty()) {
val selectedIndex = getImagePosition(selectedImages, images!![position])
@ -667,5 +681,7 @@ class ZoomableActivity : BaseActivity() {
* the custom picker.
*/
const val ORIGIN = "Origin";
const val PHOTO_BACKGROUND_COLOR = "photo_background_color"
}
}