Skip to content

Commit 803777d

Browse files
Recolved merge conflicts [commons-app#1494]
2 parents 3fcbc37 + 9845a62 commit 803777d

40 files changed

+984
-311
lines changed

CONTRIBUTING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ changed. It is also good to prefix the first line with "area: " where the "area"
1414
is a filename or identifier for the general area of the code being modified.
1515
The body should provide a meaningful commit message.
1616

17+
# Write Javadocs
18+
19+
We require contributors to include Javadocs for all new methods and classes submitted via PRs (after 1 May 2018). This is aimed at making it easier for new contributors to dive into our codebase, especially those who are new to Android development. A few things to note:
20+
21+
- This should not replace the need for code that is easily-readable in and of itself
22+
- Please make sure that your Javadocs are reasonably descriptive, not just a copy of the method name
23+
- Please do not use `@author` tags - we aim for collective code ownership, and if needed, GitHub allows us to see who wrote something without needing to add these tags
24+
1725
# Write tests for your code (if possible)
1826

1927
# Make sure the Wiki pages don't become stale by updating them (if needed)

app/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ dependencies {
4949
implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0'
5050
implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0'
5151

52+
implementation 'org.jsoup:jsoup:1.11.3'
53+
5254
implementation 'com.facebook.fresco:fresco:1.5.0'
5355
implementation 'com.facebook.stetho:stetho:1.5.0'
5456

app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,9 @@
9292
android:label="@string/navigation_item_notification" />
9393

9494
<activity
95-
android:name=".featured.FeaturedImagesActivity"
96-
android:label="@string/title_activity_featured_images" />
95+
android:name=".category.CategoryImagesActivity"
96+
android:label="@string/title_activity_featured_images"
97+
android:parentActivityName=".contributions.ContributionsActivity" />
9798

9899
<service android:name=".upload.UploadService" />
99100

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package fr.free.nrw.commons.category;
2+
3+
import java.util.List;
4+
5+
import javax.inject.Inject;
6+
import javax.inject.Singleton;
7+
8+
import fr.free.nrw.commons.Media;
9+
import fr.free.nrw.commons.mwapi.MediaWikiApi;
10+
11+
@Singleton
12+
public class CategoryImageController {
13+
14+
private MediaWikiApi mediaWikiApi;
15+
16+
@Inject
17+
public CategoryImageController(MediaWikiApi mediaWikiApi) {
18+
this.mediaWikiApi = mediaWikiApi;
19+
}
20+
21+
/**
22+
* Takes a category name as input and calls the API to get a list of images for that category
23+
* @param categoryName
24+
* @return
25+
*/
26+
public List<Media> getCategoryImages(String categoryName) {
27+
return mediaWikiApi.getCategoryImages(categoryName);
28+
}
29+
}
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
package fr.free.nrw.commons.category;
2+
3+
import org.jsoup.Jsoup;
4+
import org.w3c.dom.Element;
5+
import org.w3c.dom.Node;
6+
import org.w3c.dom.NodeList;
7+
8+
import java.text.ParseException;
9+
import java.text.SimpleDateFormat;
10+
import java.util.ArrayList;
11+
import java.util.Date;
12+
import java.util.List;
13+
14+
import javax.annotation.Nullable;
15+
16+
import fr.free.nrw.commons.Media;
17+
import timber.log.Timber;
18+
19+
public class CategoryImageUtils {
20+
21+
/**
22+
* The method iterates over the child nodes to return a list of Media objects
23+
* @param childNodes
24+
* @return
25+
*/
26+
public static List<Media> getMediaList(NodeList childNodes) {
27+
List<Media> categoryImages = new ArrayList<>();
28+
for (int i = 0; i < childNodes.getLength(); i++) {
29+
Node node = childNodes.item(i);
30+
categoryImages.add(getMediaFromPage(node));
31+
}
32+
33+
return categoryImages;
34+
}
35+
36+
/**
37+
* Creates a new Media object from the XML response as received by the API
38+
* @param node
39+
* @return
40+
*/
41+
private static Media getMediaFromPage(Node node) {
42+
Media media = new Media(null,
43+
getImageUrl(node),
44+
getFileName(node),
45+
getDescription(node),
46+
getDataLength(node),
47+
getDateCreated(node),
48+
getDateCreated(node),
49+
getCreator(node)
50+
);
51+
52+
media.setLicense(getLicense(node));
53+
54+
return media;
55+
}
56+
57+
/**
58+
* Extracts the filename of the uploaded image
59+
* @param document
60+
* @return
61+
*/
62+
private static String getFileName(Node document) {
63+
Element element = (Element) document;
64+
return element.getAttribute("title");
65+
}
66+
67+
/**
68+
* Extracts the image description for that particular upload
69+
* @param document
70+
* @return
71+
*/
72+
private static String getDescription(Node document) {
73+
return getMetaDataValue(document, "ImageDescription");
74+
}
75+
76+
/**
77+
* Extracts license information from the image meta data
78+
* @param document
79+
* @return
80+
*/
81+
private static String getLicense(Node document) {
82+
return getMetaDataValue(document, "License");
83+
}
84+
85+
/**
86+
* Returns the parsed value of artist from the response
87+
* The artist information is returned as a HTML string from the API. Jsoup library parses the HTML string
88+
* to extract just the text value
89+
* @param document
90+
* @return
91+
*/
92+
private static String getCreator(Node document) {
93+
String artist = getMetaDataValue(document, "Artist");
94+
if (artist != null) {
95+
return Jsoup.parse(artist).text();
96+
}
97+
return null;
98+
}
99+
100+
/**
101+
* Returns the parsed date of creation of the image
102+
* @param document
103+
* @return
104+
*/
105+
private static Date getDateCreated(Node document) {
106+
String dateTime = getMetaDataValue(document, "DateTime");
107+
if (dateTime != null && !dateTime.equals("")) {
108+
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
109+
try {
110+
return format.parse(dateTime);
111+
} catch (ParseException e) {
112+
Timber.d("Error occurred while parsing date %s", dateTime);
113+
return new Date();
114+
}
115+
}
116+
return new Date();
117+
}
118+
119+
/**
120+
* @param document
121+
* @return Returns the url attribute from the imageInfo node
122+
*/
123+
private static String getImageUrl(Node document) {
124+
Element element = (Element) getImageInfo(document);
125+
if (element != null) {
126+
return element.getAttribute("url");
127+
}
128+
return null;
129+
}
130+
131+
/**
132+
* Takes the node document and gives out the attribute length from the node document
133+
* @param document
134+
* @return
135+
*/
136+
private static long getDataLength(Node document) {
137+
Element element = (Element) document;
138+
if (element != null) {
139+
String length = element.getAttribute("length");
140+
if (length != null && !length.equals("")) {
141+
return Long.parseLong(length);
142+
}
143+
}
144+
return 0L;
145+
}
146+
147+
/**
148+
* Generic method to get the value of any meta as returned by the getMetaData function
149+
* @param document node document as returned by API
150+
* @param metaName the name of meta node to be returned
151+
* @return
152+
*/
153+
private static String getMetaDataValue(Node document, String metaName) {
154+
Element metaData = getMetaData(document, metaName);
155+
if (metaData != null) {
156+
return metaData.getAttribute("value");
157+
}
158+
return null;
159+
}
160+
161+
/**
162+
* Generic method to return an element taking the node document and metaName as input
163+
* @param document node document as returned by API
164+
* @param metaName the name of meta node to be returned
165+
* @return
166+
*/
167+
@Nullable
168+
private static Element getMetaData(Node document, String metaName) {
169+
Node extraMetaData = getExtraMetaData(document);
170+
if (extraMetaData != null) {
171+
Node node = getNode(extraMetaData, metaName);
172+
if (node != null) {
173+
return (Element) node;
174+
}
175+
}
176+
return null;
177+
}
178+
179+
/**
180+
* Extracts extmetadata from the response XML
181+
* @param document
182+
* @return
183+
*/
184+
@Nullable
185+
private static Node getExtraMetaData(Node document) {
186+
Node imageInfo = getImageInfo(document);
187+
if (imageInfo != null) {
188+
return getNode(imageInfo, "extmetadata");
189+
}
190+
return null;
191+
}
192+
193+
/**
194+
* Extracts the ii node from the imageinfo node
195+
* @param document
196+
* @return
197+
*/
198+
@Nullable
199+
private static Node getImageInfo(Node document) {
200+
Node imageInfo = getNode(document, "imageinfo");
201+
if (imageInfo != null) {
202+
return getNode(imageInfo, "ii");
203+
}
204+
return null;
205+
}
206+
207+
/**
208+
* Takes a parent node as input and returns a child node if present
209+
* @param node parent node
210+
* @param nodeName child node name
211+
* @return
212+
*/
213+
@Nullable
214+
public static Node getNode(Node node, String nodeName) {
215+
NodeList childNodes = node.getChildNodes();
216+
for (int i = 0; i < childNodes.getLength(); i++) {
217+
Node nodeItem = childNodes.item(i);
218+
Element item = (Element) nodeItem;
219+
if (item.getTagName().equals(nodeName)) {
220+
return nodeItem;
221+
}
222+
}
223+
return null;
224+
}
225+
}

0 commit comments

Comments
 (0)