mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
Merge 4.0-release into master (#5028)
* Fix string for custom selector * Fix bug #4950 back arrow still present on top-level activity (#4952) * Fix bug #4949 by correctly setting previous db version number (#4956) * Fix bug #4949 by correctly setting previous db version number * Fix failing tests * Fix bug #4959 by correctly setting previous db version number and updating the current db version (#4960) * Fix bug #4957 (#4961) * Update library to new version that handles older Java VMs Fixes #4972 I believe. * Versioning for v4.0.0 * Changelog for v4.0.0 * Fix bug #4984 Added queries for package name for Android API 30+ (#4987) * Update mapbox sdk version (#4989) * Versioning for v4.0.1 * Changelog for v4.0.1 * Remove network type information from NetworkUtils (#4996) * Remove network type information from NetworkUtils * Ignore dependent tests * Fix #4992 invert the equals condition to be null safe (#4995) * Fix java.lang.NullPointerException for username in ContributionBoundaryCallback (#5003) * Fix failing tests for PR #5003 (#5004) * Fix java.lang.NullPointerException for username in ContributionBoundaryCallback * Fix failing tests * Update Room DB Version (#5011) * Fix #5001 (#5010) * Fix DB update issue (#5016) * [WIP] Fix both timezone problem and saved date problem (#5019) * Fix both timezone problem and saved date problem * Fixaccidental test code and add comments * Add issue link to the comments * Fix format issue and null checks * Versioning for v4.0.2 * Changelog for v4.0.2 * Add "Report Violation" menu option (#5025) * Add "Report Violation" menu option * Update email template * Update email address * Fixed typo Co-authored-by: Josephine Lim <josephinelim86@gmail.com> * Versioning for v4.0.3 * Changelog for v4.0.3 Co-authored-by: Josephine Lim <josephinelim86@gmail.com> Co-authored-by: Nicolas Raoul <nicolas.raoul@gmail.com> Co-authored-by: neslihanturan <tur.neslihan@gmail.com>
This commit is contained in:
parent
1de8968fa8
commit
3cdfdcffe1
29 changed files with 406 additions and 72 deletions
19
CHANGELOG.md
19
CHANGELOG.md
|
|
@ -1,5 +1,24 @@
|
|||
# Wikimedia Commons for Android
|
||||
|
||||
## v4.0.3
|
||||
- Added "Report" button for Google UGC policy
|
||||
|
||||
## v4.0.2
|
||||
- Fixed bug with wrong dates taken from EXIF
|
||||
- Fixed various crashes
|
||||
|
||||
## v4.0.1
|
||||
- Fixed bug with no browser found
|
||||
- Updated Mapbox SDK to fix hamburger crash
|
||||
|
||||
## v4.0.0
|
||||
- Added map showing nearby Commons pictures
|
||||
- Added custom SPARQL queries
|
||||
- Added user profiles
|
||||
- Added custom picture selector
|
||||
- Various bugfixes
|
||||
- Updated target SDK to 30
|
||||
|
||||
## v3.1.1
|
||||
- Optimized Nearby query
|
||||
- Added Sweden's property for WLM 2021
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ dependencies {
|
|||
implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1.1@aar'
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.0.0'
|
||||
implementation 'com.github.pedrovgs:renderers:3.3.3'
|
||||
implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:9.1.0'
|
||||
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-localization-v8:0.11.0'
|
||||
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-scalebar-v9:0.4.0'
|
||||
implementation 'com.mapbox.mapboxsdk:mapbox-android-telemetry:6.1.0'
|
||||
implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:9.2.1'
|
||||
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-localization-v9:0.12.0'
|
||||
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-scalebar-v9:0.5.0'
|
||||
implementation 'com.mapbox.mapboxsdk:mapbox-android-telemetry:7.0.0'
|
||||
implementation 'com.github.deano2390:MaterialShowcaseView:1.2.0'
|
||||
implementation 'com.dinuscxj:circleprogressbar:1.1.1'
|
||||
implementation 'com.karumi:dexter:5.0.0'
|
||||
|
|
@ -173,8 +173,8 @@ android {
|
|||
defaultConfig {
|
||||
//applicationId 'fr.free.nrw.commons'
|
||||
|
||||
versionCode 1025
|
||||
versionName '3.1.1'
|
||||
versionCode 1029
|
||||
versionName '4.0.3'
|
||||
setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName())
|
||||
|
||||
minSdkVersion 19
|
||||
|
|
|
|||
|
|
@ -18,6 +18,16 @@
|
|||
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<queries>
|
||||
<!-- Browser -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https" />
|
||||
</intent>
|
||||
<!-- Google Maps -->
|
||||
<package android:name="com.google.android.apps.maps" />
|
||||
</queries>
|
||||
|
||||
|
||||
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
|
||||
|
|
|
|||
|
|
@ -110,6 +110,10 @@ public class CommonsApplication extends MultiDexApplication {
|
|||
|
||||
public static final String FEEDBACK_EMAIL_SUBJECT = "Commons Android App Feedback";
|
||||
|
||||
public static final String REPORT_EMAIL = "commons-app-android-private@googlegroups.com";
|
||||
|
||||
public static final String REPORT_EMAIL_SUBJECT = "Report a violation";
|
||||
|
||||
public static final String NOTIFICATION_CHANNEL_ID_ALL = "CommonsNotificationAll";
|
||||
|
||||
public static final String FEEDBACK_EMAIL_TEMPLATE_HEADER = "-- Technical information --";
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa
|
|||
addCredits();
|
||||
getToolbarUI();
|
||||
|
||||
if (activity.equals("UploadActivity")) {
|
||||
if ("UploadActivity".equals(activity)) {
|
||||
placeSelectedButton.setVisibility(View.GONE);
|
||||
modifyLocationButton.setVisibility(View.VISIBLE);
|
||||
showInMapButton.setVisibility(View.VISIBLE);
|
||||
|
|
|
|||
|
|
@ -309,22 +309,18 @@ public class BookmarkItemsDao {
|
|||
if (from == to) {
|
||||
return;
|
||||
}
|
||||
if (from < 7) {
|
||||
if (from < 18) {
|
||||
// doesn't exist yet
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (from == 7) {
|
||||
if (from == 18) {
|
||||
// table added in version 19
|
||||
onCreate(db);
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (from == 8) {
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,10 +93,12 @@ public class CategoryDao {
|
|||
// fixme add a limit on the original query instead of falling out of the loop?
|
||||
while (cursor != null && cursor.moveToNext()
|
||||
&& cursor.getPosition() < limit) {
|
||||
if (fromCursor(cursor).getName() != null ) {
|
||||
items.add(new CategoryItem(fromCursor(cursor).getName(),
|
||||
fromCursor(cursor).getDescription(), fromCursor(cursor).getThumbnail(),
|
||||
false));
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
|
|
@ -193,6 +195,13 @@ public class CategoryDao {
|
|||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
if (from == 17) {
|
||||
db.execSQL("ALTER TABLE categories ADD COLUMN description STRING;");
|
||||
db.execSQL("ALTER TABLE categories ADD COLUMN thumbnail STRING;");
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import android.os.Parcelable
|
|||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class CategoryItem(val name: String, val description: String,
|
||||
val thumbnail: String, var isSelected: Boolean) : Parcelable {
|
||||
data class CategoryItem(val name: String, val description: String?,
|
||||
val thumbnail: String?, var isSelected: Boolean) : Parcelable {
|
||||
|
||||
override fun toString(): String {
|
||||
return "CategoryItem: '$name'"
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ data class Contribution constructor(
|
|||
val localUri: Uri? = null,
|
||||
var dataLength: Long = 0,
|
||||
var dateCreated: Date? = null,
|
||||
var dateCreatedString: String? = null,
|
||||
var dateModified: Date? = null,
|
||||
var hasInvalidLocation : Int = 0,
|
||||
var contentUri: Uri? = null,
|
||||
|
|
@ -70,6 +71,7 @@ data class Contribution constructor(
|
|||
depictedItems = depictedItems,
|
||||
wikidataPlace = from(item.place),
|
||||
contentUri = item.contentUri,
|
||||
dateCreatedString = item.fileCreatedDateString,
|
||||
imageSHA1 = imageSHA1
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class ContributionBoundaryCallback @Inject constructor(
|
|||
@param:Named(CommonsApplicationModule.IO_THREAD) private val ioThreadScheduler: Scheduler
|
||||
) : BoundaryCallback<Contribution>() {
|
||||
private val compositeDisposable: CompositeDisposable = CompositeDisposable()
|
||||
lateinit var userName: String
|
||||
var userName: String? = null
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -53,13 +53,13 @@ class ContributionBoundaryCallback @Inject constructor(
|
|||
/**
|
||||
* Fetches contributions using the MediaWiki API
|
||||
*/
|
||||
fun fetchContributions() {
|
||||
private fun fetchContributions() {
|
||||
if (sessionManager.userName != null) {
|
||||
compositeDisposable.add(
|
||||
mediaClient.getMediaListForUser(userName!!)
|
||||
userName?.let { userName ->
|
||||
mediaClient.getMediaListForUser(userName)
|
||||
.map { mediaList ->
|
||||
mediaList.map {
|
||||
Contribution(media = it, state = Contribution.STATE_COMPLETED)
|
||||
mediaList.map { media ->
|
||||
Contribution(media = media, state = Contribution.STATE_COMPLETED)
|
||||
}
|
||||
}
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
|
|
@ -69,11 +69,13 @@ class ContributionBoundaryCallback @Inject constructor(
|
|||
error.message
|
||||
)
|
||||
}
|
||||
}?.let {
|
||||
compositeDisposable.add(
|
||||
it
|
||||
)
|
||||
}else {
|
||||
if (compositeDisposable != null){
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
}else {
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -661,7 +661,7 @@ public class ContributionsFragment
|
|||
}
|
||||
|
||||
public boolean backButtonClicked() {
|
||||
if (null != mediaDetailPagerFragment && mediaDetailPagerFragment.isVisible()) {
|
||||
if (mediaDetailPagerFragment != null && mediaDetailPagerFragment.isVisible()) {
|
||||
if (store.getBoolean("displayNearbyCardView", true) && !isUserProfile) {
|
||||
if (nearbyNotificationCardView.cardViewVisibilityState == NearbyNotificationCardView.CardViewVisibilityState.READY) {
|
||||
nearbyNotificationCardView.setVisibility(View.VISIBLE);
|
||||
|
|
@ -680,6 +680,7 @@ public class ContributionsFragment
|
|||
}
|
||||
if (getActivity() instanceof MainActivity) {
|
||||
// Fragment is associated with MainActivity
|
||||
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||
((MainActivity) getActivity()).showTabs();
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@ import android.content.Context;
|
|||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao;
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao.Table;
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
||||
import fr.free.nrw.commons.category.CategoryDao;
|
||||
|
|
@ -16,7 +14,7 @@ import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao;
|
|||
public class DBOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String DATABASE_NAME = "commons.db";
|
||||
private static final int DATABASE_VERSION = 19;
|
||||
private static final int DATABASE_VERSION = 20;
|
||||
public static final String CONTRIBUTIONS_TABLE = "contributions";
|
||||
private final String DROP_TABLE_STATEMENT="DROP TABLE IF EXISTS %s";
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import fr.free.nrw.commons.upload.depicts.DepictsDao
|
|||
* The database for accessing the respective DAOs
|
||||
*
|
||||
*/
|
||||
@Database(entities = [Contribution::class, Depicts::class, UploadedStatus::class], version = 12, exportSchema = false)
|
||||
@Database(entities = [Contribution::class, Depicts::class, UploadedStatus::class], version = 13, exportSchema = false)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun contributionDao(): ContributionDao
|
||||
|
|
|
|||
|
|
@ -154,8 +154,7 @@ class DescriptionEditActivity : BaseActivity(), UploadMediaDetailAdapter.EventLi
|
|||
buffer.append("}}, ")
|
||||
}
|
||||
}
|
||||
buffer.deleteCharAt(buffer.length - 1)
|
||||
buffer.deleteCharAt(buffer.length - 1)
|
||||
buffer.replace(", $".toRegex(), "")
|
||||
buffer.append(descriptionEnd)
|
||||
}
|
||||
val returningIntent = Intent()
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import androidx.exifinterface.media.ExifInterface;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import fr.free.nrw.commons.upload.FileUtils;
|
||||
|
|
@ -124,13 +126,30 @@ public class UploadableFile implements Parcelable {
|
|||
private DateTimeWithSource getDateTimeFromExif() {
|
||||
try {
|
||||
ExifInterface exif = new ExifInterface(file.getAbsolutePath());
|
||||
@SuppressLint("RestrictedApi") Long dateTime = exif.getDateTime();
|
||||
// TAG_DATETIME returns the last edited date, we need TAG_DATETIME_ORIGINAL for creation date
|
||||
// See issue https://github.com/commons-app/apps-android-commons/issues/1971
|
||||
String dateTimeSubString = exif.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL);
|
||||
if (dateTimeSubString!=null) { //getAttribute may return null
|
||||
String year = dateTimeSubString.substring(0,4);
|
||||
String month = dateTimeSubString.substring(5,7);
|
||||
String day = dateTimeSubString.substring(8,10);
|
||||
// This date is stored as a string (not as a date), the rason is we don't want to include timezones
|
||||
String dateCreatedString = String.format("%04d-%02d-%02d", Integer.parseInt(year), Integer.parseInt(month), Integer.parseInt(day));
|
||||
if (dateCreatedString.length() == 10) { //yyyy-MM-dd format of date is expected
|
||||
@SuppressLint("RestrictedApi") Long dateTime = exif.getDateTimeOriginal();
|
||||
if(dateTime != null){
|
||||
Date date = new Date(dateTime);
|
||||
return new DateTimeWithSource(date, DateTimeWithSource.EXIF_SOURCE);
|
||||
return new DateTimeWithSource(date, dateCreatedString, DateTimeWithSource.EXIF_SOURCE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -149,6 +168,7 @@ public class UploadableFile implements Parcelable {
|
|||
public static final String EXIF_SOURCE = "exif";
|
||||
|
||||
private final long epochDate;
|
||||
private String dateString; // this does not includes timezone information
|
||||
private final String source;
|
||||
|
||||
public DateTimeWithSource(long epochDate, String source) {
|
||||
|
|
@ -161,10 +181,20 @@ public class UploadableFile implements Parcelable {
|
|||
this.source = source;
|
||||
}
|
||||
|
||||
public DateTimeWithSource(Date date, String dateString, String source) {
|
||||
this.epochDate = date.getTime();
|
||||
this.dateString = dateString;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public long getEpochDate() {
|
||||
return epochDate;
|
||||
}
|
||||
|
||||
public String getDateString() {
|
||||
return dateString;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package fr.free.nrw.commons.media;
|
|||
import static fr.free.nrw.commons.Utils.handleWebUrl;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -12,7 +13,9 @@ import android.view.MenuInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
|
@ -22,6 +25,7 @@ import androidx.viewpager.widget.ViewPager;
|
|||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
|
|
@ -33,7 +37,6 @@ import fr.free.nrw.commons.contributions.MainActivity;
|
|||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import fr.free.nrw.commons.profile.ProfileActivity;
|
||||
import fr.free.nrw.commons.theme.BaseActivity;
|
||||
import fr.free.nrw.commons.utils.DownloadUtils;
|
||||
import fr.free.nrw.commons.utils.ImageUtils;
|
||||
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||
|
|
@ -211,11 +214,83 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
ProfileActivity.startYourself(getActivity(), m.getUser(),
|
||||
!Objects.equals(sessionManager.getUserName(), m.getUser()));
|
||||
}
|
||||
return true;
|
||||
case R.id.menu_view_report:
|
||||
showReportDialog(m);
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void showReportDialog(final Media media) {
|
||||
if (media == null) {
|
||||
return;
|
||||
}
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
|
||||
final String[] values = requireContext().getResources()
|
||||
.getStringArray(R.array.report_violation_options);
|
||||
builder.setTitle(R.string.report_violation);
|
||||
builder.setItems(R.array.report_violation_options, (dialog, which) -> {
|
||||
sendReportEmail(media, values[which]);
|
||||
});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void sendReportEmail(final Media media, final String type) {
|
||||
final String technicalInfo = getTechInfo(media, type);
|
||||
|
||||
final Intent feedbackIntent = new Intent(Intent.ACTION_SENDTO);
|
||||
feedbackIntent.setType("message/rfc822");
|
||||
feedbackIntent.setData(Uri.parse("mailto:"));
|
||||
feedbackIntent.putExtra(Intent.EXTRA_EMAIL,
|
||||
new String[]{CommonsApplication.REPORT_EMAIL});
|
||||
feedbackIntent.putExtra(Intent.EXTRA_SUBJECT,
|
||||
CommonsApplication.REPORT_EMAIL_SUBJECT);
|
||||
feedbackIntent.putExtra(Intent.EXTRA_TEXT, technicalInfo);
|
||||
try {
|
||||
startActivity(feedbackIntent);
|
||||
} catch (final ActivityNotFoundException e) {
|
||||
Toast.makeText(getActivity(), R.string.no_email_client, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private String getTechInfo(final Media media, final String type) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("Report type: ")
|
||||
.append(type)
|
||||
.append("\n\n");
|
||||
|
||||
builder.append("Image that you want to report: ")
|
||||
.append(media.getImageUrl())
|
||||
.append("\n\n");
|
||||
|
||||
builder.append("User that you want to report: ")
|
||||
.append(media.getAuthor())
|
||||
.append("\n\n");
|
||||
|
||||
if (sessionManager.getUserName() != null) {
|
||||
builder.append("Your username: ")
|
||||
.append(sessionManager.getUserName())
|
||||
.append("\n\n");
|
||||
}
|
||||
|
||||
builder.append("Violation reason: ")
|
||||
.append("\n");
|
||||
|
||||
builder.append("----------------------------------------------")
|
||||
.append("\n")
|
||||
.append("(please write reason here)")
|
||||
.append("\n")
|
||||
.append("----------------------------------------------")
|
||||
.append("\n\n")
|
||||
.append("Thank you for your report! Our team will investigate as soon as possible.")
|
||||
.append("\n")
|
||||
.append("Please note that images also have a `Nominate for deletion` button.");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the media as the device's wallpaper if the imageUrl is not null
|
||||
* Fails silently if setting the wallpaper fails
|
||||
|
|
|
|||
|
|
@ -185,23 +185,17 @@ public class RecentLanguagesDao {
|
|||
if (from == to) {
|
||||
return;
|
||||
}
|
||||
if (from < 6) {
|
||||
if (from < 19) {
|
||||
// doesn't exist yet
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
if (from == 6) {
|
||||
// table added in version 7
|
||||
if (from == 19) {
|
||||
// table added in version 20
|
||||
onCreate(db);
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
if (from == 7) {
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class PageContentsCreator {
|
|||
.append(media.getAuthor()).append("]]\n");
|
||||
|
||||
final String templatizedCreatedDate = getTemplatizedCreatedDate(
|
||||
contribution.getDateCreated(), contribution.getDateCreatedSource());
|
||||
contribution.getDateCreatedString(), contribution.getDateCreated(), contribution.getDateCreatedSource());
|
||||
if (!StringUtils.isBlank(templatizedCreatedDate)) {
|
||||
buffer.append("|date=").append(templatizedCreatedDate);
|
||||
}
|
||||
|
|
@ -90,12 +90,12 @@ class PageContentsCreator {
|
|||
* @param dateCreatedSource
|
||||
* @return
|
||||
*/
|
||||
private String getTemplatizedCreatedDate(Date dateCreated, String dateCreatedSource) {
|
||||
private String getTemplatizedCreatedDate(String dateCreatedString, Date dateCreated, String dateCreatedSource) {
|
||||
if (dateCreated != null) {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
return String.format(Locale.ENGLISH,
|
||||
isExif(dateCreatedSource) ? TEMPLATE_DATE_ACC_TO_EXIF : TEMPLATE_DATA_OTHER_SOURCE,
|
||||
dateFormat.format(dateCreated)
|
||||
isExif(dateCreatedSource) ? dateCreatedString: dateFormat.format(dateCreated)
|
||||
) + "\n";
|
||||
}
|
||||
return "";
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ public class UploadItem {
|
|||
private boolean hasInvalidLocation;
|
||||
private boolean isWLMUpload = false;
|
||||
private String countryCode;
|
||||
private String fileCreatedDateString; //according to EXIF data
|
||||
|
||||
/**
|
||||
* Uri of uploadItem
|
||||
|
|
@ -40,7 +41,8 @@ public class UploadItem {
|
|||
final Place place,
|
||||
final long createdTimestamp,
|
||||
final String createdTimestampSource,
|
||||
final Uri contentUri) {
|
||||
final Uri contentUri,
|
||||
final String fileCreatedDateString) {
|
||||
this.createdTimestampSource = createdTimestampSource;
|
||||
uploadMediaDetails = new ArrayList<>(Collections.singletonList(new UploadMediaDetail()));
|
||||
this.place = place;
|
||||
|
|
@ -50,6 +52,7 @@ public class UploadItem {
|
|||
this.createdTimestamp = createdTimestamp;
|
||||
this.contentUri = contentUri;
|
||||
imageQuality = BehaviorSubject.createDefault(ImageUtils.IMAGE_WAIT);
|
||||
this.fileCreatedDateString = fileCreatedDateString;
|
||||
}
|
||||
|
||||
public String getCreatedTimestampSource() {
|
||||
|
|
@ -83,6 +86,8 @@ public class UploadItem {
|
|||
*/
|
||||
public Uri getContentUri() { return contentUri; }
|
||||
|
||||
public String getFileCreatedDateString() { return fileCreatedDateString; }
|
||||
|
||||
public void setImageQuality(final int imageQuality) {
|
||||
this.imageQuality.onNext(imageQuality);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,8 +102,10 @@ public class UploadModel {
|
|||
.getFileCreatedDate(context);
|
||||
long fileCreatedDate = -1;
|
||||
String createdTimestampSource = "";
|
||||
String fileCreatedDateString = "";
|
||||
if (dateTimeWithSource != null) {
|
||||
fileCreatedDate = dateTimeWithSource.getEpochDate();
|
||||
fileCreatedDateString = dateTimeWithSource.getDateString();
|
||||
createdTimestampSource = dateTimeWithSource.getSource();
|
||||
}
|
||||
Timber.d("File created date is %d", fileCreatedDate);
|
||||
|
|
@ -113,7 +115,8 @@ public class UploadModel {
|
|||
Uri.parse(uploadableFile.getFilePath()),
|
||||
uploadableFile.getMimeType(context), imageCoordinates, place, fileCreatedDate,
|
||||
createdTimestampSource,
|
||||
uploadableFile.getContentUri());
|
||||
uploadableFile.getContentUri(),
|
||||
fileCreatedDateString);
|
||||
if (place != null) {
|
||||
uploadItem.getUploadMediaDetails().set(0, new UploadMediaDetail(place));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,18 +148,16 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
ButterKnife.bind(this, view);
|
||||
if (callback != null) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
tvTitle.setText(getString(R.string.step_count, callback.getIndexInViewFlipper(this) + 1,
|
||||
callback.getTotalNumberOfSteps(), getString(R.string.media_detail_step_title)));
|
||||
tooltip.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showInfoAlert(R.string.media_detail_step_title, R.string.media_details_tooltip);
|
||||
}
|
||||
});
|
||||
tooltip.setOnClickListener(
|
||||
v -> showInfoAlert(R.string.media_detail_step_title, R.string.media_details_tooltip));
|
||||
initPresenter();
|
||||
presenter.receiveImage(uploadableFile, place);
|
||||
initRecyclerView();
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ public class NetworkUtils {
|
|||
return NetworkConnectionType.WIFI;
|
||||
}
|
||||
|
||||
// TODO for Android 12+ request permission from user is mandatory
|
||||
/*
|
||||
int mobileNetwork = telephonyManager.getNetworkType();
|
||||
switch (mobileNetwork) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||
|
|
@ -71,6 +73,8 @@ public class NetworkUtils {
|
|||
default:
|
||||
return NetworkConnectionType.UNKNOWN;
|
||||
}
|
||||
*/
|
||||
return NetworkConnectionType.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -34,5 +34,9 @@
|
|||
android:id="@+id/menu_view_user_page"
|
||||
android:title="@string/menu_view_user_page"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/menu_view_report"
|
||||
android:title="@string/menu_view_report"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
|
|
@ -70,5 +70,10 @@
|
|||
<item>yearly</item>
|
||||
<item>all_time</item>
|
||||
</string-array>
|
||||
<string-array name="report_violation_options" >
|
||||
<item>@string/report_user</item>
|
||||
<item>@string/report_content</item>
|
||||
<item>@string/request_user_block</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
|
@ -691,7 +691,7 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="done">Done</string>
|
||||
<string name="back">Back</string>
|
||||
<string name="welcome_custom_picture_selector_text">Welcome to Custom Picture Selector</string>
|
||||
<string name="custom_selector_info_text1">This picker shows differently pictures that are already to Commons.</string>
|
||||
<string name="custom_selector_info_text1">This picker shows you which pictures you have already uploaded to Commons.</string>
|
||||
<string name="custom_selector_info_text2">Unlike the picture on the left, the picture on the right has the Commons logo indicating it is already uploaded. \n Touch and hold for image preview.</string>
|
||||
<string name="welcome_custom_selector_ok">Awesome</string>
|
||||
<string name="custom_selector_already_uploaded_image_text">This image has already been uploaded to Commons.</string>
|
||||
|
|
@ -734,4 +734,9 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="error_feedback">Error while sending feedback</string>
|
||||
<string name="enter_description">What is your feedback?</string>
|
||||
<string name="your_feedback">Your feedback</string>
|
||||
<string name="menu_view_report">Report</string>
|
||||
<string name="report_violation">Report violation</string>
|
||||
<string name="report_user">Report this user</string>
|
||||
<string name="report_content">Report this content</string>
|
||||
<string name="request_user_block">Request to block this user</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -271,9 +271,84 @@ class BookmarkItemsDaoTest {
|
|||
@Test
|
||||
fun migrateTableVersionFrom_v7_to_v8() {
|
||||
onUpdate(database, 7, 8)
|
||||
// Table didn't change in version 8
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v8_to_v9() {
|
||||
onUpdate(database, 8, 9)
|
||||
// Table didn't change in version 9
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v9_to_v10() {
|
||||
onUpdate(database, 9, 10)
|
||||
// Table didn't change in version 10
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v10_to_v11() {
|
||||
onUpdate(database, 10, 11)
|
||||
// Table didn't change in version 11
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v11_to_v12() {
|
||||
onUpdate(database, 11, 12)
|
||||
// Table didn't change in version 12
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v12_to_v13() {
|
||||
onUpdate(database, 12, 13)
|
||||
// Table didn't change in version 13
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v13_to_v14() {
|
||||
onUpdate(database, 13, 14)
|
||||
// Table didn't change in version 14
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v14_to_v15() {
|
||||
onUpdate(database, 14, 15)
|
||||
// Table didn't change in version 15
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v15_to_v16() {
|
||||
onUpdate(database, 15, 16)
|
||||
// Table didn't change in version 16
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v16_to_v17() {
|
||||
onUpdate(database, 16, 17)
|
||||
// Table didn't change in version 17
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v18_to_v19() {
|
||||
onUpdate(database, 18, 19)
|
||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v19_to_v19() {
|
||||
onUpdate(database, 19, 19)
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
private fun createCursor(rowCount: Int) = MatrixCursor(columns, rowCount).apply {
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import org.mockito.ArgumentMatchers.anyString
|
|||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* The unit test class for ContributionBoundaryCallbackTest
|
||||
|
|
@ -95,7 +96,11 @@ class ContributionBoundaryCallbackTest {
|
|||
whenever(mediaClient.getMediaListForUser(anyString())).thenReturn(
|
||||
Single.just(listOf(media()))
|
||||
)
|
||||
contributionBoundaryCallback.fetchContributions()
|
||||
val method: Method = ContributionBoundaryCallback::class.java.getDeclaredMethod(
|
||||
"fetchContributions"
|
||||
)
|
||||
method.isAccessible = true
|
||||
method.invoke(contributionBoundaryCallback)
|
||||
verify(repository).save(anyList());
|
||||
verify(mediaClient).getMediaListForUser(anyString());
|
||||
}
|
||||
|
|
@ -104,7 +109,11 @@ class ContributionBoundaryCallbackTest {
|
|||
fun testFetchContributionsFailed() {
|
||||
whenever(sessionManager.userName).thenReturn("Test")
|
||||
whenever(mediaClient.getMediaListForUser(anyString())).thenReturn(Single.error(Exception("Error")))
|
||||
contributionBoundaryCallback.fetchContributions()
|
||||
val method: Method = ContributionBoundaryCallback::class.java.getDeclaredMethod(
|
||||
"fetchContributions"
|
||||
)
|
||||
method.isAccessible = true
|
||||
method.invoke(contributionBoundaryCallback)
|
||||
verifyZeroInteractions(repository);
|
||||
verify(mediaClient).getMediaListForUser(anyString());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,20 +177,103 @@ class RecentLanguagesDaoUnitTest {
|
|||
@Test
|
||||
fun migrateTableVersionFrom_v5_to_v6() {
|
||||
onUpdate(database, 5, 6)
|
||||
// Table didnt exist before v7
|
||||
// Table didnt exist in version 6
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v6_to_v7() {
|
||||
onUpdate(database, 6, 7)
|
||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
// Table didnt exist in version 7
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v7_to_v8() {
|
||||
onUpdate(database, 7, 8)
|
||||
// Table didnt change in version 8
|
||||
// Table didnt exist in version 8
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v8_to_v9() {
|
||||
onUpdate(database, 8, 9)
|
||||
// Table didnt exist in version 9
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v9_to_v10() {
|
||||
onUpdate(database, 9, 10)
|
||||
// Table didnt exist in version 10
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v10_to_v11() {
|
||||
onUpdate(database, 10, 11)
|
||||
// Table didnt exist in version 11
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v11_to_v12() {
|
||||
onUpdate(database, 11, 12)
|
||||
// Table didnt exist in version 12
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v12_to_v13() {
|
||||
onUpdate(database, 12, 13)
|
||||
// Table didnt exist in version 13
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v13_to_v14() {
|
||||
onUpdate(database, 13, 14)
|
||||
// Table didnt exist in version 14
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v14_to_v15() {
|
||||
onUpdate(database, 14, 15)
|
||||
// Table didnt exist in version 15
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v15_to_v16() {
|
||||
onUpdate(database, 15, 16)
|
||||
// Table didnt exist in version 16
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v16_to_v17() {
|
||||
onUpdate(database, 16, 17)
|
||||
// Table didnt exist in version 17
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v18_to_v19() {
|
||||
onUpdate(database, 18, 19)
|
||||
// Table didnt exist in version 18
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v19_to_v20() {
|
||||
onUpdate(database, 19, 20)
|
||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v20_to_v20() {
|
||||
onUpdate(database, 20, 20)
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.telephony.TelephonyManager;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.free.nrw.commons.utils.model.NetworkConnectionType;
|
||||
|
|
@ -97,6 +98,7 @@ public class NetworkUtilsTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Fix these test with telemetry permission")
|
||||
public void testCellular2GNetwork() {
|
||||
Context mockContext = mock(Context.class);
|
||||
Application mockApplication = mock(Application.class);
|
||||
|
|
@ -123,6 +125,7 @@ public class NetworkUtilsTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Fix these test with telemetry permission")
|
||||
public void testCellular3GNetwork() {
|
||||
Context mockContext = mock(Context.class);
|
||||
Application mockApplication = mock(Application.class);
|
||||
|
|
@ -149,6 +152,7 @@ public class NetworkUtilsTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Fix these test with telemetry permission")
|
||||
public void testCellular4GNetwork() {
|
||||
Context mockContext = mock(Context.class);
|
||||
Application mockApplication = mock(Application.class);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue