mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Use JSON APIs for peer review (#2714)
This commit is contained in:
parent
ce3349385f
commit
7cb1f56165
14 changed files with 203 additions and 138 deletions
|
|
@ -1,22 +1,22 @@
|
||||||
package fr.free.nrw.commons.media;
|
package fr.free.nrw.commons.media;
|
||||||
|
|
||||||
import org.w3c.dom.Element;
|
import java.util.List;
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.mwapi.model.RecentChange;
|
||||||
|
|
||||||
public class RecentChangesImageUtils {
|
public class RecentChangesImageUtils {
|
||||||
|
|
||||||
private static final String[] imageExtensions = new String[]
|
private static final String[] imageExtensions = new String[]
|
||||||
{".jpg", ".jpeg", ".png"};
|
{".jpg", ".jpeg", ".png"};
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String findImageInRecentChanges(NodeList childNodes) {
|
public static String findImageInRecentChanges(List<RecentChange> recentChanges) {
|
||||||
String imageTitle;
|
String imageTitle;
|
||||||
Random r = new Random();
|
Random r = new Random();
|
||||||
int count = childNodes.getLength();
|
int count = recentChanges.size();
|
||||||
// Build a range array
|
// Build a range array
|
||||||
int[] randomIndexes = new int[count];
|
int[] randomIndexes = new int[count];
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
|
|
@ -31,12 +31,12 @@ public class RecentChangesImageUtils {
|
||||||
}
|
}
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
int randomIndex = randomIndexes[i];
|
int randomIndex = randomIndexes[i];
|
||||||
Element e = (Element) childNodes.item(randomIndex);
|
RecentChange recentChange = recentChanges.get(randomIndex);
|
||||||
if (e.getAttribute("type").equals("log") && !e.getAttribute("old_revid").equals("0")) {
|
if (recentChange.getType().equals("log") && !recentChange.getOldRevisionId().equals("0")) {
|
||||||
// For log entries, we only want ones where old_revid is zero, indicating a new file
|
// For log entries, we only want ones where old_revid is zero, indicating a new file
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
imageTitle = e.getAttribute("title");
|
imageTitle = recentChange.getTitle();
|
||||||
|
|
||||||
for (String imageExtension : imageExtensions) {
|
for (String imageExtension : imageExtensions) {
|
||||||
if (imageTitle.toLowerCase().endsWith(imageExtension)) {
|
if (imageTitle.toLowerCase().endsWith(imageExtension)) {
|
||||||
|
|
|
||||||
|
|
@ -162,6 +162,9 @@ public class MwQueryPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Revision {
|
public static class Revision {
|
||||||
|
private String revid;
|
||||||
|
private String user;
|
||||||
|
|
||||||
@SuppressWarnings("unused,NullableProblems")
|
@SuppressWarnings("unused,NullableProblems")
|
||||||
@SerializedName("contentformat")
|
@SerializedName("contentformat")
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|
@ -178,6 +181,8 @@ public class MwQueryPage {
|
||||||
@NonNull
|
@NonNull
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public String content() {
|
public String content() {
|
||||||
return content;
|
return content;
|
||||||
|
|
@ -187,6 +192,14 @@ public class MwQueryPage {
|
||||||
public String timeStamp() {
|
public String timeStamp() {
|
||||||
return StringUtils.defaultString(timeStamp);
|
return StringUtils.defaultString(timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRevid() {
|
||||||
|
return revid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LangLink {
|
public static class LangLink {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
|
@ -45,7 +44,6 @@ import fr.free.nrw.commons.auth.AccountUtil;
|
||||||
import fr.free.nrw.commons.category.CategoryImageUtils;
|
import fr.free.nrw.commons.category.CategoryImageUtils;
|
||||||
import fr.free.nrw.commons.category.QueryContinue;
|
import fr.free.nrw.commons.category.QueryContinue;
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.media.RecentChangesImageUtils;
|
|
||||||
import fr.free.nrw.commons.notification.Notification;
|
import fr.free.nrw.commons.notification.Notification;
|
||||||
import fr.free.nrw.commons.notification.NotificationUtils;
|
import fr.free.nrw.commons.notification.NotificationUtils;
|
||||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||||
|
|
@ -63,14 +61,6 @@ import static fr.free.nrw.commons.utils.ContinueUtils.getQueryContinue;
|
||||||
*/
|
*/
|
||||||
public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
||||||
private static final String THUMB_SIZE = "640";
|
private static final String THUMB_SIZE = "640";
|
||||||
// Give up if no random recent image found after 5 tries
|
|
||||||
private static final int MAX_RANDOM_TRIES = 5;
|
|
||||||
// Random image request is for some time in the past 30 days
|
|
||||||
private static final int RANDOM_SECONDS = 60 * 60 * 24 * 30;
|
|
||||||
// Assuming MW always gives me UTC
|
|
||||||
private static final SimpleDateFormat isoFormat =
|
|
||||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH);
|
|
||||||
private static final String FILE_NAMESPACE = "6";
|
|
||||||
private AbstractHttpClient httpClient;
|
private AbstractHttpClient httpClient;
|
||||||
private CustomMwApi api;
|
private CustomMwApi api;
|
||||||
private CustomMwApi wikidataApi;
|
private CustomMwApi wikidataApi;
|
||||||
|
|
@ -586,24 +576,6 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
||||||
.getString("/api/query/pages/page/revisions/rev");
|
.getString("/api/query/pages/page/revisions/rev");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Single<Revision> firstRevisionOfFile(String filename) {
|
|
||||||
return Single.fromCallable(() -> {
|
|
||||||
CustomApiResult res = api.action("query")
|
|
||||||
.param("prop", "revisions")
|
|
||||||
.param("rvprop", "timestamp|ids|user")
|
|
||||||
.param("titles", filename)
|
|
||||||
.param("rvdir", "newer")
|
|
||||||
.param("rvlimit", "1")
|
|
||||||
.get();
|
|
||||||
return new Revision(
|
|
||||||
res.getString("/api/query/pages/page/revisions/rev/@revid"),
|
|
||||||
res.getString("/api/query/pages/page/revisions/rev/@user"),
|
|
||||||
filename);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<Notification> getNotifications(boolean archived) {
|
public List<Notification> getNotifications(boolean archived) {
|
||||||
|
|
@ -1053,52 +1025,4 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatMWDate(Date date) {
|
|
||||||
return isoFormat.format(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Media getRecentRandomImage() throws IOException {
|
|
||||||
Media media = null;
|
|
||||||
int tries = 0;
|
|
||||||
Random r = new Random();
|
|
||||||
|
|
||||||
while (media == null && tries < MAX_RANDOM_TRIES) {
|
|
||||||
Date now = new Date();
|
|
||||||
Date startDate = new Date(now.getTime() - r.nextInt(RANDOM_SECONDS) * 1000L);
|
|
||||||
CustomApiResult apiResult = null;
|
|
||||||
try {
|
|
||||||
CustomMwApi.RequestBuilder requestBuilder = api.action("query")
|
|
||||||
.param("list", "recentchanges")
|
|
||||||
.param("rcstart", formatMWDate(startDate))
|
|
||||||
.param("rcnamespace", FILE_NAMESPACE)
|
|
||||||
.param("rcprop", "title|ids")
|
|
||||||
.param("rctype", "new|log")
|
|
||||||
.param("rctoponly", "1");
|
|
||||||
|
|
||||||
apiResult = requestBuilder.get();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Timber.e(e, "Failed to obtain recent random");
|
|
||||||
}
|
|
||||||
if (apiResult != null) {
|
|
||||||
CustomApiResult recentChangesNode = apiResult.getNode("/api/query/recentchanges");
|
|
||||||
if (recentChangesNode != null
|
|
||||||
&& recentChangesNode.getDocument() != null
|
|
||||||
&& recentChangesNode.getDocument().getChildNodes() != null
|
|
||||||
&& recentChangesNode.getDocument().getChildNodes().getLength() > 0) {
|
|
||||||
NodeList childNodes = recentChangesNode.getDocument().getChildNodes();
|
|
||||||
String imageTitle = RecentChangesImageUtils.findImageInRecentChanges(childNodes);
|
|
||||||
if (imageTitle != null) {
|
|
||||||
boolean deletionStatus = pageExists("Commons:Deletion_requests/" + imageTitle);
|
|
||||||
if (!deletionStatus) {
|
|
||||||
// strip File: prefix
|
|
||||||
imageTitle = imageTitle.replace("File:", "");
|
|
||||||
media = new Media(imageTitle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tries++;
|
|
||||||
}
|
|
||||||
return media;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
package fr.free.nrw.commons.mwapi;
|
package fr.free.nrw.commons.mwapi;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import fr.free.nrw.commons.Media;
|
import fr.free.nrw.commons.Media;
|
||||||
import fr.free.nrw.commons.notification.Notification;
|
import fr.free.nrw.commons.notification.Notification;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
|
|
@ -108,12 +108,7 @@ public interface MediaWikiApi {
|
||||||
|
|
||||||
boolean thank(String editToken, String revision) throws IOException;
|
boolean thank(String editToken, String revision) throws IOException;
|
||||||
|
|
||||||
Single<Revision> firstRevisionOfFile(String filename);
|
|
||||||
|
|
||||||
interface ProgressListener {
|
interface ProgressListener {
|
||||||
void onProgress(long transferred, long total);
|
void onProgress(long transferred, long total);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
Media getRecentRandomImage() throws IOException;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
package fr.free.nrw.commons.mwapi;
|
package fr.free.nrw.commons.mwapi;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import fr.free.nrw.commons.Media;
|
import fr.free.nrw.commons.Media;
|
||||||
import fr.free.nrw.commons.PageTitle;
|
import fr.free.nrw.commons.PageTitle;
|
||||||
import fr.free.nrw.commons.achievements.FeaturedImages;
|
import fr.free.nrw.commons.achievements.FeaturedImages;
|
||||||
|
|
@ -21,6 +22,7 @@ import fr.free.nrw.commons.campaigns.CampaignResponseDTO;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import fr.free.nrw.commons.media.model.MwQueryPage;
|
import fr.free.nrw.commons.media.model.MwQueryPage;
|
||||||
import fr.free.nrw.commons.mwapi.model.MwQueryResponse;
|
import fr.free.nrw.commons.mwapi.model.MwQueryResponse;
|
||||||
|
import fr.free.nrw.commons.mwapi.model.RecentChange;
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
import fr.free.nrw.commons.nearby.Place;
|
||||||
import fr.free.nrw.commons.nearby.model.NearbyResponse;
|
import fr.free.nrw.commons.nearby.model.NearbyResponse;
|
||||||
import fr.free.nrw.commons.nearby.model.NearbyResultItem;
|
import fr.free.nrw.commons.nearby.model.NearbyResultItem;
|
||||||
|
|
@ -277,4 +279,76 @@ public class OkHttpJsonApiClient {
|
||||||
return mediaList;
|
return mediaList;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns recent changes on commons
|
||||||
|
* @return list of recent changes made
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Single<List<RecentChange>> getRecentFileChanges() {
|
||||||
|
final int RANDOM_SECONDS = 60 * 60 * 24 * 30;
|
||||||
|
final String FILE_NAMESPACE = "6";
|
||||||
|
Random r = new Random();
|
||||||
|
Date now = new Date();
|
||||||
|
Date startDate = new Date(now.getTime() - r.nextInt(RANDOM_SECONDS) * 1000L);
|
||||||
|
|
||||||
|
HttpUrl.Builder urlBuilder = HttpUrl
|
||||||
|
.parse(commonsBaseUrl)
|
||||||
|
.newBuilder()
|
||||||
|
.addQueryParameter("action", "query")
|
||||||
|
.addQueryParameter("format", "json")
|
||||||
|
.addQueryParameter("list", "recentchanges")
|
||||||
|
.addQueryParameter("rcstart", DateUtils.formatMWDate(startDate))
|
||||||
|
.addQueryParameter("rcnamespace", FILE_NAMESPACE)
|
||||||
|
.addQueryParameter("rcprop", "title|ids")
|
||||||
|
.addQueryParameter("rctype", "new|log")
|
||||||
|
.addQueryParameter("rctoponly", "1");
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(urlBuilder.build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return Single.fromCallable(() -> {
|
||||||
|
Response response = okHttpClient.newCall(request).execute();
|
||||||
|
if (response.body() != null && response.isSuccessful()) {
|
||||||
|
String json = response.body().string();
|
||||||
|
MwQueryResponse mwQueryPage = gson.fromJson(json, MwQueryResponse.class);
|
||||||
|
return mwQueryPage.query().getRecentchanges();
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first revision of the file
|
||||||
|
*
|
||||||
|
* @return Revision object
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Single<MwQueryPage.Revision> getFirstRevisionOfFile(String filename) {
|
||||||
|
HttpUrl.Builder urlBuilder = HttpUrl
|
||||||
|
.parse(commonsBaseUrl)
|
||||||
|
.newBuilder()
|
||||||
|
.addQueryParameter("action", "query")
|
||||||
|
.addQueryParameter("format", "json")
|
||||||
|
.addQueryParameter("prop", "revisions")
|
||||||
|
.addQueryParameter("rvprop", "timestamp|ids|user")
|
||||||
|
.addQueryParameter("titles", filename)
|
||||||
|
.addQueryParameter("rvdir", "newer")
|
||||||
|
.addQueryParameter("rvlimit", "1");
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(urlBuilder.build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return Single.fromCallable(() -> {
|
||||||
|
Response response = okHttpClient.newCall(request).execute();
|
||||||
|
if (response.body() != null && response.isSuccessful()) {
|
||||||
|
String json = response.body().string();
|
||||||
|
MwQueryResponse mwQueryPage = gson.fromJson(json, MwQueryResponse.class);
|
||||||
|
return mwQueryPage.query().firstPage().revisions().get(0);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
package fr.free.nrw.commons.mwapi;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.PageTitle;
|
|
||||||
|
|
||||||
public class Revision {
|
|
||||||
public final String revisionId;
|
|
||||||
public final String username;
|
|
||||||
public final PageTitle pageTitle;
|
|
||||||
|
|
||||||
public Revision(String revisionId, String username, String pageTitle) {
|
|
||||||
this.revisionId = revisionId;
|
|
||||||
this.username = username;
|
|
||||||
this.pageTitle = new PageTitle(pageTitle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
package fr.free.nrw.commons.mwapi.model;
|
package fr.free.nrw.commons.mwapi.model;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import fr.free.nrw.commons.media.model.ImageInfo;
|
import fr.free.nrw.commons.media.model.ImageInfo;
|
||||||
import fr.free.nrw.commons.media.model.MwQueryPage;
|
import fr.free.nrw.commons.media.model.MwQueryPage;
|
||||||
|
|
||||||
|
|
@ -15,6 +14,7 @@ public class MwQueryResult {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Nullable
|
@Nullable
|
||||||
private HashMap<String, MwQueryPage> pages;
|
private HashMap<String, MwQueryPage> pages;
|
||||||
|
private List<RecentChange> recentchanges;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<MwQueryPage> pages() {
|
public List<MwQueryPage> pages() {
|
||||||
|
|
@ -24,6 +24,10 @@ public class MwQueryResult {
|
||||||
return new ArrayList<>(pages.values());
|
return new ArrayList<>(pages.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<RecentChange> getRecentchanges() {
|
||||||
|
return recentchanges;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public MwQueryPage firstPage() {
|
public MwQueryPage firstPage() {
|
||||||
return pages().get(0);
|
return pages().get(0);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package fr.free.nrw.commons.mwapi.model;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class RecentChange {
|
||||||
|
private final String type;
|
||||||
|
private final String title;
|
||||||
|
@SerializedName("old_revid")
|
||||||
|
private final String oldRevisionId;
|
||||||
|
|
||||||
|
public RecentChange(String type, String title, String oldRevisionId) {
|
||||||
|
this.type = type;
|
||||||
|
this.title = title;
|
||||||
|
this.oldRevisionId = oldRevisionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOldRevisionId() {
|
||||||
|
return oldRevisionId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,6 @@ import android.widget.ProgressBar;
|
||||||
import com.google.android.material.navigation.NavigationView;
|
import com.google.android.material.navigation.NavigationView;
|
||||||
import com.viewpagerindicator.CirclePageIndicator;
|
import com.viewpagerindicator.CirclePageIndicator;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
@ -19,7 +18,6 @@ import androidx.appcompat.widget.Toolbar;
|
||||||
import androidx.drawerlayout.widget.DrawerLayout;
|
import androidx.drawerlayout.widget.DrawerLayout;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import fr.free.nrw.commons.Media;
|
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.auth.AuthenticatedActivity;
|
import fr.free.nrw.commons.auth.AuthenticatedActivity;
|
||||||
import fr.free.nrw.commons.mwapi.MediaResult;
|
import fr.free.nrw.commons.mwapi.MediaResult;
|
||||||
|
|
@ -28,6 +26,7 @@ import fr.free.nrw.commons.utils.MediaDataExtractorUtil;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
@ -47,6 +46,8 @@ public class ReviewActivity extends AuthenticatedActivity {
|
||||||
Button skip_image_button;
|
Button skip_image_button;
|
||||||
|
|
||||||
@Inject MediaWikiApi mwApi;
|
@Inject MediaWikiApi mwApi;
|
||||||
|
@Inject
|
||||||
|
ReviewHelper reviewHelper;
|
||||||
|
|
||||||
public ReviewPagerAdapter reviewPagerAdapter;
|
public ReviewPagerAdapter reviewPagerAdapter;
|
||||||
|
|
||||||
|
|
@ -55,6 +56,8 @@ public class ReviewActivity extends AuthenticatedActivity {
|
||||||
@BindView(R.id.reviewPagerIndicator)
|
@BindView(R.id.reviewPagerIndicator)
|
||||||
public CirclePageIndicator pagerIndicator;
|
public CirclePageIndicator pagerIndicator;
|
||||||
|
|
||||||
|
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAuthCookieAcquired(String authCookie) {
|
protected void onAuthCookieAcquired(String authCookie) {
|
||||||
|
|
@ -93,21 +96,11 @@ public class ReviewActivity extends AuthenticatedActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
reviewPager.setCurrentItem(0);
|
reviewPager.setCurrentItem(0);
|
||||||
Observable.fromCallable(() -> {
|
compositeDisposable.add(reviewHelper.getRandomMedia()
|
||||||
String result = "";
|
.map(media -> media.getFilename())
|
||||||
try {
|
|
||||||
Media media = mwApi.getRecentRandomImage();
|
|
||||||
if (media != null) {
|
|
||||||
result = media.getFilename();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Timber.e("Error fetching recent random image: " + e.toString());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
})
|
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(this::updateImage);
|
.subscribe(this::updateImage));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,7 +110,7 @@ public class ReviewActivity extends AuthenticatedActivity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
reviewController.onImageRefreshed(fileName); //file name is updated
|
reviewController.onImageRefreshed(fileName); //file name is updated
|
||||||
mwApi.firstRevisionOfFile("File:" + fileName)
|
reviewHelper.getFirstRevisionOfFile("File:" + fileName)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(revision -> {
|
.subscribe(revision -> {
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.auth.SessionManager;
|
import fr.free.nrw.commons.auth.SessionManager;
|
||||||
import fr.free.nrw.commons.delete.DeleteTask;
|
import fr.free.nrw.commons.delete.DeleteTask;
|
||||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||||
|
import fr.free.nrw.commons.media.model.MwQueryPage;
|
||||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||||
import fr.free.nrw.commons.mwapi.Revision;
|
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
@ -30,7 +30,7 @@ import timber.log.Timber;
|
||||||
public class ReviewController {
|
public class ReviewController {
|
||||||
private String fileName;
|
private String fileName;
|
||||||
@Nullable
|
@Nullable
|
||||||
public Revision firstRevision; // TODO: maybe we can expand this class to include fileName
|
public MwQueryPage.Revision firstRevision; // TODO: maybe we can expand this class to include fileName
|
||||||
protected static ArrayList<String> categories;
|
protected static ArrayList<String> categories;
|
||||||
public static final int NOTIFICATION_SEND_THANK = 0x102;
|
public static final int NOTIFICATION_SEND_THANK = 0x102;
|
||||||
public static final int NOTIFICATION_CHECK_CATEGORY = 0x101;
|
public static final int NOTIFICATION_CHECK_CATEGORY = 0x101;
|
||||||
|
|
@ -197,7 +197,7 @@ public class ReviewController {
|
||||||
}
|
}
|
||||||
publishProgress(1);
|
publishProgress(1);
|
||||||
assert firstRevision != null;
|
assert firstRevision != null;
|
||||||
mwApi.thank(editToken, firstRevision.revisionId);
|
mwApi.thank(editToken, firstRevision.getRevid());
|
||||||
publishProgress(2);
|
publishProgress(2);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Timber.d(e);
|
Timber.d(e);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package fr.free.nrw.commons.review;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.Media;
|
||||||
|
import fr.free.nrw.commons.media.RecentChangesImageUtils;
|
||||||
|
import fr.free.nrw.commons.media.model.MwQueryPage;
|
||||||
|
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||||
|
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||||
|
import io.reactivex.Single;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class ReviewHelper {
|
||||||
|
private static final int MAX_RANDOM_TRIES = 5;
|
||||||
|
|
||||||
|
private final OkHttpJsonApiClient okHttpJsonApiClient;
|
||||||
|
private final MediaWikiApi mediaWikiApi;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ReviewHelper(OkHttpJsonApiClient okHttpJsonApiClient, MediaWikiApi mediaWikiApi) {
|
||||||
|
this.okHttpJsonApiClient = okHttpJsonApiClient;
|
||||||
|
this.mediaWikiApi = mediaWikiApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Single<Media> getRandomMedia() {
|
||||||
|
return okHttpJsonApiClient.getRecentFileChanges()
|
||||||
|
.map(RecentChangesImageUtils::findImageInRecentChanges)
|
||||||
|
.map(title -> {
|
||||||
|
boolean pageExists = mediaWikiApi.pageExists("Commons:Deletion_requests/" + title);
|
||||||
|
if (!pageExists) {
|
||||||
|
title = title.replace("File:", "");
|
||||||
|
return new Media(title);
|
||||||
|
}
|
||||||
|
throw new Exception("Page does not exist");
|
||||||
|
}).retry(MAX_RANDOM_TRIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Single<MwQueryPage.Revision> getFirstRevisionOfFile(String fileName) {
|
||||||
|
return okHttpJsonApiClient.getFirstRevisionOfFile(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ import com.facebook.drawee.view.SimpleDraweeView;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.Utils;
|
import fr.free.nrw.commons.Utils;
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||||
import fr.free.nrw.commons.mwapi.Revision;
|
import fr.free.nrw.commons.media.model.MwQueryPage;
|
||||||
|
|
||||||
public class ReviewImageFragment extends CommonsDaggerSupportFragment {
|
public class ReviewImageFragment extends CommonsDaggerSupportFragment {
|
||||||
|
|
||||||
|
|
@ -38,10 +38,10 @@ public class ReviewImageFragment extends CommonsDaggerSupportFragment {
|
||||||
private Button noButton;
|
private Button noButton;
|
||||||
|
|
||||||
public ProgressBar progressBar;
|
public ProgressBar progressBar;
|
||||||
private Revision revision;
|
private MwQueryPage.Revision revision;
|
||||||
|
|
||||||
|
|
||||||
public void update(int position, String fileName, Revision revision) {
|
public void update(int position, String fileName, MwQueryPage.Revision revision) {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.fileName = fileName;
|
this.fileName = fileName;
|
||||||
this.revision = revision;
|
this.revision = revision;
|
||||||
|
|
@ -118,7 +118,7 @@ public class ReviewImageFragment extends CommonsDaggerSupportFragment {
|
||||||
break;
|
break;
|
||||||
case THANKS:
|
case THANKS:
|
||||||
question = getString(R.string.review_thanks);
|
question = getString(R.string.review_thanks);
|
||||||
explanation = getString(R.string.review_thanks_explanation, ((ReviewActivity) getActivity()).reviewController.firstRevision.username);
|
explanation = getString(R.string.review_thanks_explanation, ((ReviewActivity) getActivity()).reviewController.firstRevision.getUser());
|
||||||
yesButtonText = getString(R.string.review_thanks_yes_button_text);
|
yesButtonText = getString(R.string.review_thanks_yes_button_text);
|
||||||
noButtonText = getString(R.string.review_thanks_no_button_text);
|
noButtonText = getString(R.string.review_thanks_no_button_text);
|
||||||
yesButton.setTextColor(Color.parseColor("#228b22"));
|
yesButton.setTextColor(Color.parseColor("#228b22"));
|
||||||
|
|
@ -158,7 +158,7 @@ public class ReviewImageFragment extends CommonsDaggerSupportFragment {
|
||||||
|
|
||||||
private void fillImageCaption() {
|
private void fillImageCaption() {
|
||||||
if (imageCaption != null && fileName != null && revision != null) {
|
if (imageCaption != null && fileName != null && revision != null) {
|
||||||
((TextView) imageCaption).setText(fileName + " is uploaded by: " + revision.username);
|
((TextView) imageCaption).setText(fileName + " is uploaded by: " + revision.getUser());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import android.os.Bundle;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||||
import fr.free.nrw.commons.mwapi.Revision;
|
import fr.free.nrw.commons.media.model.MwQueryPage;
|
||||||
|
|
||||||
public class ReviewPagerAdapter extends FragmentStatePagerAdapter {
|
public class ReviewPagerAdapter extends FragmentStatePagerAdapter {
|
||||||
ReviewImageFragment[] reviewImageFragments;
|
ReviewImageFragment[] reviewImageFragments;
|
||||||
|
|
@ -26,7 +26,7 @@ public class ReviewPagerAdapter extends FragmentStatePagerAdapter {
|
||||||
return reviewImageFragments.length;
|
return reviewImageFragments.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateFileInformation(String fileName, Revision revision) {
|
public void updateFileInformation(String fileName, MwQueryPage.Revision revision) {
|
||||||
for (int i = 0; i < getCount(); i++) {
|
for (int i = 0; i < getCount(); i++) {
|
||||||
ReviewImageFragment fragment = reviewImageFragments[i];
|
ReviewImageFragment fragment = reviewImageFragments[i];
|
||||||
fragment.update(i, fileName, revision);
|
fragment.update(i, fileName, revision);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class DateUtils {
|
public class DateUtils {
|
||||||
|
private static final SimpleDateFormat isoFormat =
|
||||||
|
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH);
|
||||||
|
|
||||||
public static String getTimeAgo(Date currDate, Date itemDate) {
|
public static String getTimeAgo(Date currDate, Date itemDate) {
|
||||||
Calendar c = Calendar.getInstance();
|
Calendar c = Calendar.getInstance();
|
||||||
c.setTime(currDate);
|
c.setTime(currDate);
|
||||||
|
|
@ -57,4 +60,8 @@ public class DateUtils {
|
||||||
public static String dateInLocaleFormat(Date date){
|
public static String dateInLocaleFormat(Date date){
|
||||||
return new SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "dd MMM yyyy"), Locale.getDefault()).format(date);
|
return new SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "dd MMM yyyy"), Locale.getDefault()).format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String formatMWDate(Date date) {
|
||||||
|
return isoFormat.format(date);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue