Skip to content

Commit 1856196

Browse files
Todo for user (commons-app#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
1 parent f5e2883 commit 1856196

20 files changed

+799
-36
lines changed

.idea/codeStyles/Project.xml

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/src/main/java/fr/free/nrw/commons/Media.kt

+10
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,14 @@ class Media constructor(
121121
get() = captions[Locale.getDefault().language]
122122
?: captions.values.firstOrNull()
123123
?: displayTitle
124+
125+
/**
126+
* Gets the categories the file falls under.
127+
* @return file categories as an ArrayList of Strings
128+
*/
129+
var addedCategories: List<String>? = null
130+
// TODO added categories should be removed. It is added for a short fix. On category update,
131+
// categories should be re-fetched instead
132+
get() = field // getter
133+
set(value) { field = value } // setter
124134
}

app/src/main/java/fr/free/nrw/commons/actions/PageEditClient.java

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package fr.free.nrw.commons.actions;
22

3+
import io.reactivex.Single;
4+
import io.reactivex.SingleOnSubscribe;
35
import org.wikipedia.csrf.CsrfTokenClient;
46
import org.wikipedia.dataclient.Service;
57

@@ -48,12 +50,16 @@ public Observable<Boolean> edit(String pageTitle, String text, String summary) {
4850
* @param summary Edit summary
4951
*/
5052
public Observable<Boolean> appendEdit(String pageTitle, String appendText, String summary) {
51-
try {
52-
return pageEditInterface.postAppendEdit(pageTitle, summary, appendText, csrfTokenClient.getTokenBlocking())
53-
.map(editResponse -> editResponse.edit().editSucceeded());
54-
} catch (Throwable throwable) {
55-
return Observable.just(false);
56-
}
53+
return Single.create((SingleOnSubscribe<String>) emitter -> {
54+
try {
55+
emitter.onSuccess(csrfTokenClient.getTokenBlocking());
56+
} catch (Throwable throwable) {
57+
emitter.onError(throwable);
58+
throwable.printStackTrace();
59+
}
60+
}).flatMapObservable(token -> pageEditInterface.postAppendEdit(pageTitle, summary, appendText, token)
61+
.map(editResponse -> editResponse.edit().editSucceeded()));
62+
5763
}
5864

5965
/**

app/src/main/java/fr/free/nrw/commons/category/CategoryClient.kt

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import javax.inject.Singleton
88
const val CATEGORY_PREFIX = "Category:"
99
const val SUB_CATEGORY_CONTINUATION_PREFIX = "sub_category_"
1010
const val PARENT_CATEGORY_CONTINUATION_PREFIX = "parent_category_"
11+
const val CATEGORY_UNCATEGORISED = "uncategorised"
12+
const val CATEGORY_NEEDING_CATEGORIES = "needing categories"
1113

1214
/**
1315
* Category Client to handle custom calls to Commons MediaWiki APIs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package fr.free.nrw.commons.category;
2+
3+
import static fr.free.nrw.commons.notification.NotificationHelper.NOTIFICATION_EDIT_CATEGORY;
4+
5+
import android.content.Context;
6+
import android.content.Intent;
7+
import android.net.Uri;
8+
import android.util.Log;
9+
import fr.free.nrw.commons.BuildConfig;
10+
import fr.free.nrw.commons.Media;
11+
import fr.free.nrw.commons.R;
12+
import fr.free.nrw.commons.actions.PageEditClient;
13+
import fr.free.nrw.commons.notification.NotificationHelper;
14+
import fr.free.nrw.commons.utils.ViewUtilWrapper;
15+
import io.reactivex.Observable;
16+
import io.reactivex.Single;
17+
import java.util.List;
18+
import javax.inject.Inject;
19+
import javax.inject.Named;
20+
import timber.log.Timber;
21+
22+
public class CategoryEditHelper {
23+
private final NotificationHelper notificationHelper;
24+
public final PageEditClient pageEditClient;
25+
private final ViewUtilWrapper viewUtil;
26+
private final String username;
27+
private Callback callback;
28+
29+
@Inject
30+
public CategoryEditHelper(NotificationHelper notificationHelper,
31+
@Named("commons-page-edit") PageEditClient pageEditClient,
32+
ViewUtilWrapper viewUtil,
33+
@Named("username") String username) {
34+
this.notificationHelper = notificationHelper;
35+
this.pageEditClient = pageEditClient;
36+
this.viewUtil = viewUtil;
37+
this.username = username;
38+
}
39+
40+
/**
41+
* Public interface to edit categories
42+
* @param context
43+
* @param media
44+
* @param categories
45+
* @return
46+
*/
47+
public Single<Boolean> makeCategoryEdit(Context context, Media media, List<String> categories, Callback callback) {
48+
viewUtil.showShortToast(context, context.getString(R.string.category_edit_helper_make_edit_toast));
49+
return addCategory(media, categories)
50+
.flatMapSingle(result -> Single.just(showCategoryEditNotification(context, media, result)))
51+
.firstOrError();
52+
}
53+
54+
/**
55+
* Appends new categories
56+
* @param media
57+
* @param categories to be added
58+
* @return
59+
*/
60+
private Observable<Boolean> addCategory(Media media, List<String> categories) {
61+
Timber.d("thread is category adding %s", Thread.currentThread().getName());
62+
String summary = "Adding categories";
63+
64+
StringBuilder buffer = new StringBuilder();
65+
66+
if (categories != null && categories.size() != 0) {
67+
68+
for (int i = 0; i < categories.size(); i++) {
69+
buffer.append("\n[[Category:").append(categories.get(i)).append("]]");
70+
}
71+
} else {
72+
buffer.append("{{subst:unc}}");
73+
}
74+
String appendText = buffer.toString();
75+
return pageEditClient.appendEdit(media.getFilename(), appendText + "\n", summary);
76+
}
77+
78+
private boolean showCategoryEditNotification(Context context, Media media, boolean result) {
79+
String message;
80+
String title = context.getString(R.string.category_edit_helper_show_edit_title);
81+
82+
if (result) {
83+
title += ": " + context.getString(R.string.category_edit_helper_show_edit_title_success);
84+
StringBuilder categoriesInMessage = new StringBuilder();
85+
List<String> mediaCategoryList = media.getCategories();
86+
for (String category : mediaCategoryList) {
87+
categoriesInMessage.append(category);
88+
if (category.equals(mediaCategoryList.get(mediaCategoryList.size()-1))) {
89+
continue;
90+
}
91+
categoriesInMessage.append(",");
92+
}
93+
94+
message = context.getResources().getQuantityString(R.plurals.category_edit_helper_show_edit_message_if, mediaCategoryList.size(), categoriesInMessage.toString());
95+
} else {
96+
title += ": " + context.getString(R.string.category_edit_helper_show_edit_title);
97+
message = context.getString(R.string.category_edit_helper_edit_message_else) ;
98+
}
99+
100+
String urlForFile = BuildConfig.COMMONS_URL + "/wiki/" + media.getFilename();
101+
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlForFile));
102+
notificationHelper.showNotification(context, title, message, NOTIFICATION_EDIT_CATEGORY, browserIntent);
103+
return result;
104+
}
105+
106+
public interface Callback {
107+
boolean updateCategoryDisplay(List<String> categories);
108+
}
109+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package fr.free.nrw.commons.category;
2+
3+
import android.content.Context;
4+
import android.view.LayoutInflater;
5+
import android.view.View;
6+
import android.view.ViewGroup;
7+
import android.widget.CheckBox;
8+
import android.widget.CompoundButton;
9+
import android.widget.CompoundButton.OnCheckedChangeListener;
10+
import android.widget.Filter;
11+
import android.widget.Filterable;
12+
import android.widget.TextView;
13+
import androidx.annotation.NonNull;
14+
import androidx.recyclerview.widget.RecyclerView;
15+
import fr.free.nrw.commons.R;
16+
import fr.free.nrw.commons.category.CategoryEditSearchRecyclerViewAdapter.RecyclerViewHolder;
17+
import fr.free.nrw.commons.nearby.Label;
18+
import java.util.ArrayList;
19+
import java.util.List;
20+
21+
public class CategoryEditSearchRecyclerViewAdapter
22+
extends RecyclerView.Adapter<RecyclerViewHolder>
23+
implements Filterable {
24+
25+
private List<String> displayedCategories;
26+
private List<String> categories = new ArrayList<>();
27+
private List<String> newCategories = new ArrayList<>();
28+
private final LayoutInflater inflater;
29+
private CategoryClient categoryClient;
30+
private Context context;
31+
32+
private Callback callback;
33+
34+
public CategoryEditSearchRecyclerViewAdapter(Context context, ArrayList<Label> labels,
35+
RecyclerView categoryRecyclerView, CategoryClient categoryClient, Callback callback) {
36+
this.context = context;
37+
inflater = LayoutInflater.from(context);
38+
this.categoryClient = categoryClient;
39+
this.callback = callback;
40+
}
41+
42+
public void addToCategories(List<String> categories) {
43+
for(String category : categories) {
44+
if (!this.categories.contains(category)) {
45+
this.categories.add(category);
46+
}
47+
}
48+
}
49+
50+
public void addToCategories(String categoryToBeAdded) {
51+
if (!categories.contains(categoryToBeAdded)) {
52+
categories.add(categoryToBeAdded);
53+
}
54+
}
55+
56+
public void removeFromCategories(String categoryToBeRemoved) {
57+
if (categories.contains(categoryToBeRemoved)) {
58+
categories.remove(categoryToBeRemoved);
59+
}
60+
}
61+
62+
public void removeFromNewCategories(String categoryToBeRemoved) {
63+
if (newCategories.contains(categoryToBeRemoved)) {
64+
newCategories.remove(categoryToBeRemoved);
65+
}
66+
}
67+
68+
public void addToNewCategories(List<String> newCategories) {
69+
for(String category : newCategories) {
70+
if (!this.newCategories.contains(category)) {
71+
this.newCategories.add(category);
72+
}
73+
}
74+
}
75+
76+
public void addToNewCategories(String addedCategory) {
77+
if (!newCategories.contains(addedCategory)) {
78+
newCategories.add(addedCategory);
79+
}
80+
}
81+
82+
public List<String> getCategories() {
83+
return categories;
84+
}
85+
86+
public List<String> getNewCategories() {
87+
return newCategories;
88+
}
89+
90+
@Override
91+
public Filter getFilter() {
92+
return new Filter() {
93+
94+
@Override
95+
protected FilterResults performFiltering(CharSequence constraint) {
96+
FilterResults results = new FilterResults();
97+
List<String> resultCategories = categoryClient.searchCategories(constraint.toString(), 10).blockingGet();
98+
results.values = resultCategories;
99+
results.count = resultCategories.size();
100+
return results;
101+
}
102+
103+
@Override
104+
protected void publishResults(CharSequence constraint, FilterResults results) {
105+
List<String> resultList = (List<String>)results.values;
106+
// Do not re-add already added categories
107+
for (String category : categories) {
108+
if (resultList.contains(category)) {
109+
resultList.remove(category);
110+
}
111+
}
112+
113+
displayedCategories = resultList;
114+
notifyDataSetChanged();
115+
if (displayedCategories.size()==0) {
116+
callback.noResultsFound();
117+
} else {
118+
callback.someResultsFound();
119+
}
120+
}
121+
};
122+
}
123+
124+
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
125+
public CheckBox categoryCheckBox;
126+
public TextView categoryTextView;
127+
128+
public RecyclerViewHolder(View view) {
129+
super(view);
130+
categoryCheckBox = view.findViewById(R.id.category_checkbox);
131+
categoryTextView = view.findViewById(R.id.category_text);
132+
categoryCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
133+
@Override
134+
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
135+
if (isChecked) {
136+
addToNewCategories(categoryTextView.getText().toString());
137+
} else {
138+
removeFromNewCategories(categoryTextView.getText().toString());
139+
}
140+
List<String> allCategories = new ArrayList<>();
141+
allCategories.addAll(categories);
142+
allCategories.addAll(newCategories);
143+
callback.updateSelectedCategoriesTextView(allCategories);
144+
}
145+
});
146+
}
147+
}
148+
149+
@NonNull
150+
@Override
151+
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
152+
View itemView = inflater.inflate(R.layout.layout_edit_category_item , parent, false);
153+
return new RecyclerViewHolder(itemView);
154+
}
155+
156+
@Override
157+
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
158+
holder.categoryTextView.setText(displayedCategories.get(position));
159+
}
160+
161+
@Override
162+
public long getItemId(int position) {
163+
return displayedCategories.get(position).hashCode();
164+
}
165+
166+
@Override
167+
public int getItemCount() {
168+
return (displayedCategories == null) ? 0 : displayedCategories.size();
169+
}
170+
171+
public interface Callback {
172+
void updateSelectedCategoriesTextView(List<String> selectedCategories);
173+
void noResultsFound();
174+
void someResultsFound();
175+
}
176+
}

app/src/main/java/fr/free/nrw/commons/contributions/ContributionViewHolder.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
5151
private Contribution contribution;
5252
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
5353
private final MediaClient mediaClient;
54+
private boolean isWikipediaButtonDisplayed;
5455

5556
ContributionViewHolder(final View parent, final Callback callback,
5657
final MediaClient mediaClient) {
@@ -160,6 +161,7 @@ private void checkIfMediaExistsOnWikipediaPage(final Contribution contribution)
160161
private void displayWikipediaButton(Boolean mediaExists) {
161162
if (!mediaExists) {
162163
addToWikipediaButton.setVisibility(View.VISIBLE);
164+
isWikipediaButtonDisplayed = true;
163165
cancelButton.setVisibility(View.GONE);
164166
retryButton.setVisibility(View.GONE);
165167
imageOptions.setVisibility(View.VISIBLE);
@@ -199,7 +201,7 @@ public void deleteUpload() {
199201

200202
@OnClick(R.id.contributionImage)
201203
public void imageClicked() {
202-
callback.openMediaDetail(position);
204+
callback.openMediaDetail(position, isWikipediaButtonDisplayed);
203205
}
204206

205207
@OnClick(R.id.wikipediaButton)

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -482,12 +482,12 @@ public void pauseUpload(Contribution contribution) {
482482
* contribution.
483483
*/
484484
@Override
485-
public void showDetail(int position) {
485+
public void showDetail(int position, boolean isWikipediaButtonDisplayed) {
486486
if (mediaDetailPagerFragment == null || !mediaDetailPagerFragment.isVisible()) {
487487
mediaDetailPagerFragment = new MediaDetailPagerFragment();
488488
showMediaDetailPagerFragment();
489489
}
490-
mediaDetailPagerFragment.showImage(position);
490+
mediaDetailPagerFragment.showImage(position, isWikipediaButtonDisplayed);
491491
}
492492

493493
@Override

0 commit comments

Comments
 (0)