mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-11-04 08:43:52 +01:00 
			
		
		
		
	Merge remote-tracking branch 'refs/remotes/commons-app/master' into upload-overhaul-fork
This commit is contained in:
		
						commit
						c885c31cc5
					
				
					 104 changed files with 981 additions and 494 deletions
				
			
		| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
package fr.free.nrw.commons.upload;
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint;
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.content.ContentResolver;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +23,8 @@ import javax.inject.Inject;
 | 
			
		|||
 | 
			
		||||
import fr.free.nrw.commons.caching.CacheController;
 | 
			
		||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
 | 
			
		||||
import fr.free.nrw.commons.mwapi.CategoryApi;
 | 
			
		||||
import io.reactivex.schedulers.Schedulers;
 | 
			
		||||
import timber.log.Timber;
 | 
			
		||||
 | 
			
		||||
import static com.mapbox.mapboxsdk.Mapbox.getApplicationContext;
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +45,10 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse{
 | 
			
		|||
 | 
			
		||||
    @Inject
 | 
			
		||||
    CacheController cacheController;
 | 
			
		||||
    @Inject
 | 
			
		||||
    GpsCategoryModel gpsCategoryModel;
 | 
			
		||||
    @Inject
 | 
			
		||||
    CategoryApi apiCall;
 | 
			
		||||
 | 
			
		||||
    FileProcessor(Uri mediaUri, ContentResolver contentResolver, SharedPreferences prefs, Context context) {
 | 
			
		||||
        this.mediaUri = mediaUri;
 | 
			
		||||
| 
						 | 
				
			
			@ -169,8 +176,9 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse{
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initiates retrieval of image coordinates or user coordinates, and caching of coordinates.
 | 
			
		||||
     * Then initiates the calls to MediaWiki API through an instance of MwVolleyApi.
 | 
			
		||||
     * Then initiates the calls to MediaWiki API through an instance of CategoryApi.
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressLint("CheckResult")
 | 
			
		||||
    public void useImageCoords() {
 | 
			
		||||
        if (decimalCoords != null) {
 | 
			
		||||
            Timber.d("Decimal coords of image: %s", decimalCoords);
 | 
			
		||||
| 
						 | 
				
			
			@ -183,8 +191,6 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse{
 | 
			
		|||
                cacheController.setQtPoint(decLongitude, decLatitude);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            MwVolleyApi apiCall = new MwVolleyApi(context);
 | 
			
		||||
 | 
			
		||||
            List<String> displayCatList = cacheController.findCategory();
 | 
			
		||||
            boolean catListEmpty = displayCatList.isEmpty();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -192,12 +198,21 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse{
 | 
			
		|||
            // If no categories found in cache, call MediaWiki API to match image coords with nearby Commons categories
 | 
			
		||||
            if (catListEmpty) {
 | 
			
		||||
                cacheFound = false;
 | 
			
		||||
                apiCall.request(decimalCoords);
 | 
			
		||||
                apiCall.request(decimalCoords)
 | 
			
		||||
                        .subscribeOn(Schedulers.io())
 | 
			
		||||
                        .observeOn(Schedulers.io())
 | 
			
		||||
                        .subscribe(
 | 
			
		||||
                                gpsCategoryModel::setCategoryList,
 | 
			
		||||
                                throwable -> {
 | 
			
		||||
                                    Timber.e(throwable);
 | 
			
		||||
                                    gpsCategoryModel.clear();
 | 
			
		||||
                                }
 | 
			
		||||
                        );
 | 
			
		||||
                Timber.d("displayCatList size 0, calling MWAPI %s", displayCatList);
 | 
			
		||||
            } else {
 | 
			
		||||
                cacheFound = true;
 | 
			
		||||
                Timber.d("Cache found, setting categoryList in MwVolleyApi to %s", displayCatList);
 | 
			
		||||
                MwVolleyApi.setGpsCat(displayCatList);
 | 
			
		||||
                Timber.d("Cache found, setting categoryList in model to %s", displayCatList);
 | 
			
		||||
                gpsCategoryModel.setCategoryList(displayCatList);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            Timber.d("EXIF: no coords");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
package fr.free.nrw.commons.upload;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import javax.inject.Inject;
 | 
			
		||||
import javax.inject.Singleton;
 | 
			
		||||
 | 
			
		||||
@Singleton
 | 
			
		||||
public class GpsCategoryModel {
 | 
			
		||||
    private Set<String> categorySet;
 | 
			
		||||
 | 
			
		||||
    @Inject
 | 
			
		||||
    public GpsCategoryModel() {
 | 
			
		||||
        clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void clear() {
 | 
			
		||||
        categorySet = new HashSet<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean getGpsCatExists() {
 | 
			
		||||
        return !categorySet.isEmpty();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<String> getCategoryList() {
 | 
			
		||||
        return new ArrayList<>(categorySet);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setCategoryList(List<String> categoryList) {
 | 
			
		||||
        clear();
 | 
			
		||||
        categorySet.addAll(categoryList != null ? categoryList : new ArrayList<>());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void add(String categoryString) {
 | 
			
		||||
        categorySet.add(categoryString);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,249 +0,0 @@
 | 
			
		|||
package fr.free.nrw.commons.upload;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
 | 
			
		||||
import com.android.volley.Cache;
 | 
			
		||||
import com.android.volley.NetworkResponse;
 | 
			
		||||
import com.android.volley.Request;
 | 
			
		||||
import com.android.volley.RequestQueue;
 | 
			
		||||
import com.android.volley.Response;
 | 
			
		||||
import com.android.volley.VolleyError;
 | 
			
		||||
import com.android.volley.toolbox.HttpHeaderParser;
 | 
			
		||||
import com.android.volley.toolbox.JsonRequest;
 | 
			
		||||
import com.android.volley.toolbox.Volley;
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import com.google.gson.GsonBuilder;
 | 
			
		||||
 | 
			
		||||
import java.io.UnsupportedEncodingException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import timber.log.Timber;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Uses the Volley library to implement asynchronous calls to the Commons MediaWiki API to match
 | 
			
		||||
 * GPS coordinates with nearby Commons categories. Parses the results using GSON to obtain a list
 | 
			
		||||
 * of relevant categories.
 | 
			
		||||
 */
 | 
			
		||||
public class MwVolleyApi {
 | 
			
		||||
 | 
			
		||||
    private static RequestQueue REQUEST_QUEUE;
 | 
			
		||||
    private static final Gson GSON = new GsonBuilder().create();
 | 
			
		||||
 | 
			
		||||
    private static Set<String> categorySet;
 | 
			
		||||
    private static List<String> categoryList;
 | 
			
		||||
 | 
			
		||||
    private static final String MWURL = "https://commons.wikimedia.org/";
 | 
			
		||||
    private final Context context;
 | 
			
		||||
 | 
			
		||||
    public MwVolleyApi(Context context) {
 | 
			
		||||
        this.context = context;
 | 
			
		||||
        categorySet = new HashSet<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static List<String> getGpsCat() {
 | 
			
		||||
        return categoryList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void setGpsCat(List<String> cachedList) {
 | 
			
		||||
        categoryList = new ArrayList<>();
 | 
			
		||||
        categoryList.addAll(cachedList);
 | 
			
		||||
        Timber.d("Setting GPS cats from cache: %s", categoryList);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void request(String coords) {
 | 
			
		||||
        String apiUrl = buildUrl(coords);
 | 
			
		||||
        Timber.d("URL: %s", apiUrl);
 | 
			
		||||
 | 
			
		||||
        JsonRequest<QueryResponse> request = new QueryRequest(apiUrl,
 | 
			
		||||
                new LogResponseListener<>(), new LogResponseErrorListener());
 | 
			
		||||
        getQueue().add(request);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Builds URL with image coords for MediaWiki API calls
 | 
			
		||||
     * 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
 | 
			
		||||
     * @param coords Coordinates to build query with
 | 
			
		||||
     * @return URL for API query
 | 
			
		||||
     */
 | 
			
		||||
    private String buildUrl(String coords) {
 | 
			
		||||
 | 
			
		||||
        Uri.Builder builder = Uri.parse(MWURL).buildUpon();
 | 
			
		||||
 | 
			
		||||
        builder.appendPath("w")
 | 
			
		||||
                .appendPath("api.php")
 | 
			
		||||
                .appendQueryParameter("action", "query")
 | 
			
		||||
                .appendQueryParameter("prop", "categories|coordinates|pageprops")
 | 
			
		||||
                .appendQueryParameter("format", "json")
 | 
			
		||||
                .appendQueryParameter("clshow", "!hidden")
 | 
			
		||||
                .appendQueryParameter("coprop", "type|name|dim|country|region|globe")
 | 
			
		||||
                .appendQueryParameter("codistancefrompoint", coords)
 | 
			
		||||
                .appendQueryParameter("generator", "geosearch")
 | 
			
		||||
                .appendQueryParameter("ggscoord", coords)
 | 
			
		||||
                .appendQueryParameter("ggsradius", "10000")
 | 
			
		||||
                .appendQueryParameter("ggslimit", "10")
 | 
			
		||||
                .appendQueryParameter("ggsnamespace", "6")
 | 
			
		||||
                .appendQueryParameter("ggsprop", "type|name|dim|country|region|globe")
 | 
			
		||||
                .appendQueryParameter("ggsprimary", "all")
 | 
			
		||||
                .appendQueryParameter("formatversion", "2");
 | 
			
		||||
 | 
			
		||||
        return builder.toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private synchronized RequestQueue getQueue() {
 | 
			
		||||
        if (REQUEST_QUEUE == null) {
 | 
			
		||||
            REQUEST_QUEUE = Volley.newRequestQueue(context);
 | 
			
		||||
        }
 | 
			
		||||
        return REQUEST_QUEUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class LogResponseListener<T> implements Response.Listener<T> {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onResponse(T response) {
 | 
			
		||||
            Timber.d(response.toString());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class LogResponseErrorListener implements Response.ErrorListener {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onErrorResponse(VolleyError error) {
 | 
			
		||||
            Timber.e(error.toString());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class QueryRequest extends JsonRequest<QueryResponse> {
 | 
			
		||||
 | 
			
		||||
        public QueryRequest(String url,
 | 
			
		||||
                            Response.Listener<QueryResponse> listener,
 | 
			
		||||
                            Response.ErrorListener errorListener) {
 | 
			
		||||
            super(Request.Method.GET, url, null, listener, errorListener);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected Response<QueryResponse> parseNetworkResponse(NetworkResponse response) {
 | 
			
		||||
            String json = parseString(response);
 | 
			
		||||
            QueryResponse queryResponse = GSON.fromJson(json, QueryResponse.class);
 | 
			
		||||
            return Response.success(queryResponse, cacheEntry(response));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Cache.Entry cacheEntry(NetworkResponse response) {
 | 
			
		||||
            return HttpHeaderParser.parseCacheHeaders(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private String parseString(NetworkResponse response) {
 | 
			
		||||
            try {
 | 
			
		||||
                return new String(response.data, HttpHeaderParser.parseCharset(response.headers));
 | 
			
		||||
            } catch (UnsupportedEncodingException e) {
 | 
			
		||||
                return new String(response.data);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class GpsCatExists {
 | 
			
		||||
        private static boolean gpsCatExists;
 | 
			
		||||
 | 
			
		||||
        public static void setGpsCatExists(boolean gpsCat) {
 | 
			
		||||
            gpsCatExists = gpsCat;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static boolean getGpsCatExists() {
 | 
			
		||||
            return gpsCatExists;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class QueryResponse {
 | 
			
		||||
        private Query query = new Query();
 | 
			
		||||
 | 
			
		||||
        private String printSet() {
 | 
			
		||||
            if (categorySet == null || categorySet.isEmpty()) {
 | 
			
		||||
                GpsCatExists.setGpsCatExists(false);
 | 
			
		||||
                Timber.d("gpsCatExists=%b", GpsCatExists.getGpsCatExists());
 | 
			
		||||
                return "No collection of categories";
 | 
			
		||||
            } else {
 | 
			
		||||
                GpsCatExists.setGpsCatExists(true);
 | 
			
		||||
                Timber.d("gpsCatExists=%b", GpsCatExists.getGpsCatExists());
 | 
			
		||||
                return "CATEGORIES FOUND" + categorySet.toString();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String toString() {
 | 
			
		||||
            if (query != null) {
 | 
			
		||||
                return "query=" + query.toString() + "\n" + printSet();
 | 
			
		||||
            } else {
 | 
			
		||||
                return "No pages found";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class Query {
 | 
			
		||||
        private Page [] pages;
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String toString() {
 | 
			
		||||
            StringBuilder builder = new StringBuilder("pages=" + "\n");
 | 
			
		||||
            if (pages != null) {
 | 
			
		||||
                for (Page page : pages) {
 | 
			
		||||
                    builder.append(page.toString());
 | 
			
		||||
                    builder.append("\n");
 | 
			
		||||
                }
 | 
			
		||||
                builder.replace(builder.length() - 1, builder.length(), "");
 | 
			
		||||
                return builder.toString();
 | 
			
		||||
            } else {
 | 
			
		||||
                return "No pages found";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Page {
 | 
			
		||||
        private int pageid;
 | 
			
		||||
        private int ns;
 | 
			
		||||
        private String title;
 | 
			
		||||
        private Category[] categories;
 | 
			
		||||
        private Category category;
 | 
			
		||||
 | 
			
		||||
        public Page() {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String toString() {
 | 
			
		||||
 | 
			
		||||
            StringBuilder builder = new StringBuilder("PAGEID=" + pageid + " ns=" + ns + " title=" + title + "\n" + " CATEGORIES= ");
 | 
			
		||||
 | 
			
		||||
            if (categories == null || categories.length == 0) {
 | 
			
		||||
                builder.append("no categories exist\n");
 | 
			
		||||
            } else {
 | 
			
		||||
                for (Category category : categories) {
 | 
			
		||||
                    builder.append(category.toString());
 | 
			
		||||
                    builder.append("\n");
 | 
			
		||||
                    if (category != null) {
 | 
			
		||||
                        String categoryString = category.toString().replace("Category:", "");
 | 
			
		||||
                        categorySet.add(categoryString);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            categoryList = new ArrayList<>(categorySet);
 | 
			
		||||
            builder.replace(builder.length() - 1, builder.length(), "");
 | 
			
		||||
            return builder.toString();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class Category {
 | 
			
		||||
        private String title;
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String toString() {
 | 
			
		||||
            return title;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,9 @@
 | 
			
		|||
package fr.free.nrw.commons.upload;
 | 
			
		||||
 | 
			
		||||
import android.Manifest;
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint;
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.animation.Animator;
 | 
			
		||||
import android.animation.AnimatorListenerAdapter;
 | 
			
		||||
import android.animation.AnimatorSet;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +66,9 @@ import fr.free.nrw.commons.modifications.ModificationsContentProvider;
 | 
			
		|||
import fr.free.nrw.commons.modifications.ModifierSequence;
 | 
			
		||||
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
 | 
			
		||||
import fr.free.nrw.commons.modifications.TemplateRemoveModifier;
 | 
			
		||||
import fr.free.nrw.commons.mwapi.CategoryApi;
 | 
			
		||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
 | 
			
		||||
import io.reactivex.schedulers.Schedulers;
 | 
			
		||||
import fr.free.nrw.commons.utils.ViewUtil;
 | 
			
		||||
import timber.log.Timber;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,8 +104,13 @@ public class ShareActivity
 | 
			
		|||
    @Inject
 | 
			
		||||
    ModifierSequenceDao modifierSequenceDao;
 | 
			
		||||
    @Inject
 | 
			
		||||
    CategoryApi apiCall;
 | 
			
		||||
    @Inject
 | 
			
		||||
    @Named("default_preferences")
 | 
			
		||||
    SharedPreferences prefs;
 | 
			
		||||
    @Inject
 | 
			
		||||
    GpsCategoryModel gpsCategoryModel;
 | 
			
		||||
 | 
			
		||||
    @BindView(R.id.container)
 | 
			
		||||
    FrameLayout flContainer;
 | 
			
		||||
    @BindView(R.id.backgroundImage)
 | 
			
		||||
| 
						 | 
				
			
			@ -115,6 +125,7 @@ public class ShareActivity
 | 
			
		|||
    FloatingActionButton mainFab;
 | 
			
		||||
    @BindView(R.id.expanded_image)
 | 
			
		||||
    PhotoView expandedImageView;
 | 
			
		||||
 | 
			
		||||
    private String source;
 | 
			
		||||
    private String mimeType;
 | 
			
		||||
    private CategorizationFragment categorizationFragment;
 | 
			
		||||
| 
						 | 
				
			
			@ -461,8 +472,6 @@ public class ShareActivity
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onPause() {
 | 
			
		||||
        super.onPause();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue