mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
Todo for user (#3851)
* Add a simple message * Categories are edited * Display categories * read whole page * Revert wrong changes * Add newly added category field * Doesnt displaey alreasy added categories * add strings for notifications * clean code * Readd accidentally removed imports * Fix edit layout style * Fix category update messages * Pass isWikipediaButtonDisplayed information to fragment * Remove unused class * Fix strings * Fix string * Add exeption for uncategorised images too * Revert project.xml changes * fix update buttonvisibility issue * Make sure it works for auto added categories too * make the button visible * Make the button appear when categories are entered * Include cancel button * Make view updated too * Make category view edited * Update categories in an hacky way * Fix unnecessary method call * Add notes for short term fix to display added category * Fix tests * Fix strings * Fix click issue
This commit is contained in:
parent
f5e28834fc
commit
1856196851
20 changed files with 799 additions and 36 deletions
|
|
@ -121,4 +121,14 @@ class Media constructor(
|
|||
get() = captions[Locale.getDefault().language]
|
||||
?: captions.values.firstOrNull()
|
||||
?: displayTitle
|
||||
|
||||
/**
|
||||
* Gets the categories the file falls under.
|
||||
* @return file categories as an ArrayList of Strings
|
||||
*/
|
||||
var addedCategories: List<String>? = null
|
||||
// TODO added categories should be removed. It is added for a short fix. On category update,
|
||||
// categories should be re-fetched instead
|
||||
get() = field // getter
|
||||
set(value) { field = value } // setter
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package fr.free.nrw.commons.actions;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.SingleOnSubscribe;
|
||||
import org.wikipedia.csrf.CsrfTokenClient;
|
||||
import org.wikipedia.dataclient.Service;
|
||||
|
||||
|
|
@ -48,12 +50,16 @@ public class PageEditClient {
|
|||
* @param summary Edit summary
|
||||
*/
|
||||
public Observable<Boolean> appendEdit(String pageTitle, String appendText, String summary) {
|
||||
return Single.create((SingleOnSubscribe<String>) emitter -> {
|
||||
try {
|
||||
return pageEditInterface.postAppendEdit(pageTitle, summary, appendText, csrfTokenClient.getTokenBlocking())
|
||||
.map(editResponse -> editResponse.edit().editSucceeded());
|
||||
emitter.onSuccess(csrfTokenClient.getTokenBlocking());
|
||||
} catch (Throwable throwable) {
|
||||
return Observable.just(false);
|
||||
emitter.onError(throwable);
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}).flatMapObservable(token -> pageEditInterface.postAppendEdit(pageTitle, summary, appendText, token)
|
||||
.map(editResponse -> editResponse.edit().editSucceeded()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import javax.inject.Singleton
|
|||
const val CATEGORY_PREFIX = "Category:"
|
||||
const val SUB_CATEGORY_CONTINUATION_PREFIX = "sub_category_"
|
||||
const val PARENT_CATEGORY_CONTINUATION_PREFIX = "parent_category_"
|
||||
const val CATEGORY_UNCATEGORISED = "uncategorised"
|
||||
const val CATEGORY_NEEDING_CATEGORIES = "needing categories"
|
||||
|
||||
/**
|
||||
* Category Client to handle custom calls to Commons MediaWiki APIs
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
package fr.free.nrw.commons.category;
|
||||
|
||||
import static fr.free.nrw.commons.notification.NotificationHelper.NOTIFICATION_EDIT_CATEGORY;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import fr.free.nrw.commons.BuildConfig;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.actions.PageEditClient;
|
||||
import fr.free.nrw.commons.notification.NotificationHelper;
|
||||
import fr.free.nrw.commons.utils.ViewUtilWrapper;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class CategoryEditHelper {
|
||||
private final NotificationHelper notificationHelper;
|
||||
public final PageEditClient pageEditClient;
|
||||
private final ViewUtilWrapper viewUtil;
|
||||
private final String username;
|
||||
private Callback callback;
|
||||
|
||||
@Inject
|
||||
public CategoryEditHelper(NotificationHelper notificationHelper,
|
||||
@Named("commons-page-edit") PageEditClient pageEditClient,
|
||||
ViewUtilWrapper viewUtil,
|
||||
@Named("username") String username) {
|
||||
this.notificationHelper = notificationHelper;
|
||||
this.pageEditClient = pageEditClient;
|
||||
this.viewUtil = viewUtil;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public interface to edit categories
|
||||
* @param context
|
||||
* @param media
|
||||
* @param categories
|
||||
* @return
|
||||
*/
|
||||
public Single<Boolean> makeCategoryEdit(Context context, Media media, List<String> categories, Callback callback) {
|
||||
viewUtil.showShortToast(context, context.getString(R.string.category_edit_helper_make_edit_toast));
|
||||
return addCategory(media, categories)
|
||||
.flatMapSingle(result -> Single.just(showCategoryEditNotification(context, media, result)))
|
||||
.firstOrError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends new categories
|
||||
* @param media
|
||||
* @param categories to be added
|
||||
* @return
|
||||
*/
|
||||
private Observable<Boolean> addCategory(Media media, List<String> categories) {
|
||||
Timber.d("thread is category adding %s", Thread.currentThread().getName());
|
||||
String summary = "Adding categories";
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
if (categories != null && categories.size() != 0) {
|
||||
|
||||
for (int i = 0; i < categories.size(); i++) {
|
||||
buffer.append("\n[[Category:").append(categories.get(i)).append("]]");
|
||||
}
|
||||
} else {
|
||||
buffer.append("{{subst:unc}}");
|
||||
}
|
||||
String appendText = buffer.toString();
|
||||
return pageEditClient.appendEdit(media.getFilename(), appendText + "\n", summary);
|
||||
}
|
||||
|
||||
private boolean showCategoryEditNotification(Context context, Media media, boolean result) {
|
||||
String message;
|
||||
String title = context.getString(R.string.category_edit_helper_show_edit_title);
|
||||
|
||||
if (result) {
|
||||
title += ": " + context.getString(R.string.category_edit_helper_show_edit_title_success);
|
||||
StringBuilder categoriesInMessage = new StringBuilder();
|
||||
List<String> mediaCategoryList = media.getCategories();
|
||||
for (String category : mediaCategoryList) {
|
||||
categoriesInMessage.append(category);
|
||||
if (category.equals(mediaCategoryList.get(mediaCategoryList.size()-1))) {
|
||||
continue;
|
||||
}
|
||||
categoriesInMessage.append(",");
|
||||
}
|
||||
|
||||
message = context.getResources().getQuantityString(R.plurals.category_edit_helper_show_edit_message_if, mediaCategoryList.size(), categoriesInMessage.toString());
|
||||
} else {
|
||||
title += ": " + context.getString(R.string.category_edit_helper_show_edit_title);
|
||||
message = context.getString(R.string.category_edit_helper_edit_message_else) ;
|
||||
}
|
||||
|
||||
String urlForFile = BuildConfig.COMMONS_URL + "/wiki/" + media.getFilename();
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlForFile));
|
||||
notificationHelper.showNotification(context, title, message, NOTIFICATION_EDIT_CATEGORY, browserIntent);
|
||||
return result;
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
boolean updateCategoryDisplay(List<String> categories);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
package fr.free.nrw.commons.category;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.Filter;
|
||||
import android.widget.Filterable;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.category.CategoryEditSearchRecyclerViewAdapter.RecyclerViewHolder;
|
||||
import fr.free.nrw.commons.nearby.Label;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CategoryEditSearchRecyclerViewAdapter
|
||||
extends RecyclerView.Adapter<RecyclerViewHolder>
|
||||
implements Filterable {
|
||||
|
||||
private List<String> displayedCategories;
|
||||
private List<String> categories = new ArrayList<>();
|
||||
private List<String> newCategories = new ArrayList<>();
|
||||
private final LayoutInflater inflater;
|
||||
private CategoryClient categoryClient;
|
||||
private Context context;
|
||||
|
||||
private Callback callback;
|
||||
|
||||
public CategoryEditSearchRecyclerViewAdapter(Context context, ArrayList<Label> labels,
|
||||
RecyclerView categoryRecyclerView, CategoryClient categoryClient, Callback callback) {
|
||||
this.context = context;
|
||||
inflater = LayoutInflater.from(context);
|
||||
this.categoryClient = categoryClient;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void addToCategories(List<String> categories) {
|
||||
for(String category : categories) {
|
||||
if (!this.categories.contains(category)) {
|
||||
this.categories.add(category);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addToCategories(String categoryToBeAdded) {
|
||||
if (!categories.contains(categoryToBeAdded)) {
|
||||
categories.add(categoryToBeAdded);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFromCategories(String categoryToBeRemoved) {
|
||||
if (categories.contains(categoryToBeRemoved)) {
|
||||
categories.remove(categoryToBeRemoved);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFromNewCategories(String categoryToBeRemoved) {
|
||||
if (newCategories.contains(categoryToBeRemoved)) {
|
||||
newCategories.remove(categoryToBeRemoved);
|
||||
}
|
||||
}
|
||||
|
||||
public void addToNewCategories(List<String> newCategories) {
|
||||
for(String category : newCategories) {
|
||||
if (!this.newCategories.contains(category)) {
|
||||
this.newCategories.add(category);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addToNewCategories(String addedCategory) {
|
||||
if (!newCategories.contains(addedCategory)) {
|
||||
newCategories.add(addedCategory);
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getCategories() {
|
||||
return categories;
|
||||
}
|
||||
|
||||
public List<String> getNewCategories() {
|
||||
return newCategories;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter getFilter() {
|
||||
return new Filter() {
|
||||
|
||||
@Override
|
||||
protected FilterResults performFiltering(CharSequence constraint) {
|
||||
FilterResults results = new FilterResults();
|
||||
List<String> resultCategories = categoryClient.searchCategories(constraint.toString(), 10).blockingGet();
|
||||
results.values = resultCategories;
|
||||
results.count = resultCategories.size();
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void publishResults(CharSequence constraint, FilterResults results) {
|
||||
List<String> resultList = (List<String>)results.values;
|
||||
// Do not re-add already added categories
|
||||
for (String category : categories) {
|
||||
if (resultList.contains(category)) {
|
||||
resultList.remove(category);
|
||||
}
|
||||
}
|
||||
|
||||
displayedCategories = resultList;
|
||||
notifyDataSetChanged();
|
||||
if (displayedCategories.size()==0) {
|
||||
callback.noResultsFound();
|
||||
} else {
|
||||
callback.someResultsFound();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
|
||||
public CheckBox categoryCheckBox;
|
||||
public TextView categoryTextView;
|
||||
|
||||
public RecyclerViewHolder(View view) {
|
||||
super(view);
|
||||
categoryCheckBox = view.findViewById(R.id.category_checkbox);
|
||||
categoryTextView = view.findViewById(R.id.category_text);
|
||||
categoryCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
addToNewCategories(categoryTextView.getText().toString());
|
||||
} else {
|
||||
removeFromNewCategories(categoryTextView.getText().toString());
|
||||
}
|
||||
List<String> allCategories = new ArrayList<>();
|
||||
allCategories.addAll(categories);
|
||||
allCategories.addAll(newCategories);
|
||||
callback.updateSelectedCategoriesTextView(allCategories);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View itemView = inflater.inflate(R.layout.layout_edit_category_item , parent, false);
|
||||
return new RecyclerViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
|
||||
holder.categoryTextView.setText(displayedCategories.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return displayedCategories.get(position).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return (displayedCategories == null) ? 0 : displayedCategories.size();
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void updateSelectedCategoriesTextView(List<String> selectedCategories);
|
||||
void noResultsFound();
|
||||
void someResultsFound();
|
||||
}
|
||||
}
|
||||
|
|
@ -51,6 +51,7 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
|||
private Contribution contribution;
|
||||
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
private final MediaClient mediaClient;
|
||||
private boolean isWikipediaButtonDisplayed;
|
||||
|
||||
ContributionViewHolder(final View parent, final Callback callback,
|
||||
final MediaClient mediaClient) {
|
||||
|
|
@ -160,6 +161,7 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
|||
private void displayWikipediaButton(Boolean mediaExists) {
|
||||
if (!mediaExists) {
|
||||
addToWikipediaButton.setVisibility(View.VISIBLE);
|
||||
isWikipediaButtonDisplayed = true;
|
||||
cancelButton.setVisibility(View.GONE);
|
||||
retryButton.setVisibility(View.GONE);
|
||||
imageOptions.setVisibility(View.VISIBLE);
|
||||
|
|
@ -199,7 +201,7 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
@OnClick(R.id.contributionImage)
|
||||
public void imageClicked() {
|
||||
callback.openMediaDetail(position);
|
||||
callback.openMediaDetail(position, isWikipediaButtonDisplayed);
|
||||
}
|
||||
|
||||
@OnClick(R.id.wikipediaButton)
|
||||
|
|
|
|||
|
|
@ -482,12 +482,12 @@ public class ContributionsFragment
|
|||
* contribution.
|
||||
*/
|
||||
@Override
|
||||
public void showDetail(int position) {
|
||||
public void showDetail(int position, boolean isWikipediaButtonDisplayed) {
|
||||
if (mediaDetailPagerFragment == null || !mediaDetailPagerFragment.isVisible()) {
|
||||
mediaDetailPagerFragment = new MediaDetailPagerFragment();
|
||||
showMediaDetailPagerFragment();
|
||||
}
|
||||
mediaDetailPagerFragment.showImage(position);
|
||||
mediaDetailPagerFragment.showImage(position, isWikipediaButtonDisplayed);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import androidx.paging.PagedListAdapter;
|
|||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.media.MediaClient;
|
||||
import org.wikipedia.dataclient.WikiSite;
|
||||
|
||||
/**
|
||||
* Represents The View Adapter for the List of Contributions
|
||||
|
|
@ -75,7 +74,7 @@ public class ContributionsListAdapter extends
|
|||
|
||||
void deleteUpload(Contribution contribution);
|
||||
|
||||
void openMediaDetail(int contribution);
|
||||
void openMediaDetail(int contribution, boolean isWikipediaPageExists);
|
||||
|
||||
void addImageToWikipedia(Contribution contribution);
|
||||
|
||||
|
|
|
|||
|
|
@ -29,9 +29,8 @@ import fr.free.nrw.commons.Media;
|
|||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.media.MediaClient;
|
||||
import fr.free.nrw.commons.utils.DialogUtil;
|
||||
import fr.free.nrw.commons.wikidata.WikidataEditService;
|
||||
import fr.free.nrw.commons.media.MediaClient;
|
||||
import java.util.Locale;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
|
@ -244,9 +243,9 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
}
|
||||
|
||||
@Override
|
||||
public void openMediaDetail(final int position) {
|
||||
public void openMediaDetail(final int position, boolean isWikipediaButtonDisplayed) {
|
||||
if (null != callback) {//Just being safe, ideally they won't be called when detached
|
||||
callback.showDetail(position);
|
||||
callback.showDetail(position, isWikipediaButtonDisplayed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -334,8 +333,8 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
|
||||
void retryUpload(Contribution contribution);
|
||||
|
||||
void pauseUpload(Contribution contribution);
|
||||
void showDetail(int position, boolean isWikipediaButtonDisplayed);
|
||||
|
||||
void showDetail(int position);
|
||||
void pauseUpload(Contribution contribution);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package fr.free.nrw.commons.media;
|
|||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_NEEDING_CATEGORIES;
|
||||
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_PREFIX;
|
||||
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_UNCATEGORISED;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
|
|
@ -13,7 +15,9 @@ import android.graphics.drawable.Animatable;
|
|||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
@ -23,11 +27,15 @@ import android.widget.ArrayAdapter;
|
|||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.SearchView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
|
@ -38,6 +46,8 @@ import com.facebook.drawee.interfaces.DraweeController;
|
|||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.facebook.imagepipeline.image.ImageInfo;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.jakewharton.rxbinding2.view.RxView;
|
||||
import com.jakewharton.rxbinding2.widget.RxSearchView;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.MediaDataExtractor;
|
||||
import fr.free.nrw.commons.R;
|
||||
|
|
@ -45,13 +55,18 @@ import fr.free.nrw.commons.Utils;
|
|||
import fr.free.nrw.commons.auth.AccountUtil;
|
||||
import fr.free.nrw.commons.category.CategoryClient;
|
||||
import fr.free.nrw.commons.category.CategoryDetailsActivity;
|
||||
import fr.free.nrw.commons.category.CategoryEditHelper;
|
||||
import fr.free.nrw.commons.category.CategoryEditSearchRecyclerViewAdapter;
|
||||
import fr.free.nrw.commons.category.CategoryEditSearchRecyclerViewAdapter.Callback;
|
||||
import fr.free.nrw.commons.contributions.ContributionsFragment;
|
||||
import fr.free.nrw.commons.delete.DeleteHelper;
|
||||
import fr.free.nrw.commons.delete.ReasonBuilder;
|
||||
import fr.free.nrw.commons.explore.depictions.WikidataItemDetailsActivity;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.nearby.Label;
|
||||
import fr.free.nrw.commons.ui.widget.HtmlTextView;
|
||||
import fr.free.nrw.commons.utils.ViewUtilWrapper;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
|
@ -59,22 +74,25 @@ import java.util.ArrayList;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.wikipedia.util.DateUtil;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
||||
public class MediaDetailFragment extends CommonsDaggerSupportFragment implements Callback,
|
||||
CategoryEditHelper.Callback {
|
||||
|
||||
private boolean editable;
|
||||
private boolean isCategoryImage;
|
||||
private MediaDetailPagerFragment.MediaDetailProvider detailProvider;
|
||||
private int index;
|
||||
private boolean isDeleted = false;
|
||||
private boolean isWikipediaButtonDisplayed;
|
||||
|
||||
|
||||
public static MediaDetailFragment forMedia(int index, boolean editable, boolean isCategoryImage) {
|
||||
public static MediaDetailFragment forMedia(int index, boolean editable, boolean isCategoryImage, boolean isWikipediaButtonDisplayed) {
|
||||
MediaDetailFragment mf = new MediaDetailFragment();
|
||||
|
||||
Bundle state = new Bundle();
|
||||
|
|
@ -83,6 +101,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
state.putInt("index", index);
|
||||
state.putInt("listIndex", 0);
|
||||
state.putInt("listTop", 0);
|
||||
state.putBoolean("isWikipediaButtonDisplayed", isWikipediaButtonDisplayed);
|
||||
|
||||
mf.setArguments(state);
|
||||
|
||||
|
|
@ -96,7 +115,11 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
@Inject
|
||||
DeleteHelper deleteHelper;
|
||||
@Inject
|
||||
CategoryEditHelper categoryEditHelper;
|
||||
@Inject
|
||||
ViewUtilWrapper viewUtil;
|
||||
@Inject
|
||||
CategoryClient categoryClient;
|
||||
|
||||
private int initialListTop = 0;
|
||||
|
||||
|
|
@ -132,6 +155,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
LinearLayout nominatedForDeletion;
|
||||
@BindView(R.id.mediaDetailCategoryContainer)
|
||||
LinearLayout categoryContainer;
|
||||
@BindView(R.id.categoryEditButton)
|
||||
Button categoryEditButton;
|
||||
@BindView(R.id.media_detail_depiction_container)
|
||||
LinearLayout depictionContainer;
|
||||
@BindView(R.id.authorLinearLayout)
|
||||
|
|
@ -140,6 +165,29 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
Button delete;
|
||||
@BindView(R.id.mediaDetailScrollView)
|
||||
ScrollView scrollView;
|
||||
@BindView(R.id.toDoLayout)
|
||||
LinearLayout toDoLayout;
|
||||
@BindView(R.id.toDoReason)
|
||||
TextView toDoReason;
|
||||
@BindView(R.id.category_edit_layout)
|
||||
LinearLayout categoryEditLayout;
|
||||
@BindView(R.id.et_search)
|
||||
SearchView categorySearchView;
|
||||
@BindView(R.id.rv_categories)
|
||||
RecyclerView categoryRecyclerView;
|
||||
@BindView(R.id.update_categories_button)
|
||||
Button updateCategoriesButton;
|
||||
@BindView(R.id.dummy_category_edit_container)
|
||||
LinearLayout dummyCategoryEditContainer;
|
||||
@BindView(R.id.pb_categories)
|
||||
ProgressBar progressbarCategories;
|
||||
@BindView(R.id.existing_categories)
|
||||
TextView existingCategories;
|
||||
@BindView(R.id.no_results_found)
|
||||
TextView noResultsFound;
|
||||
|
||||
private ArrayList<String> categoryNames = new ArrayList<>();
|
||||
private String categorySearchQuery;
|
||||
|
||||
/**
|
||||
* Depicts is a feature part of Structured data. Multiple Depictions can be added for an image just like categories.
|
||||
|
|
@ -151,6 +199,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
private int newWidthOfImageView;
|
||||
private boolean heightVerifyingBoolean = true; // helps in maintaining aspect ratio
|
||||
private ViewTreeObserver.OnGlobalLayoutListener layoutListener; // for layout stuff, only used once!
|
||||
private CategoryEditSearchRecyclerViewAdapter categoryEditSearchRecyclerViewAdapter;
|
||||
|
||||
//Had to make this class variable, to implement various onClicks, which access the media, also I fell why make separate variables when one can serve the purpose
|
||||
private Media media;
|
||||
|
|
@ -163,6 +212,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
outState.putInt("index", index);
|
||||
outState.putBoolean("editable", editable);
|
||||
outState.putBoolean("isCategoryImage", isCategoryImage);
|
||||
outState.putBoolean("isWikipediaButtonDisplayed", isWikipediaButtonDisplayed);
|
||||
|
||||
getScrollPosition();
|
||||
outState.putInt("listTop", initialListTop);
|
||||
|
|
@ -182,11 +232,13 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
if (savedInstanceState != null) {
|
||||
editable = savedInstanceState.getBoolean("editable");
|
||||
isCategoryImage = savedInstanceState.getBoolean("isCategoryImage");
|
||||
isWikipediaButtonDisplayed = savedInstanceState.getBoolean("isWikipediaButtonDisplayed");
|
||||
index = savedInstanceState.getInt("index");
|
||||
initialListTop = savedInstanceState.getInt("listTop");
|
||||
} else {
|
||||
editable = getArguments().getBoolean("editable");
|
||||
isCategoryImage = getArguments().getBoolean("isCategoryImage");
|
||||
isWikipediaButtonDisplayed = getArguments().getBoolean("isWikipediaButtonDisplayed");
|
||||
index = getArguments().getInt("index");
|
||||
initialListTop = 0;
|
||||
}
|
||||
|
|
@ -232,6 +284,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
.getParentFragment())).nearbyNotificationCardView
|
||||
.setVisibility(View.GONE);
|
||||
}
|
||||
categoryEditSearchRecyclerViewAdapter =
|
||||
new CategoryEditSearchRecyclerViewAdapter(getContext(), new ArrayList<>(
|
||||
Label.valuesAsList()), categoryRecyclerView, categoryClient, this);
|
||||
categoryRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
categoryRecyclerView.setAdapter(categoryEditSearchRecyclerViewAdapter);
|
||||
|
||||
media = detailProvider.getMediaAtPosition(index);
|
||||
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(
|
||||
new OnGlobalLayoutListener() {
|
||||
|
|
@ -311,6 +369,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::onDepictionsLoaded, Timber::e)
|
||||
);
|
||||
// compositeDisposable.add(disposable);
|
||||
setupToDo();
|
||||
}
|
||||
|
||||
private void onDiscussionLoaded(String discussion) {
|
||||
|
|
@ -385,6 +445,63 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
imageLandscape.setController(controllerLandscape);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays layout about missing actions to inform user
|
||||
* - Images that they uploaded with no categories/descriptions, so that they can add them
|
||||
* - Images that can be added to associated Wikipedia articles that have no pictures
|
||||
*/
|
||||
private void setupToDo() {
|
||||
updateToDoWarning();
|
||||
compositeDisposable.add(RxSearchView.queryTextChanges(categorySearchView)
|
||||
.takeUntil(RxView.detaches(categorySearchView))
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(query -> {
|
||||
this.categorySearchQuery = query.toString();
|
||||
//update image list
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
if (categoryEditLayout.getVisibility() == VISIBLE) {
|
||||
((CategoryEditSearchRecyclerViewAdapter) categoryRecyclerView.getAdapter()).
|
||||
getFilter().filter(query.toString());
|
||||
}
|
||||
}
|
||||
}, Timber::e
|
||||
));
|
||||
}
|
||||
|
||||
private void updateToDoWarning() {
|
||||
String toDoMessage = "";
|
||||
boolean toDoNeeded = false;
|
||||
boolean categoriesPresent = media.getCategories() == null ? false : (media.getCategories().size() == 0 ? false : true);
|
||||
|
||||
// Check if the presented category is about need of category
|
||||
if (categoriesPresent) {
|
||||
for (String category : media.getCategories()) {
|
||||
if (category.toLowerCase().contains(CATEGORY_NEEDING_CATEGORIES) ||
|
||||
category.toLowerCase().contains(CATEGORY_UNCATEGORISED)) {
|
||||
categoriesPresent = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!categoriesPresent) {
|
||||
toDoNeeded = true;
|
||||
toDoMessage += getString(R.string.missing_category);
|
||||
}
|
||||
if (isWikipediaButtonDisplayed) {
|
||||
toDoNeeded = true;
|
||||
toDoMessage += (toDoMessage.isEmpty()) ? "" : "\n" + getString(R.string.missing_article);
|
||||
}
|
||||
|
||||
if (toDoNeeded) {
|
||||
toDoMessage = getString(R.string.todo_improve) + "\n" + toDoMessage;
|
||||
toDoLayout.setVisibility(VISIBLE);
|
||||
toDoReason.setText(toDoMessage);
|
||||
} else {
|
||||
toDoLayout.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
if (layoutListener != null && getView() != null) {
|
||||
|
|
@ -409,15 +526,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
mediaCaption.setText(prettyCaption(media));
|
||||
}
|
||||
|
||||
final List<String> categories = media.getCategories();
|
||||
if (categories.isEmpty()) {
|
||||
// Stick in a filler element.
|
||||
categories.add(getString(R.string.detail_panel_cats_none));
|
||||
}
|
||||
|
||||
rebuildCatList(categories);
|
||||
|
||||
categoryNames.clear();
|
||||
categoryNames.addAll(media.getCategories());
|
||||
categoryEditSearchRecyclerViewAdapter.addToCategories(media.getCategories());
|
||||
updateSelectedCategoriesTextView(categoryEditSearchRecyclerViewAdapter.getCategories());
|
||||
|
||||
updateCategoryList();
|
||||
|
||||
if (media.getCreator() == null || media.getCreator().equals("")) {
|
||||
authorLayout.setVisibility(GONE);
|
||||
|
|
@ -426,6 +540,49 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
}
|
||||
}
|
||||
|
||||
private void updateCategoryList() {
|
||||
List<String> allCategories = new ArrayList<String>( media.getCategories());
|
||||
if (media.getAddedCategories() != null) {
|
||||
// TODO this added categories logic should be removed.
|
||||
// It is just a short term hack. Categories should be fetch everytime they are updated.
|
||||
// if media.getCategories contains addedCategory, then do not re-add them
|
||||
for (String addedCategory : media.getAddedCategories()) {
|
||||
if (allCategories.contains(addedCategory)) {
|
||||
media.setAddedCategories(null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
allCategories.addAll(media.getAddedCategories());
|
||||
}
|
||||
if (allCategories.isEmpty()) {
|
||||
// Stick in a filler element.
|
||||
allCategories.add(getString(R.string.detail_panel_cats_none));
|
||||
}
|
||||
|
||||
rebuildCatList(allCategories);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSelectedCategoriesTextView(List<String> selectedCategories) {
|
||||
if (selectedCategories == null || selectedCategories.size() == 0) {
|
||||
updateCategoriesButton.setClickable(false);
|
||||
}
|
||||
if (selectedCategories != null) {
|
||||
existingCategories.setText(StringUtils.join(selectedCategories,", "));
|
||||
updateCategoriesButton.setClickable(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noResultsFound() {
|
||||
noResultsFound.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void someResultsFound() {
|
||||
noResultsFound.setVisibility(GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates media details fragment with depiction list
|
||||
* @param idAndCaptions
|
||||
|
|
@ -467,6 +624,50 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
Toast.makeText(getContext(), getString(R.string.wikicode_copied), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@OnClick(R.id.dummy_category_edit_container)
|
||||
public void onOutsideOfCategoryEditClicked() {
|
||||
if (dummyCategoryEditContainer.getVisibility() == VISIBLE) {
|
||||
dummyCategoryEditContainer.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.categoryEditButton)
|
||||
public void onCategoryEditButtonClicked(){
|
||||
displayHideCategorySearch();
|
||||
}
|
||||
|
||||
public void displayHideCategorySearch() {
|
||||
if (dummyCategoryEditContainer.getVisibility() != VISIBLE) {
|
||||
dummyCategoryEditContainer.setVisibility(VISIBLE);
|
||||
} else {
|
||||
dummyCategoryEditContainer.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.update_categories_button)
|
||||
public void onUpdateCategoriesClicked() {
|
||||
updateCategories(categoryEditSearchRecyclerViewAdapter.getNewCategories());
|
||||
displayHideCategorySearch();
|
||||
}
|
||||
|
||||
@OnClick(R.id.cancel_categories_button)
|
||||
public void onCancelCategoriesClicked() {
|
||||
displayHideCategorySearch();
|
||||
}
|
||||
|
||||
public void updateCategories(List<String> selectedCategories) {
|
||||
compositeDisposable.add(categoryEditHelper.makeCategoryEdit(getContext(), media, selectedCategories, this)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(s -> {
|
||||
Timber.d("Categories are added.");
|
||||
onOutsideOfCategoryEditClicked();
|
||||
media.setAddedCategories(selectedCategories);
|
||||
updateCategoryList();
|
||||
}));
|
||||
}
|
||||
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
@OnClick(R.id.nominateDeletion)
|
||||
public void onDeleteButtonClicked(){
|
||||
if (AccountUtil.getUserName(getContext()) != null && AccountUtil.getUserName(getContext()).equals(media.getCreator())) {
|
||||
|
|
@ -537,7 +738,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void onDeleteClicked(Spinner spinner) {
|
||||
String reason = spinner.getSelectedItem().toString();
|
||||
|
|
@ -588,6 +788,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
}
|
||||
|
||||
private void rebuildCatList(List<String> categories) {
|
||||
Log.d("deneme","rebuild cat list size:"+categories.size());
|
||||
categoryContainer.removeAllViews();
|
||||
for (String category : categories) {
|
||||
categoryContainer.addView(buildCatLabel(sanitise(category), categoryContainer));
|
||||
|
|
@ -706,4 +907,13 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
return media.getCoordinates().getPrettyCoordinateString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateCategoryDisplay(List<String> categories) {
|
||||
if (categories == null) {
|
||||
return false;
|
||||
} else {
|
||||
rebuildCatList(categories);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
@BindView(R.id.mediaDetailsPager) ViewPager pager;
|
||||
private Boolean editable;
|
||||
private boolean isFeaturedImage;
|
||||
private boolean isWikipediaButtonDisplayed;
|
||||
MediaDetailAdapter adapter;
|
||||
private Bookmark bookmark;
|
||||
private MediaDetailProvider provider;
|
||||
|
|
@ -249,6 +250,12 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
item.setIcon(icon);
|
||||
}
|
||||
|
||||
public void showImage(int i, boolean isWikipediaButtonDisplayed) {
|
||||
this.isWikipediaButtonDisplayed = isWikipediaButtonDisplayed;
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(() -> pager.setCurrentItem(i), 5);
|
||||
}
|
||||
|
||||
public void showImage(int i) {
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(() -> pager.setCurrentItem(i), 5);
|
||||
|
|
@ -310,7 +317,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
}
|
||||
pager.postDelayed(() -> getActivity().invalidateOptionsMenu(), 5);
|
||||
}
|
||||
return MediaDetailFragment.forMedia(i, editable, isFeaturedImage);
|
||||
return MediaDetailFragment.forMedia(i, editable, isFeaturedImage, isWikipediaButtonDisplayed);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import static androidx.core.app.NotificationCompat.PRIORITY_HIGH;
|
|||
public class NotificationHelper {
|
||||
|
||||
public static final int NOTIFICATION_DELETE = 1;
|
||||
public static final int NOTIFICATION_EDIT_CATEGORY = 2;
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder notificationBuilder;
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@ 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 fr.free.nrw.commons.media.MediaClient;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
|
@ -43,7 +43,8 @@ public class PicOfDayAppWidget extends AppWidgetProvider {
|
|||
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
@Inject MediaClient mediaClient;
|
||||
@Inject
|
||||
MediaClient mediaClient;
|
||||
|
||||
void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.pic_of_day_app_widget);
|
||||
|
|
|
|||
10
app/src/main/res/drawable/ic_baseline_edit_24.xml
Normal file
10
app/src/main/res/drawable/ic_baseline_edit_24.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||
</vector>
|
||||
|
|
@ -8,6 +8,20 @@
|
|||
android:background="?attr/mainBackground"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/dummy_category_edit_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:elevation="35dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:visibility="gone"
|
||||
android:orientation="vertical"
|
||||
android:weightSum="10">
|
||||
|
||||
<include
|
||||
layout="@layout/layout_edit_categories" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/mediaDetailImageFailed"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -53,9 +67,12 @@
|
|||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_250"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/mediaDetailImageViewSpacer" />
|
||||
android:id="@+id/mediaDetailImageViewSpacer"
|
||||
>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
|
@ -88,6 +105,30 @@
|
|||
tools:text="Title of the media" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/toDoLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
android:background="@color/layout_light_grey"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/MediaDetailTextLabel"
|
||||
android:text="@string/warning" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/toDoReason"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/activity_margin_vertical"
|
||||
style="@style/MediaDetailTextBody" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
style="@style/MediaDetailContainer"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -255,9 +296,19 @@
|
|||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="70"
|
||||
android:orientation="vertical" />
|
||||
android:orientation="vertical">
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/categoryEditButton"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_margin="@dimen/standard_gap"
|
||||
android:layout_gravity="end"
|
||||
android:background="@drawable/ic_baseline_edit_24" />
|
||||
|
||||
<LinearLayout
|
||||
style="@style/MediaDetailContainer"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
114
app/src/main/res/layout/layout_edit_categories.xml
Normal file
114
app/src/main/res/layout/layout_edit_categories.xml
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
|
||||
android:id="@+id/category_edit_layout"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="15dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/white"
|
||||
android:elevation="30dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/half_standard_height"
|
||||
android:layout_margin="@dimen/quarter_standard_height"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Type categories"
|
||||
android:textSize="@dimen/subtitle_text"
|
||||
android:visibility="visible" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/category_search_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/standard_gap"
|
||||
>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/til_container_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<SearchView
|
||||
android:id="@+id/et_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/categories_search_text_hint"
|
||||
android:imeOptions="actionSearch"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pb_categories"
|
||||
style="?android:progressBarStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/tiny_gap"
|
||||
android:layout_marginRight="@dimen/tiny_gap"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:indeterminate="true"
|
||||
android:indeterminateOnly="true"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/existing_categories"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/quarter_standard_height"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="@dimen/subtitle_text"
|
||||
android:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/no_results_found"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/quarter_standard_height"
|
||||
android:gravity="center_vertical"
|
||||
android:text="No results found"
|
||||
android:textSize="@dimen/description_text_size"
|
||||
android:visibility="gone" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:weightSum="6"
|
||||
>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_categories"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="4"
|
||||
android:background="@color/white"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="2">
|
||||
<Button
|
||||
android:id="@+id/cancel_categories_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_margin="@dimen/quarter_standard_height"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/cancel"
|
||||
android:padding="@dimen/small_gap"
|
||||
android:textColor="@color/white"
|
||||
android:background="@color/opak_middle_grey"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/update_categories_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_margin="@dimen/quarter_standard_height"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/category_edit_button_text"
|
||||
android:padding="@dimen/small_gap"
|
||||
android:textColor="@color/white"
|
||||
android:background="@color/button_blue"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
27
app/src/main/res/layout/layout_edit_category_item.xml
Normal file
27
app/src/main/res/layout/layout_edit_category_item.xml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/category_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/category_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checkMark="?android:attr/textCheckMark"
|
||||
android:checked="false"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="@dimen/tiny_gap"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/category_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Category"
|
||||
app:layout_constraintLeft_toRightOf="@+id/category_checkbox"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -598,6 +598,17 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="delete_helper_ask_reason_copyright_logo">Logo</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Other</string>
|
||||
<string name="delete_helper_ask_alert_set_positive_button_reason">Because it is</string>
|
||||
|
||||
<string name="category_edit_helper_make_edit_toast">Trying to update categories.</string>
|
||||
<string name="category_edit_helper_show_edit_title">Category update</string>
|
||||
<string name="category_edit_helper_show_edit_title_success">Success</string>
|
||||
<plurals name="category_edit_helper_show_edit_message_if">
|
||||
<item quantity="one">Category %1$s is added.</item>
|
||||
<item quantity="other">Categories %1$s are added.</item>
|
||||
</plurals>
|
||||
<string name="category_edit_helper_edit_message_else">Could not add categories.</string>
|
||||
<string name="category_edit_button_text">Update categories</string>
|
||||
|
||||
<string name="share_image_via">Share image via</string>
|
||||
<string name="no_achievements_yet">You haven\'t made any contributions yet</string>
|
||||
<string name="account_created">Account created!</string>
|
||||
|
|
@ -636,6 +647,10 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="load_more">Load More</string>
|
||||
<string name="nearby_no_results">No places found, try changing your search criteria.</string>
|
||||
|
||||
<string name="todo_improve">Suggested improvements:</string>
|
||||
<string name="missing_category">- Add categories to this image to improve usability.</string>
|
||||
<string name="missing_article">- Add this image to the associated Wikipedia article that has no images.</string>
|
||||
<string name="edit_category">Edit categories</string>
|
||||
<string name="add_picture_to_wikipedia_article_title">Add image to Wikipedia</string>
|
||||
<string name="add_picture_to_wikipedia_article_desc">Do you want to add this picture to the %1$s language Wikipedia article?</string>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@ package fr.free.nrw.commons.actions
|
|||
|
||||
import com.nhaarman.mockitokotlin2.eq
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import io.reactivex.Observable
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.wikipedia.csrf.CsrfTokenClient
|
||||
import org.wikipedia.dataclient.Service
|
||||
import org.wikipedia.edit.Edit
|
||||
|
||||
class PageEditClientTest {
|
||||
@Mock
|
||||
|
|
@ -20,6 +23,12 @@ class PageEditClientTest {
|
|||
|
||||
private lateinit var pageEditClient: PageEditClient
|
||||
|
||||
@Mock
|
||||
lateinit var edit: Edit
|
||||
|
||||
@Mock
|
||||
lateinit var editResult: Edit.Result
|
||||
|
||||
/**
|
||||
* initial setup, test environment
|
||||
*/
|
||||
|
|
@ -46,8 +55,23 @@ class PageEditClientTest {
|
|||
@Test
|
||||
fun testAppendEdit() {
|
||||
Mockito.`when`(csrfTokenClient.tokenBlocking).thenReturn("test")
|
||||
pageEditClient.appendEdit("test", "test", "test")
|
||||
Mockito.`when`(
|
||||
pageEditInterface.postAppendEdit(
|
||||
ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.anyString()
|
||||
)
|
||||
).thenReturn(
|
||||
Observable.just(edit)
|
||||
)
|
||||
Mockito.`when`(edit.edit()).thenReturn(editResult)
|
||||
Mockito.`when`(editResult.editSucceeded()).thenReturn(true)
|
||||
pageEditClient.appendEdit("test", "test", "test").test()
|
||||
verify(csrfTokenClient).tokenBlocking
|
||||
verify(pageEditInterface).postAppendEdit(eq("test"), eq("test"), eq("test"), eq("test"))
|
||||
verify(edit).edit()
|
||||
verify(editResult).editSucceeded()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue