mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 04:43:54 +01:00
Moved single-use code out of Utils over to where it's actually used.
This commit is contained in:
parent
388f588301
commit
d0a85dbd82
12 changed files with 184 additions and 217 deletions
|
|
@ -144,12 +144,6 @@ public class CommonsApplication extends DaggerApplication {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean deviceHasCamera() {
|
|
||||||
PackageManager pm = getPackageManager();
|
|
||||||
return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA) ||
|
|
||||||
pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearApplicationData(Context context) {
|
public void clearApplicationData(Context context) {
|
||||||
File cacheDirectory = context.getCacheDir();
|
File cacheDirectory = context.getCacheDir();
|
||||||
File applicationDirectory = new File(cacheDirectory.getParent());
|
File applicationDirectory = new File(cacheDirectory.getParent());
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ import android.content.res.Resources;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
@ -21,7 +23,7 @@ public class LicenseList {
|
||||||
public LicenseList(Activity activity) {
|
public LicenseList(Activity activity) {
|
||||||
res = activity.getResources();
|
res = activity.getResources();
|
||||||
XmlPullParser parser = res.getXml(R.xml.wikimedia_licenses);
|
XmlPullParser parser = res.getXml(R.xml.wikimedia_licenses);
|
||||||
while (Utils.xmlFastForward(parser, XMLNS_LICENSE, "license")) {
|
while (xmlFastForward(parser, XMLNS_LICENSE, "license")) {
|
||||||
String id = parser.getAttributeValue(null, "id");
|
String id = parser.getAttributeValue(null, "id");
|
||||||
String template = parser.getAttributeValue(null, "template");
|
String template = parser.getAttributeValue(null, "template");
|
||||||
String url = parser.getAttributeValue(null, "url");
|
String url = parser.getAttributeValue(null, "url");
|
||||||
|
|
@ -76,4 +78,34 @@ public class LicenseList {
|
||||||
}
|
}
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fast-forward an XmlPullParser to the next instance of the given element
|
||||||
|
* in the input stream (namespaced).
|
||||||
|
*
|
||||||
|
* @param parser
|
||||||
|
* @param namespace
|
||||||
|
* @param element
|
||||||
|
* @return true on match, false on failure
|
||||||
|
*/
|
||||||
|
private boolean xmlFastForward(XmlPullParser parser, String namespace, String element) {
|
||||||
|
try {
|
||||||
|
while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||||
|
if (parser.getEventType() == XmlPullParser.START_TAG &&
|
||||||
|
parser.getNamespace().equals(namespace) &&
|
||||||
|
parser.getName().equals(element)) {
|
||||||
|
// We found it!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (XmlPullParserException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,26 +1,10 @@
|
||||||
package fr.free.nrw.commons;
|
package fr.free.nrw.commons;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.text.Html;
|
|
||||||
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.w3c.dom.Node;
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
@ -29,70 +13,10 @@ import java.util.TimeZone;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.xml.transform.Transformer;
|
|
||||||
import javax.xml.transform.TransformerConfigurationException;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import javax.xml.transform.TransformerFactory;
|
|
||||||
import javax.xml.transform.TransformerFactoryConfigurationError;
|
|
||||||
import javax.xml.transform.dom.DOMSource;
|
|
||||||
import javax.xml.transform.stream.StreamResult;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.settings.Prefs;
|
import fr.free.nrw.commons.settings.Prefs;
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
|
||||||
// Get SHA1 of file from input stream
|
|
||||||
public static String getSHA1(InputStream is) {
|
|
||||||
|
|
||||||
MessageDigest digest;
|
|
||||||
try {
|
|
||||||
digest = MessageDigest.getInstance("SHA1");
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
Timber.e(e, "Exception while getting Digest");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] buffer = new byte[8192];
|
|
||||||
int read;
|
|
||||||
try {
|
|
||||||
while ((read = is.read(buffer)) > 0) {
|
|
||||||
digest.update(buffer, 0, read);
|
|
||||||
}
|
|
||||||
byte[] md5sum = digest.digest();
|
|
||||||
BigInteger bigInt = new BigInteger(1, md5sum);
|
|
||||||
String output = bigInt.toString(16);
|
|
||||||
// Fill to 40 chars
|
|
||||||
output = String.format("%40s", output).replace(' ', '0');
|
|
||||||
Timber.i("File SHA1: %s", output);
|
|
||||||
|
|
||||||
return output;
|
|
||||||
} catch (IOException e) {
|
|
||||||
Timber.e(e, "IO Exception");
|
|
||||||
return "";
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
is.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Timber.e(e, "Exception on closing MD5 input stream");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Fix Html.fromHtml is deprecated problem
|
|
||||||
* @param source provided Html string
|
|
||||||
* @return returned Spanned of appropriate method according to version check
|
|
||||||
* */
|
|
||||||
public static Spanned fromHtml(String source) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
return Html.fromHtml(source, Html.FROM_HTML_MODE_LEGACY);
|
|
||||||
} else {
|
|
||||||
//noinspection deprecation
|
|
||||||
return Html.fromHtml(source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strips localization symbols from a string.
|
* Strips localization symbols from a string.
|
||||||
* Removes the suffix after "@" and quotes.
|
* Removes the suffix after "@" and quotes.
|
||||||
|
|
@ -109,49 +33,12 @@ public class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Date parseMWDate(String mwDate) {
|
|
||||||
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH); // Assuming MW always gives me UTC
|
|
||||||
try {
|
|
||||||
return isoFormat.parse(mwDate);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String toMWDate(Date date) {
|
|
||||||
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH); // Assuming MW always gives me UTC
|
|
||||||
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
|
||||||
return isoFormat.format(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String makeThumbBaseUrl(String filename) {
|
public static String makeThumbBaseUrl(String filename) {
|
||||||
String name = new PageTitle(filename).getPrefixedText();
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getStringFromDOM(Node dom) {
|
|
||||||
Transformer transformer = null;
|
|
||||||
try {
|
|
||||||
transformer = TransformerFactory.newInstance().newTransformer();
|
|
||||||
} catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
StringWriter outputStream = new StringWriter();
|
|
||||||
DOMSource domSource = new DOMSource(dom);
|
|
||||||
StreamResult strResult = new StreamResult(outputStream);
|
|
||||||
|
|
||||||
try {
|
|
||||||
transformer.transform(domSource, strResult);
|
|
||||||
} catch (TransformerException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return outputStream.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String urlEncode(String url) {
|
public static String urlEncode(String url) {
|
||||||
try {
|
try {
|
||||||
return URLEncoder.encode(url, "utf-8");
|
return URLEncoder.encode(url, "utf-8");
|
||||||
|
|
@ -160,39 +47,10 @@ public class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long countBytes(InputStream stream) throws IOException {
|
|
||||||
long count = 0;
|
|
||||||
BufferedInputStream bis = new BufferedInputStream(stream);
|
|
||||||
while (bis.read() != -1) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String capitalize(String string) {
|
public static String capitalize(String string) {
|
||||||
return string.substring(0, 1).toUpperCase(Locale.getDefault()) + string.substring(1);
|
return string.substring(0, 1).toUpperCase(Locale.getDefault()) + string.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String licenseTemplateFor(String license) {
|
|
||||||
switch (license) {
|
|
||||||
case Prefs.Licenses.CC_BY_3:
|
|
||||||
return "{{self|cc-by-3.0}}";
|
|
||||||
case Prefs.Licenses.CC_BY_4:
|
|
||||||
return "{{self|cc-by-4.0}}";
|
|
||||||
case Prefs.Licenses.CC_BY_SA_3:
|
|
||||||
return "{{self|cc-by-sa-3.0}}";
|
|
||||||
case Prefs.Licenses.CC_BY_SA_4:
|
|
||||||
return "{{self|cc-by-sa-4.0}}";
|
|
||||||
case Prefs.Licenses.CC0:
|
|
||||||
return "{{self|cc-zero}}";
|
|
||||||
case Prefs.Licenses.CC_BY:
|
|
||||||
return "{{self|cc-by-3.0}}";
|
|
||||||
case Prefs.Licenses.CC_BY_SA:
|
|
||||||
return "{{self|cc-by-sa-3.0}}";
|
|
||||||
}
|
|
||||||
throw new RuntimeException("Unrecognized license value: " + license);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int licenseNameFor(String license) {
|
public static int licenseNameFor(String license) {
|
||||||
switch (license) {
|
switch (license) {
|
||||||
case Prefs.Licenses.CC_BY_3:
|
case Prefs.Licenses.CC_BY_3:
|
||||||
|
|
@ -213,51 +71,6 @@ public class Utils {
|
||||||
throw new RuntimeException("Unrecognized license value: " + license);
|
throw new RuntimeException("Unrecognized license value: " + license);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String licenseUrlFor(String license) {
|
|
||||||
switch (license) {
|
|
||||||
case Prefs.Licenses.CC_BY_3:
|
|
||||||
return "https://creativecommons.org/licenses/by/3.0/";
|
|
||||||
case Prefs.Licenses.CC_BY_4:
|
|
||||||
return "https://creativecommons.org/licenses/by/4.0/";
|
|
||||||
case Prefs.Licenses.CC_BY_SA_3:
|
|
||||||
return "https://creativecommons.org/licenses/by-sa/3.0/";
|
|
||||||
case Prefs.Licenses.CC_BY_SA_4:
|
|
||||||
return "https://creativecommons.org/licenses/by-sa/4.0/";
|
|
||||||
case Prefs.Licenses.CC0:
|
|
||||||
return "https://creativecommons.org/publicdomain/zero/1.0/";
|
|
||||||
}
|
|
||||||
throw new RuntimeException("Unrecognized license value: " + license);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fast-forward an XmlPullParser to the next instance of the given element
|
|
||||||
* in the input stream (namespaced).
|
|
||||||
*
|
|
||||||
* @param parser
|
|
||||||
* @param namespace
|
|
||||||
* @param element
|
|
||||||
* @return true on match, false on failure
|
|
||||||
*/
|
|
||||||
public static boolean xmlFastForward(XmlPullParser parser, String namespace, String element) {
|
|
||||||
try {
|
|
||||||
while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
|
||||||
if (parser.getEventType() == XmlPullParser.START_TAG &&
|
|
||||||
parser.getNamespace().equals(namespace) &&
|
|
||||||
parser.getName().equals(element)) {
|
|
||||||
// We found it!
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} catch (XmlPullParserException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fixExtension(String title, String extension) {
|
public static String fixExtension(String title, String extension) {
|
||||||
Pattern jpegPattern = Pattern.compile("\\.jpeg$", Pattern.CASE_INSENSITIVE);
|
Pattern jpegPattern = Pattern.compile("\\.jpeg$", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
|
@ -272,8 +85,4 @@ public class Utils {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isNullOrWhiteSpace(String value) {
|
|
||||||
return value == null || value.trim().isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
|
@ -16,7 +17,6 @@ import java.util.Locale;
|
||||||
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.Media;
|
import fr.free.nrw.commons.Media;
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
import fr.free.nrw.commons.settings.Prefs;
|
import fr.free.nrw.commons.settings.Prefs;
|
||||||
|
|
||||||
public class Contribution extends Media {
|
public class Contribution extends Media {
|
||||||
|
|
@ -149,7 +149,7 @@ public class Contribution extends Media {
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append("== {{int:license-header}} ==\n")
|
buffer.append("== {{int:license-header}} ==\n")
|
||||||
.append(Utils.licenseTemplateFor(getLicense())).append("\n\n")
|
.append(licenseTemplateFor(getLicense())).append("\n\n")
|
||||||
.append("{{Uploaded from Mobile|platform=Android|version=").append(BuildConfig.VERSION_NAME).append("}}\n")
|
.append("{{Uploaded from Mobile|platform=Android|version=").append(BuildConfig.VERSION_NAME).append("}}\n")
|
||||||
.append(getTrackingTemplates());
|
.append(getTrackingTemplates());
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
|
|
@ -377,4 +377,25 @@ public class Contribution extends Media {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private String licenseTemplateFor(String license) {
|
||||||
|
switch (license) {
|
||||||
|
case Prefs.Licenses.CC_BY_3:
|
||||||
|
return "{{self|cc-by-3.0}}";
|
||||||
|
case Prefs.Licenses.CC_BY_4:
|
||||||
|
return "{{self|cc-by-4.0}}";
|
||||||
|
case Prefs.Licenses.CC_BY_SA_3:
|
||||||
|
return "{{self|cc-by-sa-3.0}}";
|
||||||
|
case Prefs.Licenses.CC_BY_SA_4:
|
||||||
|
return "{{self|cc-by-sa-4.0}}";
|
||||||
|
case Prefs.Licenses.CC0:
|
||||||
|
return "{{self|cc-zero}}";
|
||||||
|
case Prefs.Licenses.CC_BY:
|
||||||
|
return "{{self|cc-by-3.0}}";
|
||||||
|
case Prefs.Licenses.CC_BY_SA:
|
||||||
|
return "{{self|cc-by-sa-3.0}}";
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Unrecognized license value: " + license);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -196,11 +196,17 @@ public class ContributionsListFragment extends DaggerFragment {
|
||||||
menu.clear(); // See http://stackoverflow.com/a/8495697/17865
|
menu.clear(); // See http://stackoverflow.com/a/8495697/17865
|
||||||
inflater.inflate(R.menu.fragment_contributions_list, menu);
|
inflater.inflate(R.menu.fragment_contributions_list, menu);
|
||||||
|
|
||||||
if (!application.deviceHasCamera()) {
|
if (!deviceHasCamera()) {
|
||||||
menu.findItem(R.id.menu_from_camera).setEnabled(false);
|
menu.findItem(R.id.menu_from_camera).setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean deviceHasCamera() {
|
||||||
|
PackageManager pm = getContext().getPackageManager();
|
||||||
|
return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA) ||
|
||||||
|
pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,12 @@ import android.os.RemoteException;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
|
@ -130,7 +133,13 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prefs.edit().putString("lastSyncTimestamp", Utils.toMWDate(curTime)).apply();
|
prefs.edit().putString("lastSyncTimestamp", toMWDate(curTime)).apply();
|
||||||
Timber.d("Oh hai, everyone! Look, a kitty!");
|
Timber.d("Oh hai, everyone! Look, a kitty!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String toMWDate(Date date) {
|
||||||
|
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH); // Assuming MW always gives me UTC
|
||||||
|
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
|
return isoFormat.format(date);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import java.io.IOException;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
import fr.free.nrw.commons.CommonsApplication;
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
import fr.free.nrw.commons.contributions.Contribution;
|
import fr.free.nrw.commons.contributions.Contribution;
|
||||||
import fr.free.nrw.commons.contributions.ContributionsContentProvider;
|
import fr.free.nrw.commons.contributions.ContributionsContentProvider;
|
||||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||||
|
|
@ -59,7 +58,7 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.isNullOrWhiteSpace(authCookie)) {
|
if (isNullOrWhiteSpace(authCookie)) {
|
||||||
Timber.d("Could not authenticate :(");
|
Timber.d("Could not authenticate :(");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -133,4 +132,8 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isNullOrWhiteSpace(String value) {
|
||||||
|
return value == null || value.trim().isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ import org.mediawiki.api.MWApi;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
@ -33,7 +35,6 @@ import java.util.Locale;
|
||||||
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
import fr.free.nrw.commons.BuildConfig;
|
||||||
import fr.free.nrw.commons.PageTitle;
|
import fr.free.nrw.commons.PageTitle;
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
import in.yuvi.http.fluent.Http;
|
import in.yuvi.http.fluent.Http;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
|
@ -337,7 +338,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
||||||
logEvents.add(new LogEventResult.LogEvent(
|
logEvents.add(new LogEventResult.LogEvent(
|
||||||
image.getString("@pageid"),
|
image.getString("@pageid"),
|
||||||
image.getString("@title"),
|
image.getString("@title"),
|
||||||
Utils.parseMWDate(image.getString("@timestamp")))
|
parseMWDate(image.getString("@timestamp")))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return logEvents;
|
return logEvents;
|
||||||
|
|
@ -399,7 +400,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
||||||
String errorCode = result.getString("/api/error/@code");
|
String errorCode = result.getString("/api/error/@code");
|
||||||
return new UploadResult(resultStatus, errorCode);
|
return new UploadResult(resultStatus, errorCode);
|
||||||
} else {
|
} else {
|
||||||
Date dateUploaded = Utils.parseMWDate(result.getString("/api/upload/imageinfo/@timestamp"));
|
Date dateUploaded = parseMWDate(result.getString("/api/upload/imageinfo/@timestamp"));
|
||||||
String canonicalFilename = "File:" + result.getString("/api/upload/@filename").replace("_", " "); // Title vs Filename
|
String canonicalFilename = "File:" + result.getString("/api/upload/@filename").replace("_", " "); // Title vs Filename
|
||||||
String imageUrl = result.getString("/api/upload/imageinfo/@url");
|
String imageUrl = result.getString("/api/upload/imageinfo/@url");
|
||||||
return new UploadResult(resultStatus, dateUploaded, canonicalFilename, imageUrl);
|
return new UploadResult(resultStatus, dateUploaded, canonicalFilename, imageUrl);
|
||||||
|
|
@ -425,4 +426,13 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
||||||
return Integer.parseInt(uploadCount);
|
return Integer.parseInt(uploadCount);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Date parseMWDate(String mwDate) {
|
||||||
|
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH); // Assuming MW always gives me UTC
|
||||||
|
try {
|
||||||
|
return isoFormat.parse(mwDate);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
package fr.free.nrw.commons.ui.widget;
|
package fr.free.nrw.commons.ui.widget;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
import android.support.v7.widget.AppCompatTextView;
|
import android.support.v7.widget.AppCompatTextView;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link AppCompatTextView} which formats the text to HTML displayable text and makes any
|
* An {@link AppCompatTextView} which formats the text to HTML displayable text and makes any
|
||||||
* links clickable.
|
* links clickable.
|
||||||
|
|
@ -17,10 +18,25 @@ public class HtmlTextView extends AppCompatTextView {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
setMovementMethod(LinkMovementMethod.getInstance());
|
setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
setText(Utils.fromHtml(getText().toString()));
|
setText(fromHtml(getText().toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHtmlText(String newText) {
|
public void setHtmlText(String newText) {
|
||||||
setText(Utils.fromHtml(newText));
|
setText(fromHtml(newText));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix Html.fromHtml is deprecated problem
|
||||||
|
*
|
||||||
|
* @param source provided Html string
|
||||||
|
* @return returned Spanned of appropriate method according to version check
|
||||||
|
*/
|
||||||
|
private static Spanned fromHtml(String source) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
return Html.fromHtml(source, Html.FROM_HTML_MODE_LEGACY);
|
||||||
|
} else {
|
||||||
|
//noinspection deprecation
|
||||||
|
return Html.fromHtml(source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@ import com.facebook.drawee.view.SimpleDraweeView;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -35,7 +38,6 @@ import javax.inject.Inject;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
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.auth.AuthenticatedActivity;
|
import fr.free.nrw.commons.auth.AuthenticatedActivity;
|
||||||
import fr.free.nrw.commons.caching.CacheController;
|
import fr.free.nrw.commons.caching.CacheController;
|
||||||
import fr.free.nrw.commons.category.CategorizationFragment;
|
import fr.free.nrw.commons.category.CategorizationFragment;
|
||||||
|
|
@ -380,7 +382,7 @@ public class ShareActivity
|
||||||
try {
|
try {
|
||||||
InputStream inputStream = getContentResolver().openInputStream(mediaUri);
|
InputStream inputStream = getContentResolver().openInputStream(mediaUri);
|
||||||
Timber.d("Input stream created from %s", mediaUri.toString());
|
Timber.d("Input stream created from %s", mediaUri.toString());
|
||||||
String fileSHA1 = Utils.getSHA1(inputStream);
|
String fileSHA1 = getSHA1(inputStream);
|
||||||
Timber.d("File SHA1 is: %s", fileSHA1);
|
Timber.d("File SHA1 is: %s", fileSHA1);
|
||||||
|
|
||||||
ExistingFileAsync fileAsyncTask =
|
ExistingFileAsync fileAsyncTask =
|
||||||
|
|
@ -536,4 +538,41 @@ public class ShareActivity
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get SHA1 of file from input stream
|
||||||
|
private String getSHA1(InputStream is) {
|
||||||
|
|
||||||
|
MessageDigest digest;
|
||||||
|
try {
|
||||||
|
digest = MessageDigest.getInstance("SHA1");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
Timber.e(e, "Exception while getting Digest");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int read;
|
||||||
|
try {
|
||||||
|
while ((read = is.read(buffer)) > 0) {
|
||||||
|
digest.update(buffer, 0, read);
|
||||||
|
}
|
||||||
|
byte[] md5sum = digest.digest();
|
||||||
|
BigInteger bigInt = new BigInteger(1, md5sum);
|
||||||
|
String output = bigInt.toString(16);
|
||||||
|
// Fill to 40 chars
|
||||||
|
output = String.format("%40s", output).replace(' ', '0');
|
||||||
|
Timber.i("File SHA1: %s", output);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Timber.e(e, "IO Exception");
|
||||||
|
return "";
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Timber.e(e, "Exception on closing MD5 input stream");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
|
@ -184,7 +184,7 @@ public class SingleUploadFragment extends DaggerFragment {
|
||||||
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.setAction(Intent.ACTION_VIEW);
|
intent.setAction(Intent.ACTION_VIEW);
|
||||||
intent.setData(Uri.parse(Utils.licenseUrlFor(license)));
|
intent.setData(Uri.parse(licenseUrlFor(license)));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -280,6 +280,23 @@ public class SingleUploadFragment extends DaggerFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private String licenseUrlFor(String license) {
|
||||||
|
switch (license) {
|
||||||
|
case Prefs.Licenses.CC_BY_3:
|
||||||
|
return "https://creativecommons.org/licenses/by/3.0/";
|
||||||
|
case Prefs.Licenses.CC_BY_4:
|
||||||
|
return "https://creativecommons.org/licenses/by/4.0/";
|
||||||
|
case Prefs.Licenses.CC_BY_SA_3:
|
||||||
|
return "https://creativecommons.org/licenses/by-sa/3.0/";
|
||||||
|
case Prefs.Licenses.CC_BY_SA_4:
|
||||||
|
return "https://creativecommons.org/licenses/by-sa/4.0/";
|
||||||
|
case Prefs.Licenses.CC0:
|
||||||
|
return "https://creativecommons.org/publicdomain/zero/1.0/";
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Unrecognized license value: " + license);
|
||||||
|
}
|
||||||
|
|
||||||
private class TitleTextWatcher implements TextWatcher {
|
private class TitleTextWatcher implements TextWatcher {
|
||||||
@Override
|
@Override
|
||||||
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { }
|
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { }
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,14 @@ import android.preference.PreferenceManager;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
import fr.free.nrw.commons.CommonsApplication;
|
||||||
import fr.free.nrw.commons.HandlerService;
|
import fr.free.nrw.commons.HandlerService;
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
import fr.free.nrw.commons.contributions.Contribution;
|
import fr.free.nrw.commons.contributions.Contribution;
|
||||||
import fr.free.nrw.commons.settings.Prefs;
|
import fr.free.nrw.commons.settings.Prefs;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
@ -109,7 +110,7 @@ public class UploadController {
|
||||||
.getLength();
|
.getLength();
|
||||||
if(length == -1) {
|
if(length == -1) {
|
||||||
// Let us find out the long way!
|
// Let us find out the long way!
|
||||||
length = Utils.countBytes(application.getContentResolver()
|
length = countBytes(application.getContentResolver()
|
||||||
.openInputStream(contribution.getLocalUri()));
|
.openInputStream(contribution.getLocalUri()));
|
||||||
}
|
}
|
||||||
contribution.setDataLength(length);
|
contribution.setDataLength(length);
|
||||||
|
|
@ -165,4 +166,14 @@ public class UploadController {
|
||||||
}
|
}
|
||||||
}.executeOnExecutor(Executors.newFixedThreadPool(1)); // TODO remove this by using a sensible thread handling strategy
|
}.executeOnExecutor(Executors.newFixedThreadPool(1)); // TODO remove this by using a sensible thread handling strategy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private long countBytes(InputStream stream) throws IOException {
|
||||||
|
long count = 0;
|
||||||
|
BufferedInputStream bis = new BufferedInputStream(stream);
|
||||||
|
while (bis.read() != -1) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue