mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
Migration of review module from Java to Kotlin (#5950)
* Rename .java to .kt * Migrated repository module to Kotlin * Rename .java to .kt * Migrated review module to Kotlin
This commit is contained in:
parent
e070c5dbe8
commit
bafae821e2
15 changed files with 906 additions and 932 deletions
|
|
@ -232,7 +232,7 @@ public class MoreBottomSheetFragment extends BottomSheetDialogFragment {
|
|||
}
|
||||
|
||||
protected void onPeerReviewClicked() {
|
||||
ReviewActivity.startYourself(getActivity(), getString(R.string.title_activity_review));
|
||||
ReviewActivity.Companion.startYourself(getActivity(), getString(R.string.title_activity_review));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,334 +0,0 @@
|
|||
package fr.free.nrw.commons.review;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.auth.AccountUtil;
|
||||
import fr.free.nrw.commons.databinding.ActivityReviewBinding;
|
||||
import fr.free.nrw.commons.delete.DeleteHelper;
|
||||
import fr.free.nrw.commons.media.MediaDetailFragment;
|
||||
import fr.free.nrw.commons.theme.BaseActivity;
|
||||
import fr.free.nrw.commons.utils.DialogUtil;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.Locale;
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class ReviewActivity extends BaseActivity {
|
||||
|
||||
|
||||
private ActivityReviewBinding binding;
|
||||
|
||||
MediaDetailFragment mediaDetailFragment;
|
||||
public ReviewPagerAdapter reviewPagerAdapter;
|
||||
public ReviewController reviewController;
|
||||
@Inject
|
||||
ReviewHelper reviewHelper;
|
||||
@Inject
|
||||
DeleteHelper deleteHelper;
|
||||
/**
|
||||
* Represent fragment for ReviewImage
|
||||
* Use to call some methods of ReviewImage fragment
|
||||
*/
|
||||
private ReviewImageFragment reviewImageFragment;
|
||||
|
||||
/**
|
||||
* Flag to check whether there are any non-hidden categories in the File
|
||||
*/
|
||||
private boolean hasNonHiddenCategories = false;
|
||||
|
||||
final String SAVED_MEDIA = "saved_media";
|
||||
private Media media;
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
if (media != null) {
|
||||
outState.putParcelable(SAVED_MEDIA, media);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumers should be simply using this method to use this activity.
|
||||
*
|
||||
* @param context
|
||||
* @param title Page title
|
||||
*/
|
||||
public static void startYourself(Context context, String title) {
|
||||
Intent reviewActivity = new Intent(context, ReviewActivity.class);
|
||||
reviewActivity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
reviewActivity.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
context.startActivity(reviewActivity);
|
||||
}
|
||||
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
public Media getMedia() {
|
||||
return media;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityReviewBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
setSupportActionBar(binding.toolbarBinding.toolbar);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
reviewController = new ReviewController(deleteHelper, this);
|
||||
|
||||
reviewPagerAdapter = new ReviewPagerAdapter(getSupportFragmentManager());
|
||||
binding.viewPagerReview.setAdapter(reviewPagerAdapter);
|
||||
binding.pagerIndicatorReview.setViewPager(binding.viewPagerReview);
|
||||
binding.pbReviewImage.setVisibility(View.VISIBLE);
|
||||
|
||||
Drawable d[]=binding.skipImage.getCompoundDrawablesRelative();
|
||||
d[2].setColorFilter(getApplicationContext().getResources().getColor(R.color.button_blue), PorterDuff.Mode.SRC_IN);
|
||||
|
||||
if (savedInstanceState != null && savedInstanceState.getParcelable(SAVED_MEDIA) != null) {
|
||||
updateImage(savedInstanceState.getParcelable(SAVED_MEDIA)); // Use existing media if we have one
|
||||
setUpMediaDetailOnOrientation();
|
||||
} else {
|
||||
runRandomizer(); //Run randomizer whenever everything is ready so that a first random image will be added
|
||||
}
|
||||
|
||||
binding.skipImage.setOnClickListener(view -> {
|
||||
reviewImageFragment = getInstanceOfReviewImageFragment();
|
||||
reviewImageFragment.disableButtons();
|
||||
runRandomizer();
|
||||
});
|
||||
|
||||
binding.reviewImageView.setOnClickListener(view ->setUpMediaDetailFragment());
|
||||
|
||||
binding.skipImage.setOnTouchListener((view, event) -> {
|
||||
if (event.getAction() == MotionEvent.ACTION_UP && event.getRawX() >= (
|
||||
binding.skipImage.getRight() - binding.skipImage
|
||||
.getCompoundDrawables()[2].getBounds().width())) {
|
||||
showSkipImageInfo();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
public boolean runRandomizer() {
|
||||
hasNonHiddenCategories = false;
|
||||
binding.pbReviewImage.setVisibility(View.VISIBLE);
|
||||
binding.viewPagerReview.setCurrentItem(0);
|
||||
// Finds non-hidden categories from Media instance
|
||||
compositeDisposable.add(reviewHelper.getRandomMedia()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::checkWhetherFileIsUsedInWikis));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether media is used or not in any Wiki Page
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
private void checkWhetherFileIsUsedInWikis(final Media media) {
|
||||
compositeDisposable.add(reviewHelper.checkFileUsage(media.getFilename())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
// result false indicates media is not used in any wiki
|
||||
if (!result) {
|
||||
// Finds non-hidden categories from Media instance
|
||||
findNonHiddenCategories(media);
|
||||
} else {
|
||||
runRandomizer();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds non-hidden categories and updates current image
|
||||
*/
|
||||
private void findNonHiddenCategories(Media media) {
|
||||
for(String key : media.getCategoriesHiddenStatus().keySet()) {
|
||||
Boolean value = media.getCategoriesHiddenStatus().get(key);
|
||||
// If non-hidden category is found then set hasNonHiddenCategories to true
|
||||
// so that category review cannot be skipped
|
||||
if(!value) {
|
||||
hasNonHiddenCategories = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
reviewImageFragment = getInstanceOfReviewImageFragment();
|
||||
reviewImageFragment.disableButtons();
|
||||
updateImage(media);
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void updateImage(Media media) {
|
||||
reviewHelper.addViewedImagesToDB(media.getPageId());
|
||||
this.media = media;
|
||||
String fileName = media.getFilename();
|
||||
if (fileName.length() == 0) {
|
||||
ViewUtil.showShortSnackbar(binding.drawerLayout, R.string.error_review);
|
||||
return;
|
||||
}
|
||||
|
||||
//If The Media User and Current Session Username is same then Skip the Image
|
||||
if (media.getUser() != null && media.getUser().equals(AccountUtil.getUserName(getApplicationContext()))) {
|
||||
runRandomizer();
|
||||
return;
|
||||
}
|
||||
|
||||
binding.reviewImageView.setImageURI(media.getImageUrl());
|
||||
|
||||
reviewController.onImageRefreshed(media); //file name is updated
|
||||
compositeDisposable.add(reviewHelper.getFirstRevisionOfFile(fileName)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(revision -> {
|
||||
reviewController.firstRevision = revision;
|
||||
reviewPagerAdapter.updateFileInformation();
|
||||
@SuppressLint({"StringFormatInvalid", "LocalSuppress"}) String caption = String.format(getString(R.string.review_is_uploaded_by), fileName, revision.getUser());
|
||||
binding.tvImageCaption.setText(caption);
|
||||
binding.pbReviewImage.setVisibility(View.GONE);
|
||||
reviewImageFragment = getInstanceOfReviewImageFragment();
|
||||
reviewImageFragment.enableButtons();
|
||||
}));
|
||||
binding.viewPagerReview.setCurrentItem(0);
|
||||
}
|
||||
|
||||
public void swipeToNext() {
|
||||
int nextPos = binding.viewPagerReview.getCurrentItem() + 1;
|
||||
// If currently at category fragment, then check whether the media has any non-hidden category
|
||||
if (nextPos <= 3) {
|
||||
binding.viewPagerReview.setCurrentItem(nextPos);
|
||||
if (nextPos == 2) {
|
||||
// The media has no non-hidden category. Such media are already flagged by server-side bots, so no need to review manually.
|
||||
if (!hasNonHiddenCategories) {
|
||||
swipeToNext();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
runRandomizer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
compositeDisposable.clear();
|
||||
binding = null;
|
||||
}
|
||||
|
||||
public void showSkipImageInfo(){
|
||||
DialogUtil.showAlertDialog(ReviewActivity.this,
|
||||
getString(R.string.skip_image).toUpperCase(Locale.ROOT),
|
||||
getString(R.string.skip_image_explanation),
|
||||
getString(android.R.string.ok),
|
||||
"",
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
public void showReviewImageInfo() {
|
||||
DialogUtil.showAlertDialog(ReviewActivity.this,
|
||||
getString(R.string.title_activity_review),
|
||||
getString(R.string.review_image_explanation),
|
||||
getString(android.R.string.ok),
|
||||
"",
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_review_activty, menu);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_image_info:
|
||||
showReviewImageInfo();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* this function return the instance of reviewImageFragment
|
||||
*/
|
||||
public ReviewImageFragment getInstanceOfReviewImageFragment(){
|
||||
int currentItemOfReviewPager = binding.viewPagerReview.getCurrentItem();
|
||||
reviewImageFragment = (ReviewImageFragment) reviewPagerAdapter.instantiateItem(binding.viewPagerReview, currentItemOfReviewPager);
|
||||
return reviewImageFragment;
|
||||
}
|
||||
|
||||
/**
|
||||
* set up the media detail fragment when click on the review image
|
||||
*/
|
||||
private void setUpMediaDetailFragment() {
|
||||
if (binding.mediaDetailContainer.getVisibility() == View.GONE && media != null) {
|
||||
binding.mediaDetailContainer.setVisibility(View.VISIBLE);
|
||||
binding.reviewActivityContainer.setVisibility(View.INVISIBLE);
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
mediaDetailFragment = new MediaDetailFragment();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable("media", media);
|
||||
mediaDetailFragment.setArguments(bundle);
|
||||
fragmentManager.beginTransaction().add(R.id.mediaDetailContainer, mediaDetailFragment).
|
||||
addToBackStack("MediaDetail").commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handle the back pressed event of this activity
|
||||
* this function call every time when back button is pressed
|
||||
*/
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (binding.mediaDetailContainer.getVisibility() == View.VISIBLE) {
|
||||
binding.mediaDetailContainer.setVisibility(View.GONE);
|
||||
binding.reviewActivityContainer.setVisibility(View.VISIBLE);
|
||||
}
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
* set up media detail fragment after orientation change
|
||||
*/
|
||||
private void setUpMediaDetailOnOrientation() {
|
||||
Fragment mediaDetailFragment = getSupportFragmentManager()
|
||||
.findFragmentById(R.id.mediaDetailContainer);
|
||||
if (mediaDetailFragment != null) {
|
||||
binding.mediaDetailContainer.setVisibility(View.VISIBLE);
|
||||
binding.reviewActivityContainer.setVisibility(View.INVISIBLE);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.mediaDetailContainer, mediaDetailFragment).commit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
336
app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.kt
Normal file
336
app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.kt
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
package fr.free.nrw.commons.review
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.PorterDuff
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.auth.AccountUtil
|
||||
import fr.free.nrw.commons.databinding.ActivityReviewBinding
|
||||
import fr.free.nrw.commons.delete.DeleteHelper
|
||||
import fr.free.nrw.commons.media.MediaDetailFragment
|
||||
import fr.free.nrw.commons.theme.BaseActivity
|
||||
import fr.free.nrw.commons.utils.DialogUtil
|
||||
import fr.free.nrw.commons.utils.ViewUtil
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
class ReviewActivity : BaseActivity() {
|
||||
|
||||
private lateinit var binding: ActivityReviewBinding
|
||||
|
||||
private var mediaDetailFragment: MediaDetailFragment? = null
|
||||
lateinit var reviewPagerAdapter: ReviewPagerAdapter
|
||||
lateinit var reviewController: ReviewController
|
||||
|
||||
@Inject
|
||||
lateinit var reviewHelper: ReviewHelper
|
||||
|
||||
@Inject
|
||||
lateinit var deleteHelper: DeleteHelper
|
||||
|
||||
/**
|
||||
* Represent fragment for ReviewImage
|
||||
* Use to call some methods of ReviewImage fragment
|
||||
*/
|
||||
private var reviewImageFragment: ReviewImageFragment? = null
|
||||
private var hasNonHiddenCategories = false
|
||||
var media: Media? = null
|
||||
|
||||
private val SAVED_MEDIA = "saved_media"
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
media?.let {
|
||||
outState.putParcelable(SAVED_MEDIA, it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumers should be simply using this method to use this activity.
|
||||
*
|
||||
* @param context
|
||||
* @param title Page title
|
||||
*/
|
||||
companion object {
|
||||
fun startYourself(context: Context, title: String) {
|
||||
val reviewActivity = Intent(context, ReviewActivity::class.java)
|
||||
reviewActivity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
|
||||
reviewActivity.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
context.startActivity(reviewActivity)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityReviewBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
setSupportActionBar(binding.toolbarBinding?.toolbar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
reviewController = ReviewController(deleteHelper, this)
|
||||
|
||||
reviewPagerAdapter = ReviewPagerAdapter(supportFragmentManager)
|
||||
binding.viewPagerReview.adapter = reviewPagerAdapter
|
||||
binding.pagerIndicatorReview.setViewPager(binding.viewPagerReview)
|
||||
binding.pbReviewImage.visibility = View.VISIBLE
|
||||
|
||||
binding.skipImage.compoundDrawablesRelative[2]?.setColorFilter(
|
||||
resources.getColor(R.color.button_blue),
|
||||
PorterDuff.Mode.SRC_IN
|
||||
)
|
||||
|
||||
if (savedInstanceState?.getParcelable<Media>(SAVED_MEDIA) != null) {
|
||||
updateImage(savedInstanceState.getParcelable(SAVED_MEDIA)!!)
|
||||
setUpMediaDetailOnOrientation()
|
||||
} else {
|
||||
runRandomizer()
|
||||
}
|
||||
|
||||
binding.skipImage.setOnClickListener {
|
||||
reviewImageFragment = getInstanceOfReviewImageFragment()
|
||||
reviewImageFragment?.disableButtons()
|
||||
runRandomizer()
|
||||
}
|
||||
|
||||
binding.reviewImageView.setOnClickListener {
|
||||
setUpMediaDetailFragment()
|
||||
}
|
||||
|
||||
binding.skipImage.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_UP &&
|
||||
event.rawX >= (binding.skipImage.right - binding.skipImage.compoundDrawables[2].bounds.width())
|
||||
) {
|
||||
showSkipImageInfo()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun runRandomizer(): Boolean {
|
||||
hasNonHiddenCategories = false
|
||||
binding.pbReviewImage.visibility = View.VISIBLE
|
||||
binding.viewPagerReview.currentItem = 0
|
||||
|
||||
compositeDisposable.add(
|
||||
reviewHelper.getRandomMedia()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(::checkWhetherFileIsUsedInWikis)
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether media is used or not in any Wiki Page
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
private fun checkWhetherFileIsUsedInWikis(media: Media) {
|
||||
compositeDisposable.add(
|
||||
reviewHelper.checkFileUsage(media.filename)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { result ->
|
||||
if (!result) {
|
||||
findNonHiddenCategories(media)
|
||||
} else {
|
||||
runRandomizer()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds non-hidden categories and updates current image
|
||||
*/
|
||||
private fun findNonHiddenCategories(media: Media) {
|
||||
this.media = media
|
||||
// If non-hidden category is found then set hasNonHiddenCategories to true
|
||||
// so that category review cannot be skipped
|
||||
hasNonHiddenCategories = media.categoriesHiddenStatus.values.any { !it }
|
||||
reviewImageFragment = getInstanceOfReviewImageFragment()
|
||||
reviewImageFragment?.disableButtons()
|
||||
updateImage(media)
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun updateImage(media: Media) {
|
||||
reviewHelper.addViewedImagesToDB(media.pageId)
|
||||
this.media = media
|
||||
val fileName = media.filename
|
||||
|
||||
if (fileName.isNullOrEmpty()) {
|
||||
ViewUtil.showShortSnackbar(binding.drawerLayout, R.string.error_review)
|
||||
return
|
||||
}
|
||||
|
||||
//If The Media User and Current Session Username is same then Skip the Image
|
||||
if (media.user == AccountUtil.getUserName(applicationContext)) {
|
||||
runRandomizer()
|
||||
return
|
||||
}
|
||||
|
||||
binding.reviewImageView.setImageURI(media.imageUrl)
|
||||
|
||||
reviewController.onImageRefreshed(media) // filename is updated
|
||||
compositeDisposable.add(
|
||||
reviewHelper.getFirstRevisionOfFile(fileName)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { revision ->
|
||||
reviewController.firstRevision = revision
|
||||
reviewPagerAdapter.updateFileInformation()
|
||||
val caption = getString(
|
||||
R.string.review_is_uploaded_by,
|
||||
fileName,
|
||||
revision.user
|
||||
)
|
||||
binding.tvImageCaption.text = caption
|
||||
binding.pbReviewImage.visibility = View.GONE
|
||||
reviewImageFragment = getInstanceOfReviewImageFragment()
|
||||
reviewImageFragment?.enableButtons()
|
||||
}
|
||||
)
|
||||
binding.viewPagerReview.currentItem = 0
|
||||
}
|
||||
|
||||
fun swipeToNext() {
|
||||
val nextPos = binding.viewPagerReview.currentItem + 1
|
||||
|
||||
// If currently at category fragment, then check whether the media has any non-hidden category
|
||||
if (nextPos <= 3) {
|
||||
binding.viewPagerReview.currentItem = nextPos
|
||||
if (nextPos == 2 && !hasNonHiddenCategories)
|
||||
{
|
||||
// The media has no non-hidden category. Such media are already flagged by server-side bots, so no need to review manually.
|
||||
swipeToNext()
|
||||
}
|
||||
} else {
|
||||
runRandomizer()
|
||||
}
|
||||
}
|
||||
|
||||
public override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
fun showSkipImageInfo() {
|
||||
DialogUtil.showAlertDialog(
|
||||
this,
|
||||
getString(R.string.skip_image).uppercase(Locale.ROOT),
|
||||
getString(R.string.skip_image_explanation),
|
||||
getString(android.R.string.ok),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
fun showReviewImageInfo() {
|
||||
DialogUtil.showAlertDialog(
|
||||
this,
|
||||
getString(R.string.title_activity_review),
|
||||
getString(R.string.review_image_explanation),
|
||||
getString(android.R.string.ok),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_review_activty, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.menu_image_info -> {
|
||||
showReviewImageInfo()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this function return the instance of reviewImageFragment
|
||||
*/
|
||||
private fun getInstanceOfReviewImageFragment(): ReviewImageFragment? {
|
||||
val currentItemOfReviewPager = binding.viewPagerReview.currentItem
|
||||
return reviewPagerAdapter.instantiateItem(
|
||||
binding.viewPagerReview,
|
||||
currentItemOfReviewPager
|
||||
) as? ReviewImageFragment
|
||||
}
|
||||
|
||||
/**
|
||||
* set up the media detail fragment when click on the review image
|
||||
*/
|
||||
private fun setUpMediaDetailFragment() {
|
||||
if (binding.mediaDetailContainer.visibility == View.GONE && media != null) {
|
||||
binding.mediaDetailContainer.visibility = View.VISIBLE
|
||||
binding.reviewActivityContainer.visibility = View.INVISIBLE
|
||||
val fragmentManager = supportFragmentManager
|
||||
mediaDetailFragment = MediaDetailFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putParcelable("media", media)
|
||||
}
|
||||
}
|
||||
fragmentManager.beginTransaction()
|
||||
.add(R.id.mediaDetailContainer, mediaDetailFragment!!)
|
||||
.addToBackStack("MediaDetail")
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handle the back pressed event of this activity
|
||||
* this function call every time when back button is pressed
|
||||
*/
|
||||
@Deprecated("This method has been deprecated in favor of using the" +
|
||||
"{@link OnBackPressedDispatcher} via {@link #getOnBackPressedDispatcher()}." +
|
||||
"The OnBackPressedDispatcher controls how back button events are dispatched" +
|
||||
"to one or more {@link OnBackPressedCallback} objects.")
|
||||
override fun onBackPressed() {
|
||||
if (binding.mediaDetailContainer.visibility == View.VISIBLE) {
|
||||
binding.mediaDetailContainer.visibility = View.GONE
|
||||
binding.reviewActivityContainer.visibility = View.VISIBLE
|
||||
}
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
/**
|
||||
* set up media detail fragment after orientation change
|
||||
*/
|
||||
private fun setUpMediaDetailOnOrientation() {
|
||||
val fragment = supportFragmentManager.findFragmentById(R.id.mediaDetailContainer)
|
||||
fragment?.let {
|
||||
binding.mediaDetailContainer.visibility = View.VISIBLE
|
||||
binding.reviewActivityContainer.visibility = View.INVISIBLE
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.mediaDetailContainer, it)
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,220 +0,0 @@
|
|||
package fr.free.nrw.commons.review;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
|
||||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.actions.PageEditClient;
|
||||
import fr.free.nrw.commons.actions.ThanksClient;
|
||||
import fr.free.nrw.commons.delete.DeleteHelper;
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.ObservableSource;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import timber.log.Timber;
|
||||
|
||||
@Singleton
|
||||
public class ReviewController {
|
||||
private static final int NOTIFICATION_SEND_THANK = 0x102;
|
||||
private static final int NOTIFICATION_CHECK_CATEGORY = 0x101;
|
||||
protected static ArrayList<String> categories;
|
||||
@Inject
|
||||
ThanksClient thanksClient;
|
||||
|
||||
@Inject
|
||||
SessionManager sessionManager;
|
||||
private final DeleteHelper deleteHelper;
|
||||
@Nullable
|
||||
MwQueryPage.Revision firstRevision; // TODO: maybe we can expand this class to include fileName
|
||||
@Inject
|
||||
@Named("commons-page-edit")
|
||||
PageEditClient pageEditClient;
|
||||
private NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder notificationBuilder;
|
||||
private Media media;
|
||||
|
||||
ReviewController(DeleteHelper deleteHelper, Context context) {
|
||||
this.deleteHelper = deleteHelper;
|
||||
CommonsApplication.createNotificationChannel(context.getApplicationContext());
|
||||
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationBuilder = new NotificationCompat.Builder(context, CommonsApplication.NOTIFICATION_CHANNEL_ID_ALL);
|
||||
}
|
||||
|
||||
void onImageRefreshed(Media media) {
|
||||
this.media = media;
|
||||
}
|
||||
|
||||
public Media getMedia() {
|
||||
return media;
|
||||
}
|
||||
|
||||
public enum DeleteReason {
|
||||
SPAM,
|
||||
COPYRIGHT_VIOLATION
|
||||
}
|
||||
|
||||
void reportSpam(@NonNull Activity activity, ReviewCallback reviewCallback) {
|
||||
Timber.d("Report spam for %s", media.getFilename());
|
||||
deleteHelper.askReasonAndExecute(media,
|
||||
activity,
|
||||
activity.getResources().getString(R.string.review_spam_report_question),
|
||||
DeleteReason.SPAM,
|
||||
reviewCallback);
|
||||
}
|
||||
|
||||
void reportPossibleCopyRightViolation(@NonNull Activity activity, ReviewCallback reviewCallback) {
|
||||
Timber.d("Report spam for %s", media.getFilename());
|
||||
deleteHelper.askReasonAndExecute(media,
|
||||
activity,
|
||||
activity.getResources().getString(R.string.review_c_violation_report_question),
|
||||
DeleteReason.COPYRIGHT_VIOLATION,
|
||||
reviewCallback);
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
void reportWrongCategory(@NonNull Activity activity, ReviewCallback reviewCallback) {
|
||||
Context context = activity.getApplicationContext();
|
||||
ApplicationlessInjection
|
||||
.getInstance(context)
|
||||
.getCommonsApplicationComponent()
|
||||
.inject(this);
|
||||
|
||||
ViewUtil.showShortToast(context, context.getString(R.string.check_category_toast, media.getDisplayTitle()));
|
||||
|
||||
publishProgress(context, 0);
|
||||
String summary = context.getString(R.string.check_category_edit_summary);
|
||||
Observable.defer((Callable<ObservableSource<Boolean>>) () ->
|
||||
pageEditClient.appendEdit(media.getFilename(), "\n{{subst:chc}}\n", summary))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe((result) -> {
|
||||
publishProgress(context, 2);
|
||||
String message;
|
||||
String title;
|
||||
|
||||
if (result) {
|
||||
title = context.getString(R.string.check_category_success_title);
|
||||
message = context.getString(R.string.check_category_success_message, media.getDisplayTitle());
|
||||
reviewCallback.onSuccess();
|
||||
} else {
|
||||
title = context.getString(R.string.check_category_failure_title);
|
||||
message = context.getString(R.string.check_category_failure_message, media.getDisplayTitle());
|
||||
reviewCallback.onFailure();
|
||||
}
|
||||
|
||||
showNotification(title, message);
|
||||
|
||||
}, Timber::e);
|
||||
}
|
||||
|
||||
private void publishProgress(@NonNull Context context, int i) {
|
||||
int[] messages = new int[]{R.string.getting_edit_token, R.string.check_category_adding_template};
|
||||
String message = "";
|
||||
if (0 < i && i < messages.length) {
|
||||
message = context.getString(messages[i]);
|
||||
}
|
||||
|
||||
notificationBuilder.setContentTitle(context.getString(R.string.check_category_notification_title, media.getDisplayTitle()))
|
||||
.setStyle(new NotificationCompat.BigTextStyle()
|
||||
.bigText(message))
|
||||
.setSmallIcon(R.drawable.ic_launcher)
|
||||
.setProgress(messages.length, i, false)
|
||||
.setOngoing(true);
|
||||
notificationManager.notify(NOTIFICATION_CHECK_CATEGORY, notificationBuilder.build());
|
||||
}
|
||||
|
||||
@SuppressLint({"CheckResult", "StringFormatInvalid"})
|
||||
void sendThanks(@NonNull Activity activity) {
|
||||
Context context = activity.getApplicationContext();
|
||||
ApplicationlessInjection
|
||||
.getInstance(context)
|
||||
.getCommonsApplicationComponent()
|
||||
.inject(this);
|
||||
ViewUtil.showShortToast(context, context.getString(R.string.send_thank_toast, media.getDisplayTitle()));
|
||||
|
||||
if (firstRevision == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Observable.defer((Callable<ObservableSource<Boolean>>) () -> thanksClient.thank(firstRevision.getRevisionId()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
displayThanksToast(context, result);
|
||||
}, throwable -> {
|
||||
if (throwable instanceof InvalidLoginTokenException) {
|
||||
final String username = sessionManager.getUserName();
|
||||
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
|
||||
activity,
|
||||
activity.getString(R.string.invalid_login_message),
|
||||
username
|
||||
);
|
||||
|
||||
CommonsApplication.getInstance().clearApplicationData(
|
||||
activity, logoutListener);
|
||||
} else {
|
||||
Timber.e(throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
private void displayThanksToast(final Context context, final boolean result){
|
||||
final String message;
|
||||
final String title;
|
||||
if (result) {
|
||||
title = context.getString(R.string.send_thank_success_title);
|
||||
message = context.getString(R.string.send_thank_success_message, media.getDisplayTitle());
|
||||
} else {
|
||||
title = context.getString(R.string.send_thank_failure_title);
|
||||
message = context.getString(R.string.send_thank_failure_message, media.getDisplayTitle());
|
||||
}
|
||||
|
||||
ViewUtil.showShortToast(context,message);
|
||||
}
|
||||
|
||||
private void showNotification(String title, String message) {
|
||||
notificationBuilder.setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||
.setContentTitle(title)
|
||||
.setStyle(new NotificationCompat.BigTextStyle()
|
||||
.bigText(message))
|
||||
.setSmallIcon(R.drawable.ic_launcher)
|
||||
.setProgress(0, 0, false)
|
||||
.setOngoing(false)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||
notificationManager.notify(NOTIFICATION_SEND_THANK, notificationBuilder.build());
|
||||
}
|
||||
|
||||
public interface ReviewCallback {
|
||||
void onSuccess();
|
||||
|
||||
void onFailure();
|
||||
|
||||
void onTokenException(Exception e);
|
||||
|
||||
void disableButtons();
|
||||
|
||||
void enableButtons();
|
||||
}
|
||||
}
|
||||
231
app/src/main/java/fr/free/nrw/commons/review/ReviewController.kt
Normal file
231
app/src/main/java/fr/free/nrw/commons/review/ReviewController.kt
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
package fr.free.nrw.commons.review
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
|
||||
import androidx.core.app.NotificationCompat
|
||||
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
|
||||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
import javax.inject.Singleton
|
||||
|
||||
import fr.free.nrw.commons.CommonsApplication
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.actions.PageEditClient
|
||||
import fr.free.nrw.commons.actions.ThanksClient
|
||||
import fr.free.nrw.commons.delete.DeleteHelper
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection
|
||||
import fr.free.nrw.commons.utils.ViewUtil
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.ObservableSource
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
|
||||
|
||||
@Singleton
|
||||
class ReviewController @Inject constructor(
|
||||
private val deleteHelper: DeleteHelper,
|
||||
context: Context
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private const val NOTIFICATION_SEND_THANK = 0x102
|
||||
private const val NOTIFICATION_CHECK_CATEGORY = 0x101
|
||||
protected var categories: ArrayList<String> = ArrayList()
|
||||
}
|
||||
|
||||
@Inject
|
||||
lateinit var thanksClient: ThanksClient
|
||||
|
||||
@Inject
|
||||
lateinit var sessionManager: SessionManager
|
||||
|
||||
@Inject
|
||||
@field: Named("commons-page-edit")
|
||||
lateinit var pageEditClient: PageEditClient
|
||||
|
||||
var firstRevision: MwQueryPage.Revision? = null // TODO: maybe we can expand this class to include fileName
|
||||
|
||||
private val notificationManager: NotificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
private val notificationBuilder: NotificationCompat.Builder =
|
||||
NotificationCompat.Builder(context, CommonsApplication.NOTIFICATION_CHANNEL_ID_ALL)
|
||||
|
||||
var media: Media? = null
|
||||
|
||||
init {
|
||||
CommonsApplication.createNotificationChannel(context.applicationContext)
|
||||
}
|
||||
|
||||
fun onImageRefreshed(media: Media) {
|
||||
this.media = media
|
||||
}
|
||||
|
||||
enum class DeleteReason {
|
||||
SPAM,
|
||||
COPYRIGHT_VIOLATION
|
||||
}
|
||||
|
||||
fun reportSpam(activity: Activity, reviewCallback: ReviewCallback) {
|
||||
Timber.d("Report spam for %s", media?.filename)
|
||||
deleteHelper.askReasonAndExecute(
|
||||
media,
|
||||
activity,
|
||||
activity.resources.getString(R.string.review_spam_report_question),
|
||||
DeleteReason.SPAM,
|
||||
reviewCallback
|
||||
)
|
||||
}
|
||||
|
||||
fun reportPossibleCopyRightViolation(activity: Activity, reviewCallback: ReviewCallback) {
|
||||
Timber.d("Report copyright violation for %s", media?.filename)
|
||||
deleteHelper.askReasonAndExecute(
|
||||
media,
|
||||
activity,
|
||||
activity.resources.getString(R.string.review_c_violation_report_question),
|
||||
DeleteReason.COPYRIGHT_VIOLATION,
|
||||
reviewCallback
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun reportWrongCategory(activity: Activity, reviewCallback: ReviewCallback) {
|
||||
val context = activity.applicationContext
|
||||
ApplicationlessInjection
|
||||
.getInstance(context)
|
||||
.commonsApplicationComponent
|
||||
.inject(this)
|
||||
|
||||
ViewUtil.showShortToast(
|
||||
context,
|
||||
context.getString(R.string.check_category_toast, media?.displayTitle)
|
||||
)
|
||||
|
||||
publishProgress(context, 0)
|
||||
val summary = context.getString(R.string.check_category_edit_summary)
|
||||
|
||||
Observable.defer {
|
||||
pageEditClient.appendEdit(media?.filename ?: "", "\n{{subst:chc}}\n", summary)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ result ->
|
||||
publishProgress(context, 2)
|
||||
val (title, message) = if (result) {
|
||||
reviewCallback.onSuccess()
|
||||
context.getString(R.string.check_category_success_title) to
|
||||
context.getString(R.string.check_category_success_message, media?.displayTitle)
|
||||
} else {
|
||||
reviewCallback.onFailure()
|
||||
context.getString(R.string.check_category_failure_title) to
|
||||
context.getString(R.string.check_category_failure_message, media?.displayTitle)
|
||||
}
|
||||
showNotification(title, message)
|
||||
}, Timber::e)
|
||||
}
|
||||
|
||||
private fun publishProgress(context: Context, progress: Int) {
|
||||
val messages = arrayOf(
|
||||
R.string.getting_edit_token,
|
||||
R.string.check_category_adding_template
|
||||
)
|
||||
|
||||
val message = if (progress in 1 until messages.size) {
|
||||
context.getString(messages[progress])
|
||||
} else ""
|
||||
|
||||
notificationBuilder.setContentTitle(
|
||||
context.getString(
|
||||
R.string.check_category_notification_title,
|
||||
media?.displayTitle
|
||||
)
|
||||
)
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
|
||||
.setSmallIcon(R.drawable.ic_launcher)
|
||||
.setProgress(messages.size, progress, false)
|
||||
.setOngoing(true)
|
||||
|
||||
notificationManager.notify(NOTIFICATION_CHECK_CATEGORY, notificationBuilder.build())
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun sendThanks(activity: Activity) {
|
||||
val context = activity.applicationContext
|
||||
ApplicationlessInjection
|
||||
.getInstance(context)
|
||||
.commonsApplicationComponent
|
||||
.inject(this)
|
||||
|
||||
ViewUtil.showShortToast(
|
||||
context,
|
||||
context.getString(R.string.send_thank_toast, media?.displayTitle)
|
||||
)
|
||||
|
||||
if (firstRevision == null) return
|
||||
|
||||
Observable.defer {
|
||||
thanksClient.thank(firstRevision!!.revisionId)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ result ->
|
||||
displayThanksToast(context, result)
|
||||
}, { throwable ->
|
||||
if (throwable is InvalidLoginTokenException) {
|
||||
val username = sessionManager.userName
|
||||
val logoutListener = CommonsApplication.BaseLogoutListener(
|
||||
activity,
|
||||
activity.getString(R.string.invalid_login_message),
|
||||
username
|
||||
)
|
||||
CommonsApplication.instance.clearApplicationData(activity, logoutListener)
|
||||
} else {
|
||||
Timber.e(throwable)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
private fun displayThanksToast(context: Context, result: Boolean) {
|
||||
val (title, message) = if (result) {
|
||||
context.getString(R.string.send_thank_success_title) to
|
||||
context.getString(R.string.send_thank_success_message, media?.displayTitle)
|
||||
} else {
|
||||
context.getString(R.string.send_thank_failure_title) to
|
||||
context.getString(R.string.send_thank_failure_message, media?.displayTitle)
|
||||
}
|
||||
|
||||
ViewUtil.showShortToast(context, message)
|
||||
}
|
||||
|
||||
private fun showNotification(title: String, message: String) {
|
||||
notificationBuilder.setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||
.setContentTitle(title)
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
|
||||
.setSmallIcon(R.drawable.ic_launcher)
|
||||
.setProgress(0, 0, false)
|
||||
.setOngoing(false)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
|
||||
notificationManager.notify(NOTIFICATION_SEND_THANK, notificationBuilder.build())
|
||||
}
|
||||
|
||||
interface ReviewCallback {
|
||||
fun onSuccess()
|
||||
fun onFailure()
|
||||
fun onTokenException(e: Exception)
|
||||
fun disableButtons()
|
||||
fun enableButtons()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
package fr.free.nrw.commons.review;
|
||||
package fr.free.nrw.commons.review
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
|
||||
/**
|
||||
* Dao interface for reviewed images database
|
||||
*/
|
||||
@Dao
|
||||
public interface ReviewDao {
|
||||
interface ReviewDao {
|
||||
|
||||
/**
|
||||
* Inserts reviewed/skipped image identifier into the database
|
||||
|
|
@ -17,7 +17,7 @@ public interface ReviewDao {
|
|||
* @param reviewEntity
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
void insert(ReviewEntity reviewEntity);
|
||||
fun insert(reviewEntity: ReviewEntity)
|
||||
|
||||
/**
|
||||
* Checks if the image has already been reviewed/skipped by the user
|
||||
|
|
@ -26,7 +26,6 @@ public interface ReviewDao {
|
|||
* @param imageId
|
||||
* @return
|
||||
*/
|
||||
@Query( "SELECT EXISTS (SELECT * from `reviewed-images` where imageId = (:imageId))")
|
||||
Boolean isReviewedAlready(String imageId);
|
||||
|
||||
}
|
||||
@Query("SELECT EXISTS (SELECT * from `reviewed-images` where imageId = (:imageId))")
|
||||
fun isReviewedAlready(imageId: String): Boolean
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package fr.free.nrw.commons.review;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
/**
|
||||
* Entity to store reviewed/skipped images identifier
|
||||
*/
|
||||
@Entity(tableName = "reviewed-images")
|
||||
public class ReviewEntity {
|
||||
@PrimaryKey
|
||||
@NonNull
|
||||
String imageId;
|
||||
|
||||
public ReviewEntity(String imageId) {
|
||||
this.imageId = imageId;
|
||||
}
|
||||
}
|
||||
13
app/src/main/java/fr/free/nrw/commons/review/ReviewEntity.kt
Normal file
13
app/src/main/java/fr/free/nrw/commons/review/ReviewEntity.kt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package fr.free.nrw.commons.review
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
/**
|
||||
* Entity to store reviewed/skipped images identifier
|
||||
*/
|
||||
@Entity(tableName = "reviewed-images")
|
||||
data class ReviewEntity(
|
||||
@PrimaryKey
|
||||
val imageId: String
|
||||
)
|
||||
|
|
@ -77,7 +77,7 @@ class ReviewHelper
|
|||
* @param image
|
||||
* @return
|
||||
*/
|
||||
fun getReviewStatus(image: String?): Boolean = dao?.isReviewedAlready(image) ?: false
|
||||
fun getReviewStatus(image: String?): Boolean = image?.let { dao?.isReviewedAlready(it) } ?: false
|
||||
|
||||
/**
|
||||
* Gets the first revision of the file from filename
|
||||
|
|
@ -132,7 +132,7 @@ class ReviewHelper
|
|||
*/
|
||||
fun addViewedImagesToDB(imageId: String?) {
|
||||
Completable
|
||||
.fromAction { dao!!.insert(ReviewEntity(imageId)) }
|
||||
.fromAction { imageId?.let { ReviewEntity(it) }?.let { dao!!.insert(it) } }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
|
|
|
|||
|
|
@ -1,262 +0,0 @@
|
|||
package fr.free.nrw.commons.review;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
|
||||
import fr.free.nrw.commons.databinding.FragmentReviewImageBinding;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class ReviewImageFragment extends CommonsDaggerSupportFragment {
|
||||
|
||||
static final int CATEGORY = 2;
|
||||
private static final int SPAM = 0;
|
||||
private static final int COPYRIGHT = 1;
|
||||
private static final int THANKS = 3;
|
||||
|
||||
private int position;
|
||||
|
||||
private FragmentReviewImageBinding binding;
|
||||
|
||||
@Inject
|
||||
SessionManager sessionManager;
|
||||
|
||||
|
||||
// Constant variable used to store user's key name for onSaveInstanceState method
|
||||
private final String SAVED_USER = "saved_user";
|
||||
|
||||
// Variable that stores the value of user
|
||||
private String user;
|
||||
|
||||
public void update(final int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
private String updateCategoriesQuestion() {
|
||||
final Media media = getReviewActivity().getMedia();
|
||||
if (media != null && media.getCategoriesHiddenStatus() != null && isAdded()) {
|
||||
// Filter category name attribute from all categories
|
||||
final List<String> categories = new ArrayList<>();
|
||||
for(final String key : media.getCategoriesHiddenStatus().keySet()) {
|
||||
String value = String.valueOf(key);
|
||||
// Each category returned has a format like "Category:<some-category-name>"
|
||||
// so remove the prefix "Category:"
|
||||
final int index = key.indexOf("Category:");
|
||||
if(index == 0) {
|
||||
value = key.substring(9);
|
||||
}
|
||||
categories.add(value);
|
||||
}
|
||||
String catString = TextUtils.join(", ", categories);
|
||||
if (catString != null && !catString.equals("") && binding.tvReviewQuestionContext != null) {
|
||||
catString = "<b>" + catString + "</b>";
|
||||
final String stringToConvertHtml = String.format(getResources().getString(R.string.review_category_explanation), catString);
|
||||
return Html.fromHtml(stringToConvertHtml).toString();
|
||||
}
|
||||
}
|
||||
return getResources().getString(R.string.review_no_category);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
|
||||
final Bundle savedInstanceState) {
|
||||
position = getArguments().getInt("position");
|
||||
binding = FragmentReviewImageBinding.inflate(inflater, container, false);
|
||||
|
||||
final String question;
|
||||
String explanation=null;
|
||||
String yesButtonText;
|
||||
final String noButtonText;
|
||||
|
||||
binding.buttonYes.setOnClickListener(view -> onYesButtonClicked());
|
||||
|
||||
switch (position) {
|
||||
case SPAM:
|
||||
question = getString(R.string.review_spam);
|
||||
explanation = getString(R.string.review_spam_explanation);
|
||||
yesButtonText = getString(R.string.yes);
|
||||
noButtonText = getString(R.string.no);
|
||||
binding.buttonNo.setOnClickListener(view -> getReviewActivity()
|
||||
.reviewController.reportSpam(requireActivity(), getReviewCallback()));
|
||||
break;
|
||||
case COPYRIGHT:
|
||||
enableButtons();
|
||||
question = getString(R.string.review_copyright);
|
||||
explanation = getString(R.string.review_copyright_explanation);
|
||||
yesButtonText = getString(R.string.yes);
|
||||
noButtonText = getString(R.string.no);
|
||||
binding.buttonNo.setOnClickListener(view -> getReviewActivity()
|
||||
.reviewController
|
||||
.reportPossibleCopyRightViolation(requireActivity(), getReviewCallback()));
|
||||
break;
|
||||
case CATEGORY:
|
||||
enableButtons();
|
||||
question = getString(R.string.review_category);
|
||||
explanation = updateCategoriesQuestion();
|
||||
yesButtonText = getString(R.string.yes);
|
||||
noButtonText = getString(R.string.no);
|
||||
binding.buttonNo.setOnClickListener(view -> {
|
||||
getReviewActivity()
|
||||
.reviewController
|
||||
.reportWrongCategory(requireActivity(), getReviewCallback());
|
||||
getReviewActivity().swipeToNext();
|
||||
});
|
||||
break;
|
||||
case THANKS:
|
||||
enableButtons();
|
||||
question = getString(R.string.review_thanks);
|
||||
|
||||
if (getReviewActivity().reviewController.firstRevision != null) {
|
||||
user = getReviewActivity().reviewController.firstRevision.getUser();
|
||||
} else {
|
||||
if(savedInstanceState != null) {
|
||||
user = savedInstanceState.getString(SAVED_USER);
|
||||
}
|
||||
}
|
||||
|
||||
//if the user is null because of whatsoever reason, review will not be sent anyways
|
||||
if (!TextUtils.isEmpty(user)) {
|
||||
explanation = getString(R.string.review_thanks_explanation, user);
|
||||
}
|
||||
|
||||
// Note that the yes and no buttons are swapped in this section
|
||||
yesButtonText = getString(R.string.review_thanks_yes_button_text);
|
||||
noButtonText = getString(R.string.review_thanks_no_button_text);
|
||||
binding.buttonYes.setTextColor(Color.parseColor("#116aaa"));
|
||||
binding.buttonNo.setTextColor(Color.parseColor("#228b22"));
|
||||
binding.buttonNo.setOnClickListener(view -> {
|
||||
getReviewActivity().reviewController.sendThanks(getReviewActivity());
|
||||
getReviewActivity().swipeToNext();
|
||||
});
|
||||
break;
|
||||
default:
|
||||
enableButtons();
|
||||
question = "How did we get here?";
|
||||
explanation = "No idea.";
|
||||
yesButtonText = "yes";
|
||||
noButtonText = "no";
|
||||
}
|
||||
|
||||
binding.tvReviewQuestion.setText(question);
|
||||
binding.tvReviewQuestionContext.setText(explanation);
|
||||
binding.buttonYes.setText(yesButtonText);
|
||||
binding.buttonNo.setText(noButtonText);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method will be called when configuration changes happen
|
||||
*
|
||||
* @param outState
|
||||
*/
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
//Save user name when configuration changes happen
|
||||
outState.putString(SAVED_USER, user);
|
||||
}
|
||||
|
||||
private ReviewController.ReviewCallback getReviewCallback() {
|
||||
return new ReviewController
|
||||
.ReviewCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
getReviewActivity().runRandomizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure() {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTokenException(final Exception e) {
|
||||
if (e instanceof InvalidLoginTokenException){
|
||||
final String username = sessionManager.getUserName();
|
||||
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
|
||||
getActivity(),
|
||||
requireActivity().getString(R.string.invalid_login_message),
|
||||
username
|
||||
);
|
||||
|
||||
CommonsApplication.getInstance().clearApplicationData(
|
||||
requireActivity(), logoutListener);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when an image is being loaded
|
||||
* to disable the review buttons
|
||||
*/
|
||||
@Override
|
||||
public void disableButtons() {
|
||||
ReviewImageFragment.this.disableButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when an image has
|
||||
* been loaded to enable the review buttons.
|
||||
*/
|
||||
@Override
|
||||
public void enableButtons() {
|
||||
ReviewImageFragment.this.enableButtons();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when an image has
|
||||
* been loaded to enable the review buttons.
|
||||
*/
|
||||
public void enableButtons() {
|
||||
binding.buttonYes.setEnabled(true);
|
||||
binding.buttonYes.setAlpha(1);
|
||||
binding.buttonNo.setEnabled(true);
|
||||
binding.buttonNo.setAlpha(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when an image is being loaded
|
||||
* to disable the review buttons
|
||||
*/
|
||||
public void disableButtons() {
|
||||
binding.buttonYes.setEnabled(false);
|
||||
binding.buttonYes.setAlpha(0.5f);
|
||||
binding.buttonNo.setEnabled(false);
|
||||
binding.buttonNo.setAlpha(0.5f);
|
||||
}
|
||||
|
||||
void onYesButtonClicked() {
|
||||
getReviewActivity().swipeToNext();
|
||||
}
|
||||
|
||||
private ReviewActivity getReviewActivity() {
|
||||
return (ReviewActivity) requireActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
package fr.free.nrw.commons.review
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import fr.free.nrw.commons.CommonsApplication
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
|
||||
import fr.free.nrw.commons.databinding.FragmentReviewImageBinding
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
|
||||
import java.util.ArrayList
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class ReviewImageFragment : CommonsDaggerSupportFragment() {
|
||||
|
||||
companion object {
|
||||
const val CATEGORY = 2
|
||||
private const val SPAM = 0
|
||||
private const val COPYRIGHT = 1
|
||||
private const val THANKS = 3
|
||||
}
|
||||
|
||||
private var position: Int = 0
|
||||
private var binding: FragmentReviewImageBinding? = null
|
||||
|
||||
@Inject
|
||||
lateinit var sessionManager: SessionManager
|
||||
|
||||
// Constant variable used to store user's key name for onSaveInstanceState method
|
||||
private val SAVED_USER = "saved_user"
|
||||
|
||||
// Variable that stores the value of user
|
||||
private var user: String? = null
|
||||
|
||||
fun update(position: Int) {
|
||||
this.position = position
|
||||
}
|
||||
|
||||
private fun updateCategoriesQuestion(): String {
|
||||
val media = reviewActivity.media
|
||||
if (media?.categoriesHiddenStatus != null && isAdded) {
|
||||
// Filter category name attribute from all categories
|
||||
val categories = media.categoriesHiddenStatus.keys.map { key ->
|
||||
var value = key
|
||||
// Each category returned has a format like "Category:<some-category-name>"
|
||||
// so remove the prefix "Category:"
|
||||
if (key.startsWith("Category:")) {
|
||||
value = key.substring(9)
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
val catString = categories.joinToString(", ")
|
||||
if (catString.isNotEmpty() && binding?.tvReviewQuestionContext != null) {
|
||||
val formattedCatString = "<b>$catString</b>"
|
||||
val stringToConvertHtml = getString(
|
||||
R.string.review_category_explanation,
|
||||
formattedCatString
|
||||
)
|
||||
return Html.fromHtml(stringToConvertHtml).toString()
|
||||
}
|
||||
}
|
||||
return getString(R.string.review_no_category)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
position = requireArguments().getInt("position")
|
||||
binding = FragmentReviewImageBinding.inflate(inflater, container, false)
|
||||
|
||||
val question: String
|
||||
var explanation: String? = null
|
||||
val yesButtonText: String
|
||||
val noButtonText: String
|
||||
|
||||
binding?.buttonYes?.setOnClickListener { onYesButtonClicked() }
|
||||
|
||||
when (position) {
|
||||
SPAM -> {
|
||||
question = getString(R.string.review_spam)
|
||||
explanation = getString(R.string.review_spam_explanation)
|
||||
yesButtonText = getString(R.string.yes)
|
||||
noButtonText = getString(R.string.no)
|
||||
binding?.buttonNo?.setOnClickListener {
|
||||
reviewActivity.reviewController.reportSpam(requireActivity(), reviewCallback)
|
||||
}
|
||||
}
|
||||
COPYRIGHT -> {
|
||||
enableButtons()
|
||||
question = getString(R.string.review_copyright)
|
||||
explanation = getString(R.string.review_copyright_explanation)
|
||||
yesButtonText = getString(R.string.yes)
|
||||
noButtonText = getString(R.string.no)
|
||||
binding?.buttonNo?.setOnClickListener {
|
||||
reviewActivity.reviewController.reportPossibleCopyRightViolation(
|
||||
requireActivity(),
|
||||
reviewCallback
|
||||
)
|
||||
}
|
||||
}
|
||||
CATEGORY -> {
|
||||
enableButtons()
|
||||
question = getString(R.string.review_category)
|
||||
explanation = updateCategoriesQuestion()
|
||||
yesButtonText = getString(R.string.yes)
|
||||
noButtonText = getString(R.string.no)
|
||||
binding?.buttonNo?.setOnClickListener {
|
||||
reviewActivity.reviewController.reportWrongCategory(
|
||||
requireActivity(),
|
||||
reviewCallback
|
||||
)
|
||||
reviewActivity.swipeToNext()
|
||||
}
|
||||
}
|
||||
THANKS -> {
|
||||
enableButtons()
|
||||
question = getString(R.string.review_thanks)
|
||||
|
||||
user = reviewActivity.reviewController.firstRevision?.user
|
||||
?: savedInstanceState?.getString(SAVED_USER)
|
||||
|
||||
//if the user is null because of whatsoever reason, review will not be sent anyways
|
||||
if (!user.isNullOrEmpty()) {
|
||||
explanation = getString(R.string.review_thanks_explanation, user)
|
||||
}
|
||||
|
||||
// Note that the yes and no buttons are swapped in this section
|
||||
yesButtonText = getString(R.string.review_thanks_yes_button_text)
|
||||
noButtonText = getString(R.string.review_thanks_no_button_text)
|
||||
binding?.buttonYes?.setTextColor(Color.parseColor("#116aaa"))
|
||||
binding?.buttonNo?.setTextColor(Color.parseColor("#228b22"))
|
||||
binding?.buttonNo?.setOnClickListener {
|
||||
reviewActivity.reviewController.sendThanks(requireActivity())
|
||||
reviewActivity.swipeToNext()
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
enableButtons()
|
||||
question = "How did we get here?"
|
||||
explanation = "No idea."
|
||||
yesButtonText = "yes"
|
||||
noButtonText = "no"
|
||||
}
|
||||
}
|
||||
|
||||
binding?.apply {
|
||||
tvReviewQuestion.text = question
|
||||
tvReviewQuestionContext.text = explanation
|
||||
buttonYes.text = yesButtonText
|
||||
buttonNo.text = noButtonText
|
||||
}
|
||||
return binding?.root
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when configuration changes happen
|
||||
*
|
||||
* @param outState
|
||||
*/
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
//Save user name when configuration changes happen
|
||||
outState.putString(SAVED_USER, user)
|
||||
}
|
||||
|
||||
private val reviewCallback: ReviewController.ReviewCallback
|
||||
get() = object : ReviewController.ReviewCallback {
|
||||
override fun onSuccess() {
|
||||
reviewActivity.runRandomizer()
|
||||
}
|
||||
|
||||
override fun onFailure() {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
override fun onTokenException(e: Exception) {
|
||||
if (e is InvalidLoginTokenException) {
|
||||
val username = sessionManager.userName
|
||||
val logoutListener = activity?.let {
|
||||
CommonsApplication.BaseLogoutListener(
|
||||
it,
|
||||
getString(R.string.invalid_login_message),
|
||||
username
|
||||
)
|
||||
}
|
||||
|
||||
if (logoutListener != null) {
|
||||
CommonsApplication.instance.clearApplicationData(
|
||||
requireActivity(), logoutListener
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun disableButtons() {
|
||||
this@ReviewImageFragment.disableButtons()
|
||||
}
|
||||
|
||||
override fun enableButtons() {
|
||||
this@ReviewImageFragment.enableButtons()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when an image has
|
||||
* been loaded to enable the review buttons.
|
||||
*/
|
||||
fun enableButtons() {
|
||||
binding?.apply {
|
||||
buttonYes.isEnabled = true
|
||||
buttonYes.alpha = 1f
|
||||
buttonNo.isEnabled = true
|
||||
buttonNo.alpha = 1f
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when an image is being loaded
|
||||
* to disable the review buttons
|
||||
*/
|
||||
fun disableButtons() {
|
||||
binding?.apply {
|
||||
buttonYes.isEnabled = false
|
||||
buttonYes.alpha = 0.5f
|
||||
buttonNo.isEnabled = false
|
||||
buttonNo.alpha = 0.5f
|
||||
}
|
||||
}
|
||||
|
||||
fun onYesButtonClicked() {
|
||||
reviewActivity.swipeToNext()
|
||||
}
|
||||
|
||||
private val reviewActivity: ReviewActivity
|
||||
get() = requireActivity() as ReviewActivity
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
binding = null
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
package fr.free.nrw.commons.review;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
|
||||
public class ReviewPagerAdapter extends FragmentStatePagerAdapter {
|
||||
private ReviewImageFragment[] reviewImageFragments;
|
||||
|
||||
/**
|
||||
* this function return the instance of ReviewviewPage current item
|
||||
*/
|
||||
@Override
|
||||
public Object instantiateItem(@NonNull ViewGroup container, int position) {
|
||||
return super.instantiateItem(container, position);
|
||||
}
|
||||
|
||||
ReviewPagerAdapter(FragmentManager fm) {
|
||||
super(fm);
|
||||
reviewImageFragments = new ReviewImageFragment[]{
|
||||
new ReviewImageFragment(),
|
||||
new ReviewImageFragment(),
|
||||
new ReviewImageFragment(),
|
||||
new ReviewImageFragment()
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return reviewImageFragments.length;
|
||||
}
|
||||
|
||||
void updateFileInformation() {
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
ReviewImageFragment fragment = reviewImageFragments[i];
|
||||
fragment.update(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("position", position);
|
||||
reviewImageFragments[position].setArguments(bundle);
|
||||
return reviewImageFragments[position];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package fr.free.nrw.commons.review
|
||||
|
||||
import android.os.Bundle
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter
|
||||
|
||||
|
||||
class ReviewPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
|
||||
private val reviewImageFragments: Array<ReviewImageFragment> = arrayOf(
|
||||
ReviewImageFragment(),
|
||||
ReviewImageFragment(),
|
||||
ReviewImageFragment(),
|
||||
ReviewImageFragment()
|
||||
)
|
||||
|
||||
override fun getCount(): Int {
|
||||
return reviewImageFragments.size
|
||||
}
|
||||
|
||||
fun updateFileInformation() {
|
||||
for (i in 0 until count) {
|
||||
val fragment = reviewImageFragments[i]
|
||||
fragment.update(i)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItem(position: Int): Fragment {
|
||||
val bundle = Bundle().apply {
|
||||
putInt("position", position)
|
||||
}
|
||||
reviewImageFragments[position].arguments = bundle
|
||||
return reviewImageFragments[position]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package fr.free.nrw.commons.review;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
public class ReviewViewPager extends ViewPager {
|
||||
|
||||
public ReviewViewPager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ReviewViewPager(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
// Never allow swiping to switch between pages
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
// Never allow swiping to switch between pages
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package fr.free.nrw.commons.review
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
|
||||
class ReviewViewPager @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : ViewPager(context, attrs) {
|
||||
|
||||
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
||||
// Never allow swiping to switch between pages
|
||||
return false
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
// Never allow swiping to switch between pages
|
||||
return false
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue