mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 21:03:54 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
8e47f82de6
16 changed files with 326 additions and 52 deletions
23
app/src/androidTest/java/fr/free/nrw/commons/MediaTest.java
Normal file
23
app/src/androidTest/java/fr/free/nrw/commons/MediaTest.java
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package fr.free.nrw.commons;
|
||||||
|
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
|
||||||
|
// TODO: use Robolectric and make it runnable without a connected device
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class MediaTest {
|
||||||
|
@Test public void displayTitleShouldStripExtension() {
|
||||||
|
Media m = new Media("File:Example.jpg");
|
||||||
|
Assert.assertThat(m.getDisplayTitle(), is("Example"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void displayTitleShouldUseSpaceForUnderscore() {
|
||||||
|
Media m = new Media("File:Example 1_2.jpg");
|
||||||
|
Assert.assertThat(m.getDisplayTitle(), is("Example 1 2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package fr.free.nrw.commons;
|
||||||
|
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
|
||||||
|
// TODO: use Robolectric and make it runnable without a connected device
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class PageTitleTest {
|
||||||
|
@Test public void displayTextShouldNotBeUnderscored() {
|
||||||
|
Assert.assertThat(new PageTitle("Ex_1 ").getDisplayText(),
|
||||||
|
is("Ex 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void moreThanTwoColons() {
|
||||||
|
Assert.assertThat(new PageTitle("File:sample:a.jpg").getPrefixedText(),
|
||||||
|
is("File:Sample:a.jpg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void getTextShouldReturnWithoutNamespace() {
|
||||||
|
Assert.assertThat(new PageTitle("File:sample.jpg").getText(),
|
||||||
|
is("Sample.jpg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test public void capitalizeNameAfterNamespace() {
|
||||||
|
Assert.assertThat(new PageTitle("File:sample.jpg").getPrefixedText(),
|
||||||
|
is("File:Sample.jpg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void prefixedTextShouldBeUnderscored() {
|
||||||
|
Assert.assertThat(new PageTitle("Ex 1 ").getPrefixedText(),
|
||||||
|
is("Ex_1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void getMobileUriForTest() {
|
||||||
|
Assert.assertThat(new PageTitle("Test").getMobileUri().toString(),
|
||||||
|
is("https://commons.m.wikimedia.org/wiki/Test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void spaceBecomesUnderscoreInUri() {
|
||||||
|
Assert.assertThat(new PageTitle("File:Ex 1.jpg").getCanonicalUri().toString(),
|
||||||
|
is("https://commons.wikimedia.org/wiki/File:Ex_1.jpg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void leaveSubpageNamesUncapitalizedInUri() {
|
||||||
|
Assert.assertThat(new PageTitle("User:Ex/subpage").getCanonicalUri().toString(),
|
||||||
|
is("https://commons.wikimedia.org/wiki/User:Ex/subpage"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void unicodeUri() throws Throwable {
|
||||||
|
Assert.assertThat(new PageTitle("User:例").getCanonicalUri().toString(),
|
||||||
|
is("https://commons.wikimedia.org/wiki/User:" + URLEncoder.encode("例", "utf-8")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
|
@ -42,10 +43,11 @@ public class LicenseList {
|
||||||
return licenses.get(key);
|
return licenses.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public License licenseForTemplate(String template) {
|
public License licenseForTemplate(String template) {
|
||||||
String ucTemplate = Utils.capitalize(template);
|
String ucTemplate = new PageTitle(template).getDisplayText();
|
||||||
for (License license : values()) {
|
for (License license : values()) {
|
||||||
if (ucTemplate.equals(Utils.capitalize(license.getTemplate()))) {
|
if (ucTemplate.equals(new PageTitle(license.getTemplate()).getDisplayText())) {
|
||||||
return license;
|
return license;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public class Media implements Parcelable {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
// FIXME: Gross hack bercause my regex skills suck maybe or I am too lazy who knows
|
// FIXME: Gross hack bercause my regex skills suck maybe or I am too lazy who knows
|
||||||
String title = filename.replaceFirst("^File:", "");
|
String title = getFilePageTitle().getDisplayText().replaceFirst("^File:", "");
|
||||||
Matcher matcher = displayTitlePattern.matcher(title);
|
Matcher matcher = displayTitlePattern.matcher(title);
|
||||||
if(matcher.matches()) {
|
if(matcher.matches()) {
|
||||||
return matcher.group(1);
|
return matcher.group(1);
|
||||||
|
|
@ -56,13 +56,8 @@ public class Media implements Parcelable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescriptionUrl() {
|
public PageTitle getFilePageTitle() {
|
||||||
// HACK! Geez
|
return new PageTitle("File:" + getFilename().replaceFirst("^File:", ""));
|
||||||
return CommonsApplication.HOME_URL + "File:" + Utils.urlEncode(getFilename().replace("File:", "").replace(" ", "_"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMobileDescriptionUrl() {
|
|
||||||
return CommonsApplication.MOBILE_HOME_URL + "File:" + Utils.urlEncode(getFilename().replace("File:", "").replace(" ", "_"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getLocalUri() {
|
public Uri getLocalUri() {
|
||||||
|
|
|
||||||
|
|
@ -150,14 +150,14 @@ public class MediaDataExtractor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node findTemplate(Element parentNode, String title) throws IOException {
|
private Node findTemplate(Element parentNode, String title_) throws IOException {
|
||||||
String ucTitle= Utils.capitalize(title);
|
String title= new PageTitle(title_).getDisplayText();
|
||||||
NodeList nodes = parentNode.getChildNodes();
|
NodeList nodes = parentNode.getChildNodes();
|
||||||
for (int i = 0, length = nodes.getLength(); i < length; i++) {
|
for (int i = 0, length = nodes.getLength(); i < length; i++) {
|
||||||
Node node = nodes.item(i);
|
Node node = nodes.item(i);
|
||||||
if (node.getNodeName().equals("template")) {
|
if (node.getNodeName().equals("template")) {
|
||||||
String foundTitle = getTemplateTitle(node);
|
String foundTitle = getTemplateTitle(node);
|
||||||
if (Utils.capitalize(foundTitle).equals(ucTitle)) {
|
if (title.equals(new PageTitle(foundTitle).getDisplayText())) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,13 @@ import android.support.annotation.Nullable;
|
||||||
import android.support.graphics.drawable.VectorDrawableCompat;
|
import android.support.graphics.drawable.VectorDrawableCompat;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||||
import com.facebook.drawee.view.SimpleDraweeView;
|
import com.facebook.drawee.view.SimpleDraweeView;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class MediaWikiImageView extends SimpleDraweeView {
|
public class MediaWikiImageView extends SimpleDraweeView {
|
||||||
private ThumbnailFetchTask currentThumbnailTask;
|
private ThumbnailFetchTask currentThumbnailTask;
|
||||||
|
|
||||||
|
|
@ -81,7 +84,13 @@ public class MediaWikiImageView extends SimpleDraweeView {
|
||||||
result = media.getLocalUri().toString();
|
result = media.getLocalUri().toString();
|
||||||
} else {
|
} else {
|
||||||
// only cache meaningful thumbnails received from network.
|
// only cache meaningful thumbnails received from network.
|
||||||
|
try {
|
||||||
CommonsApplication.getInstance().getThumbnailUrlCache().put(media.getFilename(), result);
|
CommonsApplication.getInstance().getThumbnailUrlCache().put(media.getFilename(), result);
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
Timber.e("error when adding pic to cache " + npe);
|
||||||
|
|
||||||
|
Toast.makeText(getContext(), R.string.error_while_cache, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setImageUrl(result);
|
setImageUrl(result);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
91
app/src/main/java/fr/free/nrw/commons/PageTitle.java
Normal file
91
app/src/main/java/fr/free/nrw/commons/PageTitle.java
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
package fr.free.nrw.commons;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
public class PageTitle {
|
||||||
|
private final String namespace;
|
||||||
|
private final String titleKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct from a namespace-prefixed page name.
|
||||||
|
* @param prefixedText namespace-prefixed page name
|
||||||
|
*/
|
||||||
|
public PageTitle(@NonNull String prefixedText) {
|
||||||
|
String[] segments = prefixedText.trim().replace(" ", "_").split(":", 2);
|
||||||
|
|
||||||
|
// canonicalize and capitalize page title as done by MediaWiki
|
||||||
|
if (segments.length == 2) {
|
||||||
|
// TODO: canonicalize and capitalize namespace as well
|
||||||
|
// see https://www.mediawiki.org/wiki/Manual:Title.php#Canonical_forms
|
||||||
|
namespace = segments[0];
|
||||||
|
titleKey = Utils.capitalize(segments[1]);
|
||||||
|
} else {
|
||||||
|
namespace = "";
|
||||||
|
titleKey = Utils.capitalize(segments[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the canonicalized title for displaying (such as "File:My example.jpg").
|
||||||
|
*
|
||||||
|
* @return canonical title
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String getPrefixedText() {
|
||||||
|
if (namespace.isEmpty()) {
|
||||||
|
return titleKey;
|
||||||
|
} else {
|
||||||
|
return namespace + ":" + titleKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the canonical title for DB and URLs (such as "File:My_example.jpg").
|
||||||
|
*
|
||||||
|
* @return canonical title
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String getDisplayText() {
|
||||||
|
return getPrefixedText().replace("_", " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to a URI
|
||||||
|
* (such as "https://commons.wikimedia.org/wiki/File:My_example.jpg").
|
||||||
|
*
|
||||||
|
* @return URI
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Uri getCanonicalUri() {
|
||||||
|
String uriStr = CommonsApplication.HOME_URL + Uri.encode(getPrefixedText(), ":/");
|
||||||
|
return Uri.parse(uriStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to a mobile URI
|
||||||
|
* (such as "https://commons.m.wikimedia.org/wiki/File:My_example.jpg").
|
||||||
|
*
|
||||||
|
* @return URI
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Uri getMobileUri() {
|
||||||
|
String uriStr = CommonsApplication.MOBILE_HOME_URL + Uri.encode(getPrefixedText(), ":/");
|
||||||
|
return Uri.parse(uriStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the canonical title without namespace.
|
||||||
|
* @return title
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String getText() {
|
||||||
|
return titleKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getPrefixedText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package fr.free.nrw.commons;
|
package fr.free.nrw.commons;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
|
|
@ -9,7 +8,6 @@ import android.text.Spanned;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Hex;
|
import org.apache.commons.codec.binary.Hex;
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
import org.apache.commons.codec.net.URLCodec;
|
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
@ -20,6 +18,7 @@ import java.io.InputStream;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.net.URLEncoder;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
|
|
@ -126,7 +125,7 @@ public class Utils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String makeThumbBaseUrl(String filename) {
|
public static String makeThumbBaseUrl(String filename) {
|
||||||
String name = filename.replaceFirst("File:", "").replace(" ", "_");
|
String name = new PageTitle(filename).getPrefixedText();
|
||||||
String sha = new String(Hex.encodeHex(DigestUtils.md5(name)));
|
String sha = new String(Hex.encodeHex(DigestUtils.md5(name)));
|
||||||
return String.format("%s/%s/%s/%s", CommonsApplication.IMAGE_URL_BASE, sha.substring(0, 1), sha.substring(0, 2), urlEncode(name));
|
return String.format("%s/%s/%s/%s", CommonsApplication.IMAGE_URL_BASE, sha.substring(0, 1), sha.substring(0, 2), urlEncode(name));
|
||||||
}
|
}
|
||||||
|
|
@ -153,11 +152,9 @@ public class Utils {
|
||||||
return outputStream.toString();
|
return outputStream.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final URLCodec urlCodec = new URLCodec();
|
|
||||||
|
|
||||||
public static String urlEncode(String url) {
|
public static String urlEncode(String url) {
|
||||||
try {
|
try {
|
||||||
return urlCodec.encode(url, "utf-8");
|
return URLEncoder.encode(url, "utf-8");
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
@ -232,12 +229,6 @@ public class Utils {
|
||||||
throw new RuntimeException("Unrecognized license value: " + license);
|
throw new RuntimeException("Unrecognized license value: " + license);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri uriForWikiPage(String name) {
|
|
||||||
String underscored = name.trim().replace(" ", "_");
|
|
||||||
String uriStr = CommonsApplication.HOME_URL + urlEncode(underscored);
|
|
||||||
return Uri.parse(uriStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fast-forward an XmlPullParser to the next instance of the given element
|
* Fast-forward an XmlPullParser to the next instance of the given element
|
||||||
* in the input stream (namespaced).
|
* in the input stream (namespaced).
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,9 @@ import android.widget.Toast;
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
import fr.free.nrw.commons.BuildConfig;
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
import fr.free.nrw.commons.CommonsApplication;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
import fr.free.nrw.commons.WelcomeActivity;
|
import fr.free.nrw.commons.WelcomeActivity;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.PageTitle;
|
||||||
import fr.free.nrw.commons.contributions.ContributionsActivity;
|
import fr.free.nrw.commons.contributions.ContributionsActivity;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
@ -162,7 +163,7 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
||||||
* @return String canonicial username
|
* @return String canonicial username
|
||||||
*/
|
*/
|
||||||
private String canonicializeUsername( String username ) {
|
private String canonicializeUsername( String username ) {
|
||||||
return Utils.capitalize(username.substring(0,1)) + username.substring(1);
|
return new PageTitle(username).getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.contributions;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
|
@ -9,6 +10,7 @@ import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
|
|
@ -105,19 +107,57 @@ public class ContributionsListFragment extends Fragment {
|
||||||
case R.id.menu_from_gallery:
|
case R.id.menu_from_gallery:
|
||||||
//Gallery crashes before reach ShareActivity screen so must implement permissions check here
|
//Gallery crashes before reach ShareActivity screen so must implement permissions check here
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
if (ContextCompat.checkSelfPermission(this.getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
//See http://stackoverflow.com/questions/33169455/onrequestpermissionsresult-not-being-called-in-dialog-fragment
|
// Here, thisActivity is the current activity
|
||||||
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
|
if (ContextCompat.checkSelfPermission(getActivity(),
|
||||||
return true;
|
Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
|
||||||
|
// Should we show an explanation?
|
||||||
|
if (shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
||||||
|
|
||||||
|
// Show an explanation to the user *asynchronously* -- don't block
|
||||||
|
// this thread waiting for the user's response! After the user
|
||||||
|
// sees the explanation, try again to request the permission.
|
||||||
|
|
||||||
|
new AlertDialog.Builder(getActivity())
|
||||||
|
.setMessage(getString(R.string.storage_permission_rationale))
|
||||||
|
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
|
||||||
|
requestPermissions(
|
||||||
|
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||||
|
1);
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton("Cancel", null)
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// No explanation needed, we can request the permission.
|
||||||
|
|
||||||
|
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||||
|
1);
|
||||||
|
|
||||||
|
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
|
||||||
|
// app-defined int constant. The callback method gets the
|
||||||
|
// result of the request.
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
controller.startGalleryPick();
|
controller.startGalleryPick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
} else {
|
||||||
controller.startGalleryPick();
|
controller.startGalleryPick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
case R.id.menu_from_camera:
|
case R.id.menu_from_camera:
|
||||||
controller.startCameraCapture();
|
controller.startCameraCapture();
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -128,6 +168,9 @@ public class ContributionsListFragment extends Fragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||||
|
|
||||||
|
Timber.d("onRequestPermissionsResult: req code = " + " perm = " + permissions + " grant =" + grantResults);
|
||||||
|
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
// 1 = Storage allowed when gallery selected
|
// 1 = Storage allowed when gallery selected
|
||||||
case 1: {
|
case 1: {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.PageTitle;
|
||||||
import fr.free.nrw.commons.concurrency.BackgroundPoolExceptionHandler;
|
import fr.free.nrw.commons.concurrency.BackgroundPoolExceptionHandler;
|
||||||
import fr.free.nrw.commons.concurrency.ThreadPoolExecutorService;
|
import fr.free.nrw.commons.concurrency.ThreadPoolExecutorService;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
@ -33,7 +34,8 @@ public class UploadCountClient {
|
||||||
public void run() {
|
public void run() {
|
||||||
URL url;
|
URL url;
|
||||||
try {
|
try {
|
||||||
url = new URL(String.format(Locale.ENGLISH, UPLOAD_COUNT_URL_TEMPLATE, userName));
|
url = new URL(String.format(Locale.ENGLISH, UPLOAD_COUNT_URL_TEMPLATE,
|
||||||
|
new PageTitle(userName).getText()));
|
||||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||||
try {
|
try {
|
||||||
BufferedReader bufferedReader = new BufferedReader(new
|
BufferedReader bufferedReader = new BufferedReader(new
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ import fr.free.nrw.commons.LicenseList;
|
||||||
import fr.free.nrw.commons.Media;
|
import fr.free.nrw.commons.Media;
|
||||||
import fr.free.nrw.commons.MediaDataExtractor;
|
import fr.free.nrw.commons.MediaDataExtractor;
|
||||||
import fr.free.nrw.commons.MediaWikiImageView;
|
import fr.free.nrw.commons.MediaWikiImageView;
|
||||||
|
import fr.free.nrw.commons.PageTitle;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class MediaDetailFragment extends Fragment {
|
public class MediaDetailFragment extends Fragment {
|
||||||
|
|
@ -269,12 +269,11 @@ public class MediaDetailFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private View buildCatLabel(String cat) {
|
private View buildCatLabel(final String catName) {
|
||||||
final String catName = cat;
|
|
||||||
final View item = getLayoutInflater(null).inflate(R.layout.detail_category_item, null, false);
|
final View item = getLayoutInflater(null).inflate(R.layout.detail_category_item, null, false);
|
||||||
final TextView textView = (TextView)item.findViewById(R.id.mediaDetailCategoryItemText);
|
final TextView textView = (TextView)item.findViewById(R.id.mediaDetailCategoryItemText);
|
||||||
|
|
||||||
textView.setText(cat);
|
textView.setText(catName);
|
||||||
if (categoriesLoaded && categoriesPresent) {
|
if (categoriesLoaded && categoriesPresent) {
|
||||||
textView.setOnClickListener(new View.OnClickListener() {
|
textView.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -282,7 +281,7 @@ public class MediaDetailFragment extends Fragment {
|
||||||
String selectedCategoryTitle = "Category:" + catName;
|
String selectedCategoryTitle = "Category:" + catName;
|
||||||
Intent viewIntent = new Intent();
|
Intent viewIntent = new Intent();
|
||||||
viewIntent.setAction(Intent.ACTION_VIEW);
|
viewIntent.setAction(Intent.ACTION_VIEW);
|
||||||
viewIntent.setData(Utils.uriForWikiPage(selectedCategoryTitle));
|
viewIntent.setData(new PageTitle(selectedCategoryTitle).getCanonicalUri());
|
||||||
startActivity(viewIntent);
|
startActivity(viewIntent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ public class MediaDetailPagerFragment extends Fragment implements ViewPager.OnPa
|
||||||
// View in browser
|
// View in browser
|
||||||
Intent viewIntent = new Intent();
|
Intent viewIntent = new Intent();
|
||||||
viewIntent.setAction(Intent.ACTION_VIEW);
|
viewIntent.setAction(Intent.ACTION_VIEW);
|
||||||
viewIntent.setData(Uri.parse(m.getMobileDescriptionUrl()));
|
viewIntent.setData(m.getFilePageTitle().getMobileUri());
|
||||||
startActivity(viewIntent);
|
startActivity(viewIntent);
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_download_current_image:
|
case R.id.menu_download_current_image:
|
||||||
|
|
@ -227,7 +227,8 @@ public class MediaDetailPagerFragment extends Fragment implements ViewPager.OnPa
|
||||||
if (mShareActionProvider != null) {
|
if (mShareActionProvider != null) {
|
||||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||||
shareIntent.setType("text/plain");
|
shareIntent.setType("text/plain");
|
||||||
shareIntent.putExtra(Intent.EXTRA_TEXT, m.getDisplayTitle() + " \n" + m.getDescriptionUrl());
|
shareIntent.putExtra(Intent.EXTRA_TEXT,
|
||||||
|
m.getDisplayTitle() + " \n" + m.getFilePageTitle().getCanonicalUri());
|
||||||
mShareActionProvider.setShareIntent(shareIntent);
|
mShareActionProvider.setShareIntent(shareIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,8 +101,47 @@ public class NearbyActivity extends NavigationBaseActivity {
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||||
startLookingForNearby();
|
startLookingForNearby();
|
||||||
} else {
|
} else {
|
||||||
|
if (ContextCompat.checkSelfPermission(this,
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
|
||||||
|
// Should we show an explanation?
|
||||||
|
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||||
|
|
||||||
|
// Show an explanation to the user *asynchronously* -- don't block
|
||||||
|
// this thread waiting for the user's response! After the user
|
||||||
|
// sees the explanation, try again to request the permission.
|
||||||
|
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setMessage(getString(R.string.location_permission_rationale))
|
||||||
|
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
|
||||||
|
ActivityCompat.requestPermissions(NearbyActivity.this,
|
||||||
|
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
|
||||||
|
LOCATION_REQUEST);
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton("Cancel", null)
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// No explanation needed, we can request the permission.
|
||||||
|
|
||||||
ActivityCompat.requestPermissions(this,
|
ActivityCompat.requestPermissions(this,
|
||||||
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_REQUEST);
|
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
|
||||||
|
LOCATION_REQUEST);
|
||||||
|
|
||||||
|
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
|
||||||
|
// app-defined int constant. The callback method gets the
|
||||||
|
// result of the request.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
startLookingForNearby();
|
startLookingForNearby();
|
||||||
|
|
@ -279,7 +318,7 @@ public class NearbyActivity extends NavigationBaseActivity {
|
||||||
Fragment fragment = new NearbyMapFragment();
|
Fragment fragment = new NearbyMapFragment();
|
||||||
fragment.setArguments(bundle);
|
fragment.setArguments(bundle);
|
||||||
fragmentTransaction.replace(R.id.container, fragment);
|
fragmentTransaction.replace(R.id.container, fragment);
|
||||||
fragmentTransaction.commit();
|
fragmentTransaction.commitAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -290,7 +329,7 @@ public class NearbyActivity extends NavigationBaseActivity {
|
||||||
Fragment fragment = new NearbyListFragment();
|
Fragment fragment = new NearbyListFragment();
|
||||||
fragment.setArguments(bundle);
|
fragment.setArguments(bundle);
|
||||||
fragmentTransaction.replace(R.id.container, fragment);
|
fragmentTransaction.replace(R.id.container, fragment);
|
||||||
fragmentTransaction.commit();
|
fragmentTransaction.commitAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void startYourself(Context context) {
|
public static void startYourself(Context context) {
|
||||||
|
|
|
||||||
|
|
@ -198,5 +198,6 @@ Tap this message (or hit back) to skip this step.</string>
|
||||||
<string name="no_description_found">no description found</string>
|
<string name="no_description_found">no description found</string>
|
||||||
<string name="nearby_info_menu_commons_article">Commons Article</string>
|
<string name="nearby_info_menu_commons_article">Commons Article</string>
|
||||||
<string name="nearby_info_menu_wikidata_article">Wikidata item</string>
|
<string name="nearby_info_menu_wikidata_article">Wikidata item</string>
|
||||||
|
<string name="error_while_cache">Error while caching pictures</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package fr.free.nrw.commons;
|
package fr.free.nrw.commons;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
|
||||||
public class UtilsTest {
|
public class UtilsTest {
|
||||||
@Test public void stripLocalizedStringPass() {
|
@Test public void stripLocalizedStringPass() {
|
||||||
Assert.assertThat(Utils.stripLocalizedString("Hello"), is("Hello"));
|
Assert.assertThat(Utils.stripLocalizedString("Hello"), is("Hello"));
|
||||||
|
|
@ -13,4 +13,20 @@ public class UtilsTest {
|
||||||
@Test public void stripLocalizedStringJa() {
|
@Test public void stripLocalizedStringJa() {
|
||||||
Assert.assertThat(Utils.stripLocalizedString("\"こんにちは\"@ja"), is("こんにちは"));
|
Assert.assertThat(Utils.stripLocalizedString("\"こんにちは\"@ja"), is("こんにちは"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void capitalizeLowercase() {
|
||||||
|
Assert.assertThat(Utils.capitalize("hello"), is("Hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void capitalizeFullCaps() {
|
||||||
|
Assert.assertThat(Utils.capitalize("HELLO"), is("HELLO"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void capitalizeNumbersPass() {
|
||||||
|
Assert.assertThat(Utils.capitalize("12x"), is("12x"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void capitalizeJaPass() {
|
||||||
|
Assert.assertThat(Utils.capitalize("こんにちは"), is("こんにちは"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue