Skip to content

Commit a66a0e8

Browse files
committed
Refactoring to extract GpsCategoryModel and ensure single-responsibility-principle is maintained in CategoryApi.
1 parent c7948c8 commit a66a0e8

18 files changed

+542
-192
lines changed

app/proguard-rules.txt

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
-dontobfuscate
22
-keep class org.apache.http.** { *; }
33
-dontwarn org.apache.http.**
4-
-keep class fr.free.nrw.commons.upload.CategoryApi$Page {*;}
54
-keep class android.support.v7.widget.ShareActionProvider { *; }

app/src/main/java/fr/free/nrw/commons/caching/CacheController.java

+13-6
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,25 @@
77
import java.util.Arrays;
88
import java.util.List;
99

10-
import fr.free.nrw.commons.upload.CategoryApi;
10+
import javax.inject.Inject;
11+
import javax.inject.Singleton;
12+
13+
import fr.free.nrw.commons.upload.GpsCategoryModel;
1114
import timber.log.Timber;
1215

16+
@Singleton
1317
public class CacheController {
1418

19+
private final GpsCategoryModel gpsCategoryModel;
20+
private final QuadTree<List<String>> quadTree;
1521
private double x, y;
16-
private QuadTree<List<String>> quadTree;
1722
private double xMinus, xPlus, yMinus, yPlus;
1823

1924
private static final int EARTH_RADIUS = 6378137;
2025

21-
public CacheController() {
26+
@Inject
27+
CacheController(GpsCategoryModel gpsCategoryModel) {
28+
this.gpsCategoryModel = gpsCategoryModel;
2229
quadTree = new QuadTree<>(-180, -90, +180, +90);
2330
}
2431

@@ -31,8 +38,8 @@ public void setQtPoint(double decLongitude, double decLatitude) {
3138

3239
public void cacheCategory() {
3340
List<String> pointCatList = new ArrayList<>();
34-
if (CategoryApi.GpsCatExists.getGpsCatExists()) {
35-
pointCatList.addAll(CategoryApi.getGpsCat());
41+
if (gpsCategoryModel.getGpsCatExists()) {
42+
pointCatList.addAll(gpsCategoryModel.getCategoryList());
3643
Timber.d("Categories being cached: %s", pointCatList);
3744
} else {
3845
Timber.d("No categories found, so no categories cached");
@@ -65,7 +72,7 @@ public List<String> findCategory() {
6572
}
6673

6774
//Based on algorithm at http://gis.stackexchange.com/questions/2951/algorithm-for-offsetting-a-latitude-longitude-by-some-amount-of-meters
68-
public void convertCoordRange() {
75+
private void convertCoordRange() {
6976
//Position, decimal degrees
7077
double lat = y;
7178
double lon = x;

app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
import fr.free.nrw.commons.R;
4040
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
4141
import fr.free.nrw.commons.mwapi.MediaWikiApi;
42-
import fr.free.nrw.commons.upload.CategoryApi;
42+
import fr.free.nrw.commons.upload.GpsCategoryModel;
4343
import fr.free.nrw.commons.utils.StringSortingUtils;
4444
import fr.free.nrw.commons.utils.ViewUtil;
4545
import io.reactivex.Observable;
@@ -73,6 +73,7 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment {
7373
@Inject @Named("prefs") SharedPreferences prefsPrefs;
7474
@Inject @Named("direct_nearby_upload_prefs") SharedPreferences directPrefs;
7575
@Inject CategoryDao categoryDao;
76+
@Inject GpsCategoryModel gpsCategoryModel;
7677

7778
private RVRendererAdapter<CategoryItem> categoriesAdapter;
7879
private OnCategoriesSaveHandler onCategoriesSaveHandler;
@@ -253,7 +254,6 @@ private List<String> getStringList(List<CategoryItem> input) {
253254
}
254255

255256
private Observable<CategoryItem> defaultCategories() {
256-
257257
Observable<CategoryItem> directCat = directCategories();
258258
if (hasDirectCategories) {
259259
Timber.d("Image has direct Cat");
@@ -287,9 +287,7 @@ private Observable<CategoryItem> directCategories() {
287287
}
288288

289289
private Observable<CategoryItem> gpsCategories() {
290-
return Observable.fromIterable(
291-
CategoryApi.GpsCatExists.getGpsCatExists()
292-
? CategoryApi.getGpsCat() : new ArrayList<>())
290+
return Observable.fromIterable(gpsCategoryModel.getCategoryList())
293291
.map(name -> new CategoryItem(name, false));
294292
}
295293

app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java

-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import dagger.Provides;
1414
import fr.free.nrw.commons.auth.AccountUtil;
1515
import fr.free.nrw.commons.auth.SessionManager;
16-
import fr.free.nrw.commons.caching.CacheController;
1716
import fr.free.nrw.commons.data.DBOpenHelper;
1817
import fr.free.nrw.commons.location.LocationServiceManager;
1918
import fr.free.nrw.commons.mwapi.MediaWikiApi;
@@ -117,12 +116,6 @@ public LocationServiceManager provideLocationServiceManager(Context context) {
117116
return new LocationServiceManager(context);
118117
}
119118

120-
@Provides
121-
@Singleton
122-
public CacheController provideCacheController() {
123-
return new CacheController();
124-
}
125-
126119
@Provides
127120
@Singleton
128121
public DBOpenHelper provideDBOpenHelper(Context context) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package fr.free.nrw.commons.mwapi;
2+
3+
import com.google.gson.Gson;
4+
5+
import java.util.ArrayList;
6+
import java.util.Collections;
7+
import java.util.LinkedHashSet;
8+
import java.util.List;
9+
import java.util.Set;
10+
11+
import javax.inject.Inject;
12+
import javax.inject.Named;
13+
14+
import fr.free.nrw.commons.mwapi.model.ApiResponse;
15+
import fr.free.nrw.commons.mwapi.model.Page;
16+
import fr.free.nrw.commons.mwapi.model.PageCategory;
17+
import io.reactivex.Single;
18+
import okhttp3.HttpUrl;
19+
import okhttp3.OkHttpClient;
20+
import okhttp3.Request;
21+
import okhttp3.Response;
22+
import okhttp3.ResponseBody;
23+
import timber.log.Timber;
24+
25+
/**
26+
* Uses the OkHttp library to implement calls to the Commons MediaWiki API to match GPS coordinates
27+
* with nearby Commons categories. Parses the results using GSON to obtain a list of relevant
28+
* categories. Note: that caller is responsible for executing the request() method on a background
29+
* thread.
30+
*/
31+
public class CategoryApi {
32+
33+
private final OkHttpClient okHttpClient;
34+
private final HttpUrl mwUrl;
35+
private final Gson gson;
36+
37+
@Inject
38+
public CategoryApi(OkHttpClient okHttpClient, Gson gson,
39+
@Named("commons_mediawiki_url") HttpUrl mwUrl) {
40+
this.okHttpClient = okHttpClient;
41+
this.mwUrl = mwUrl;
42+
this.gson = gson;
43+
}
44+
45+
public Single<List<String>> request(String coords) {
46+
return Single.fromCallable(() -> {
47+
HttpUrl apiUrl = buildUrl(coords);
48+
Timber.d("URL: %s", apiUrl.toString());
49+
50+
Request request = new Request.Builder().get().url(apiUrl).build();
51+
Response response = okHttpClient.newCall(request).execute();
52+
ResponseBody body = response.body();
53+
if (body == null) {
54+
return Collections.emptyList();
55+
}
56+
57+
ApiResponse apiResponse = gson.fromJson(body.charStream(), ApiResponse.class);
58+
Set<String> categories = new LinkedHashSet<>();
59+
if (apiResponse != null && apiResponse.hasPages()) {
60+
for (Page page : apiResponse.query.pages) {
61+
for (PageCategory category : page.getCategories()) {
62+
categories.add(category.withoutPrefix());
63+
}
64+
}
65+
}
66+
return new ArrayList<>(categories);
67+
});
68+
}
69+
70+
/**
71+
* Builds URL with image coords for MediaWiki API calls
72+
* Example URL: https://commons.wikimedia.org/w/api.php?action=query&prop=categories|coordinates|pageprops&format=json&clshow=!hidden&coprop=type|name|dim|country|region|globe&codistancefrompoint=38.11386944444445|13.356263888888888&generator=geosearch&redirects=&ggscoord=38.11386944444445|1.356263888888888&ggsradius=100&ggslimit=10&ggsnamespace=6&ggsprop=type|name|dim|country|region|globe&ggsprimary=all&formatversion=2
73+
*
74+
* @param coords Coordinates to build query with
75+
* @return URL for API query
76+
*/
77+
private HttpUrl buildUrl(String coords) {
78+
return mwUrl.newBuilder()
79+
.addPathSegment("w")
80+
.addPathSegment("api.php")
81+
.addQueryParameter("action", "query")
82+
.addQueryParameter("prop", "categories|coordinates|pageprops")
83+
.addQueryParameter("format", "json")
84+
.addQueryParameter("clshow", "!hidden")
85+
.addQueryParameter("coprop", "type|name|dim|country|region|globe")
86+
.addQueryParameter("codistancefrompoint", coords)
87+
.addQueryParameter("generator", "geosearch")
88+
.addQueryParameter("ggscoord", coords)
89+
.addQueryParameter("ggsradius", "10000")
90+
.addQueryParameter("ggslimit", "10")
91+
.addQueryParameter("ggsnamespace", "6")
92+
.addQueryParameter("ggsprop", "type|name|dim|country|region|globe")
93+
.addQueryParameter("ggsprimary", "all")
94+
.addQueryParameter("formatversion", "2")
95+
.build();
96+
}
97+
98+
}
99+
100+
101+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package fr.free.nrw.commons.mwapi.model;
2+
3+
public class ApiResponse {
4+
public Query query;
5+
6+
public ApiResponse() {
7+
}
8+
9+
public boolean hasPages() {
10+
return query != null && query.pages != null;
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package fr.free.nrw.commons.mwapi.model;
2+
3+
import android.support.annotation.NonNull;
4+
5+
public class Page {
6+
public String title;
7+
public PageCategory[] categories;
8+
public PageCategory category;
9+
10+
public Page() {
11+
}
12+
13+
@NonNull
14+
public PageCategory[] getCategories() {
15+
return categories != null ? categories : new PageCategory[0];
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package fr.free.nrw.commons.mwapi.model;
2+
3+
public class PageCategory {
4+
public String title;
5+
6+
public PageCategory() {
7+
}
8+
9+
public String withoutPrefix() {
10+
return title != null ? title.replace("Category:", "") : "";
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package fr.free.nrw.commons.mwapi.model;
2+
3+
public class Query {
4+
public Page[] pages;
5+
6+
public Query() {
7+
pages = new Page[0];
8+
}
9+
10+
}

0 commit comments

Comments
 (0)