mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Compare commits
30 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
757c7b0087 | ||
|
|
9352e1d029 | ||
|
|
a75ec1e89b | ||
|
|
f496b9dfd2 | ||
|
|
e2ba80c342 | ||
|
|
ece085d1d1 | ||
|
|
d4420860b7 | ||
|
|
624d351d4b | ||
|
|
87f4796504 | ||
|
|
917a944721 | ||
|
|
d9aea26005 | ||
|
|
8c79447803 | ||
|
|
fcc3053d40 | ||
|
|
aa1d6fe2aa | ||
|
|
e7d93159d3 | ||
|
|
e471226405 | ||
|
|
78d519f83e | ||
|
|
3e389be6f5 | ||
|
|
d02b959341 | ||
|
|
ac3e5158be | ||
|
|
d950f72193 | ||
|
|
d97d40fbb9 | ||
|
|
741746892a | ||
|
|
bff923135e | ||
|
|
63018fcbd5 | ||
|
|
461249fc30 | ||
|
|
d7c2480174 | ||
|
|
05a9aa8575 | ||
|
|
c961099013 | ||
|
|
cf73e28623 |
55 changed files with 632 additions and 472 deletions
17
CHANGELOG.md
17
CHANGELOG.md
|
|
@ -1,5 +1,22 @@
|
|||
# Wikimedia Commons for Android
|
||||
|
||||
## v2.13.2
|
||||
- Fixed issue with invisible pins on Nearby map being targetable
|
||||
- Fixed logout bug
|
||||
- Fixed various crashes
|
||||
|
||||
## v2.13.1
|
||||
- Added OpenStreetMap attribution
|
||||
- Fixed various crashes
|
||||
- Fixed SQLite error in Nearby map
|
||||
- Fixed issue with Nearby uploads not being associated with Wikidata p18
|
||||
|
||||
## v2.13.0
|
||||
- New media details UI, ability to zoom and pan around image
|
||||
- Added suggestions for a place that needs photos if user uploads a photo that is near one of them
|
||||
- Modifications and fixes to Nearby filters based on user feedback
|
||||
- Multiple crash and bug fixes
|
||||
|
||||
## v2.12.3
|
||||
- Fixed issue with EXIF data, including coords, being removed from uploads
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ dependencies {
|
|||
implementation 'com.github.nicolas-raoul:Quadtree:ac16ea8035bf07'
|
||||
implementation 'in.yuvi:http.fluent:1.3'
|
||||
implementation 'com.google.code.gson:gson:2.8.5'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.2.0'
|
||||
implementation ("com.squareup.okhttp3:okhttp:$OKHTTP_VERSION"){
|
||||
force = true //API 19 support
|
||||
}
|
||||
implementation 'com.squareup.okio:okio:2.2.2'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.3'
|
||||
|
|
@ -35,7 +37,6 @@ dependencies {
|
|||
|
||||
// UI
|
||||
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:8.6.2'
|
||||
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-localization-v8:0.11.0'
|
||||
|
|
@ -53,7 +54,7 @@ dependencies {
|
|||
api('com.github.tony19:logback-android-classic:1.1.1-6') {
|
||||
exclude group: 'com.google.android', module: 'android'
|
||||
}
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.2.0"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:$OKHTTP_VERSION"
|
||||
|
||||
// Dependency injector
|
||||
implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION"
|
||||
|
|
@ -125,8 +126,8 @@ android {
|
|||
|
||||
defaultConfig {
|
||||
//applicationId 'fr.free.nrw.commons'
|
||||
versionCode 561
|
||||
versionName '2.12.3'
|
||||
versionCode 791
|
||||
versionName '2.13.2'
|
||||
setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName())
|
||||
|
||||
minSdkVersion 19
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.mapbox.mapboxsdk.Mapbox;
|
|||
import com.squareup.leakcanary.LeakCanary;
|
||||
import com.squareup.leakcanary.RefWatcher;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import org.acra.ACRA;
|
||||
import org.acra.annotation.AcraCore;
|
||||
import org.acra.annotation.AcraDialog;
|
||||
|
|
@ -267,17 +268,18 @@ public class CommonsApplication extends Application {
|
|||
}
|
||||
|
||||
sessionManager.logout()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(() -> {
|
||||
Timber.d("All accounts have been removed");
|
||||
clearImageCache();
|
||||
//TODO: fix preference manager
|
||||
defaultPrefs.clearAll();
|
||||
defaultPrefs.putBoolean("firstrun", false);
|
||||
updateAllDatabases();
|
||||
logoutListener.onLogoutComplete();
|
||||
});
|
||||
.andThen(Completable.fromAction(() ->{
|
||||
Timber.d("All accounts have been removed");
|
||||
clearImageCache();
|
||||
//TODO: fix preference manager
|
||||
defaultPrefs.clearAll();
|
||||
defaultPrefs.putBoolean("firstrun", false);
|
||||
updateAllDatabases();
|
||||
}
|
||||
))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(logoutListener::onLogoutComplete, Timber::e);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -263,10 +263,9 @@ public class BookmarkLocationsDao {
|
|||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
if (from == 10 && to == 11) {
|
||||
from++;
|
||||
if (from == 10) {
|
||||
//This is safe, and can be called clean, as we/I do not remember the appropriate version for this
|
||||
//We are anyways switching to room, these things won't be nescessary then
|
||||
//We are anyways switching to room, these things won't be necessary then
|
||||
try {
|
||||
db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_pic STRING;");
|
||||
}catch (SQLiteException exception){
|
||||
|
|
|
|||
|
|
@ -123,9 +123,8 @@ public class CategoriesModel{
|
|||
}
|
||||
|
||||
//otherwise, search API for matching categories
|
||||
//term passed as lower case to make search case-insensitive(taking only lower case for everything)
|
||||
return categoryClient
|
||||
.searchCategoriesForPrefix(term.toLowerCase(), SEARCH_CATS_LIMIT)
|
||||
.searchCategoriesForPrefix(term, SEARCH_CATS_LIMIT)
|
||||
.map(name -> new CategoryItem(name, false));
|
||||
}
|
||||
|
||||
|
|
@ -184,12 +183,11 @@ public class CategoriesModel{
|
|||
|
||||
/**
|
||||
* Return category for single title
|
||||
* title is converted to lower case to make search case-insensitive
|
||||
* @param title
|
||||
* @return
|
||||
*/
|
||||
private Observable<CategoryItem> getTitleCategories(String title) {
|
||||
return categoryClient.searchCategories(title.toLowerCase(), SEARCH_CATS_LIMIT)
|
||||
return categoryClient.searchCategories(title, SEARCH_CATS_LIMIT)
|
||||
.map(name -> new CategoryItem(name, false));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public class CategoryClient {
|
|||
|
||||
/**
|
||||
* Searches for categories starting with the specified string.
|
||||
*
|
||||
*
|
||||
* @param prefix The prefix to be searched
|
||||
* @param itemLimit How many results are returned
|
||||
* @param offset Starts returning items from the nth result. If offset is 9, the response starts with the 9th item of the search result
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ package fr.free.nrw.commons.category;
|
|||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Represents a Category Item.
|
||||
* Implemented as Parcelable so that its object could be parsed between activity components.
|
||||
*/
|
||||
public class CategoryItem implements Parcelable {
|
||||
private final String name;
|
||||
private boolean selected;
|
||||
|
|
@ -24,28 +28,53 @@ public class CategoryItem implements Parcelable {
|
|||
this.selected = selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from the received Parcel
|
||||
* @param in
|
||||
*/
|
||||
private CategoryItem(Parcel in) {
|
||||
name = in.readString();
|
||||
selected = in.readInt() == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Name
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if that Category Item has been selected.
|
||||
* @return
|
||||
*/
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the Category Item.
|
||||
* @param selected
|
||||
*/
|
||||
public void setSelected(boolean selected) {
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by Parcelable
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes to the received Parcel
|
||||
* @param parcel
|
||||
* @param flags
|
||||
*/
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeString(name);
|
||||
|
|
@ -67,13 +96,19 @@ public class CategoryItem implements Parcelable {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns hash code for current object
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return String form of current object
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CategoryItem: '" + name + '\'';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,19 @@ public class Contribution extends Media {
|
|||
private String p18Value;
|
||||
public Uri contentProviderUri;
|
||||
public String dateCreatedSource;
|
||||
public int hasInvalidLocation;
|
||||
|
||||
/**
|
||||
* Set this true when ImageProcessor has said that the location is invalid
|
||||
* @param hasInvalidLocation
|
||||
*/
|
||||
public void setHasInvalidLocation(boolean hasInvalidLocation) {
|
||||
this.hasInvalidLocation = hasInvalidLocation ? 1 : 0;
|
||||
}
|
||||
|
||||
public boolean isHasInvalidLocation() {
|
||||
return hasInvalidLocation == 1;
|
||||
}
|
||||
|
||||
public Contribution(Uri contentUri, String filename, Uri localUri, String imageUrl, Date dateCreated,
|
||||
int state, long dataLength, Date dateUploaded, long transferred,
|
||||
|
|
@ -269,6 +282,7 @@ public class Contribution extends Media {
|
|||
this.contentProviderUri = contentProviderUri;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
|
|
@ -290,6 +304,7 @@ public class Contribution extends Media {
|
|||
dest.writeString(this.p18Value);
|
||||
dest.writeParcelable(this.contentProviderUri, flags);
|
||||
dest.writeString(this.dateCreatedSource);
|
||||
dest.writeInt(this.hasInvalidLocation);
|
||||
}
|
||||
|
||||
protected Contribution(Parcel in) {
|
||||
|
|
@ -307,6 +322,7 @@ public class Contribution extends Media {
|
|||
this.p18Value = in.readString();
|
||||
this.contentProviderUri = in.readParcelable(Uri.class.getClassLoader());
|
||||
this.dateCreatedSource = in.readString();
|
||||
this.hasInvalidLocation = in.readInt();
|
||||
}
|
||||
|
||||
public static final Creator<Contribution> CREATOR = new Creator<Contribution>() {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
|
|||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import fr.free.nrw.commons.MediaDataExtractor;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -94,6 +95,9 @@ public class ContributionsFragment
|
|||
|
||||
@Inject ContributionsPresenter contributionsPresenter;
|
||||
|
||||
@Inject
|
||||
SessionManager sessionManager;
|
||||
|
||||
private LatLng curLatLng;
|
||||
|
||||
private boolean firstLocationUpdate = true;
|
||||
|
|
@ -162,7 +166,8 @@ public class ContributionsFragment
|
|||
showContributionsListFragment();
|
||||
}
|
||||
|
||||
if (!ConfigUtils.isBetaFlavour()) {
|
||||
if (!ConfigUtils.isBetaFlavour() && sessionManager.isUserLoggedIn()
|
||||
&& sessionManager.getCurrentAccount() != null) {
|
||||
setUploadCount();
|
||||
}
|
||||
|
||||
|
|
@ -224,6 +229,14 @@ public class ContributionsFragment
|
|||
Timber.d("Fetching thumbnail for %s", contribution.filename);
|
||||
contributionsPresenter.fetchMediaDetails(contribution);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContributionsUpdated() {
|
||||
//If the contributions are updated, let the pager fragment know
|
||||
if (null != mediaDetailPagerFragment) {
|
||||
mediaDetailPagerFragment.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(null==mediaDetailPagerFragment){
|
||||
|
|
|
|||
|
|
@ -77,5 +77,7 @@ public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionV
|
|||
Contribution getContributionForPosition(int position);
|
||||
|
||||
void fetchMediaUriFor(Contribution contribution);
|
||||
|
||||
void onContributionsUpdated();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
|
|||
this.contributions.clear();
|
||||
this.contributions.addAll(contributionList);
|
||||
adapter.setContributions(contributions);
|
||||
callback.onContributionsUpdated();
|
||||
}
|
||||
|
||||
public interface SourceRefresher {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import androidx.room.TypeConverters;
|
|||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
import fr.free.nrw.commons.contributions.ContributionDao;
|
||||
|
||||
@Database(entities = {Contribution.class}, version = 1, exportSchema = false)
|
||||
@Database(entities = {Contribution.class}, version = 2, exportSchema = false)
|
||||
@TypeConverters({Converters.class})
|
||||
abstract public class AppDatabase extends RoomDatabase {
|
||||
public abstract ContributionDao getContributionDao();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import android.content.Context;
|
|||
import android.view.inputmethod.InputMethodManager;
|
||||
import androidx.collection.LruCache;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.migration.Migration;
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
import com.github.varunpant.quadtree.QuadTree;
|
||||
import com.google.gson.Gson;
|
||||
import dagger.Module;
|
||||
|
|
@ -52,6 +54,14 @@ public class CommonsApplicationModule {
|
|||
public static final String MAIN_THREAD="main_thread";
|
||||
private AppDatabase appDatabase;
|
||||
|
||||
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
|
||||
@Override
|
||||
public void migrate(SupportSQLiteDatabase database) {
|
||||
database.execSQL("ALTER TABLE contribution "
|
||||
+ " ADD COLUMN hasInvalidLocation INTEGER NOT NULL DEFAULT 0");
|
||||
}
|
||||
};
|
||||
|
||||
public CommonsApplicationModule(Context applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
|
@ -231,7 +241,9 @@ public class CommonsApplicationModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
public AppDatabase provideAppDataBase() {
|
||||
appDatabase=Room.databaseBuilder(applicationContext, AppDatabase.class, "commons_room.db").build();
|
||||
appDatabase=Room.databaseBuilder(applicationContext, AppDatabase.class, "commons_room.db")
|
||||
.addMigrations(MIGRATION_1_2)
|
||||
.build();
|
||||
return appDatabase;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ public class FilePicker implements Constants {
|
|||
public static List<UploadableFile> handleExternalImagesPicked(Intent data, Activity activity) {
|
||||
try {
|
||||
return getFilesFromGalleryPictures(data, activity);
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | SecurityException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new ArrayList<>();
|
||||
|
|
@ -207,7 +207,7 @@ public class FilePicker implements Constants {
|
|||
}
|
||||
}
|
||||
|
||||
private static List<UploadableFile> getFilesFromGalleryPictures(Intent data, Activity activity) throws IOException {
|
||||
private static List<UploadableFile> getFilesFromGalleryPictures(Intent data, Activity activity) throws IOException, SecurityException {
|
||||
List<UploadableFile> files = new ArrayList<>();
|
||||
ClipData clipData = data.getClipData();
|
||||
if (clipData == null) {
|
||||
|
|
|
|||
|
|
@ -104,12 +104,15 @@ class PickedFiles implements Constants {
|
|||
});
|
||||
}
|
||||
|
||||
static UploadableFile pickedExistingPicture(@NonNull Context context, Uri photoUri) throws IOException {
|
||||
static UploadableFile pickedExistingPicture(@NonNull Context context, Uri photoUri) throws IOException, SecurityException {// SecurityException for those file providers who share URI but forget to grant necessary permissions
|
||||
InputStream pictureInputStream = context.getContentResolver().openInputStream(photoUri);
|
||||
File directory = tempImageDirectory(context);
|
||||
File photoFile = new File(directory, UUID.randomUUID().toString() + "." + getMimeType(context, photoUri));
|
||||
photoFile.createNewFile();
|
||||
writeToFile(pictureInputStream, photoFile);
|
||||
if (photoFile.createNewFile()) {
|
||||
writeToFile(pictureInputStream, photoFile);
|
||||
} else {
|
||||
throw new IOException("could not create photoFile to write upon");
|
||||
}
|
||||
return new UploadableFile(photoUri, photoFile);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
|
||||
@BindView(R.id.mediaDetailImageView)
|
||||
SimpleDraweeView image;
|
||||
@BindView(R.id.mediaDetailImageViewSpacer)
|
||||
LinearLayout imageSpacer;
|
||||
@BindView(R.id.mediaDetailTitle)
|
||||
TextView title;
|
||||
@BindView(R.id.mediaDetailDesc)
|
||||
|
|
@ -205,12 +207,14 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
return view;
|
||||
}
|
||||
|
||||
@OnClick(R.id.mediaDetailImageView)
|
||||
@OnClick(R.id.mediaDetailImageViewSpacer)
|
||||
public void launchZoomActivity(View view) {
|
||||
Context ctx = view.getContext();
|
||||
ctx.startActivity(
|
||||
new Intent(ctx,ZoomableActivity.class).setData(Uri.parse(media.getImageUrl()))
|
||||
);
|
||||
if (media.getImageUrl() != null) {
|
||||
Context ctx = view.getContext();
|
||||
ctx.startActivity(
|
||||
new Intent(ctx, ZoomableActivity.class).setData(Uri.parse(media.getImageUrl()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -241,12 +245,21 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
compositeDisposable.add(disposable);
|
||||
}
|
||||
|
||||
/**
|
||||
* The imageSpacer is Basically a transparent overlay for the SimpleDraweeView
|
||||
* which holds the image to be displayed( moreover this image is out of
|
||||
* the scroll view )
|
||||
* @param imageInfo used to calculate height of the ImageSpacer
|
||||
*/
|
||||
private void updateAspectRatio(ImageInfo imageInfo) {
|
||||
if (imageInfo != null) {
|
||||
int finalHeight = (scrollView.getWidth()*imageInfo.getHeight()) / imageInfo.getWidth();
|
||||
ViewGroup.LayoutParams params = image.getLayoutParams();
|
||||
ViewGroup.LayoutParams spacerParams = imageSpacer.getLayoutParams();
|
||||
params.height = finalHeight;
|
||||
spacerParams.height = finalHeight;
|
||||
image.setLayoutParams(params);
|
||||
imageSpacer.setLayoutParams(spacerParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -320,7 +320,9 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
* The method notify the viewpager that number of items have changed.
|
||||
*/
|
||||
public void notifyDataSetChanged(){
|
||||
adapter.notifyDataSetChanged();
|
||||
if (null != adapter) {
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -23,18 +23,11 @@ import com.facebook.drawee.drawable.ScalingUtils;
|
|||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.facebook.imagepipeline.image.ImageInfo;
|
||||
import com.github.chrisbanes.photoview.PhotoView;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
public class ZoomableActivity extends AppCompatActivity {
|
||||
private Uri imageUri;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public class ZoomableDraweeView extends DraweeView<GenericDraweeHierarchy>
|
|||
|
||||
private boolean mIsDialtoneEnabled = false;
|
||||
private boolean mZoomingEnabled = true;
|
||||
private TransformationListener transformationListener;
|
||||
|
||||
private final ControllerListener mControllerListener =
|
||||
new BaseControllerListener<Object>() {
|
||||
|
|
@ -73,9 +74,18 @@ public class ZoomableDraweeView extends DraweeView<GenericDraweeHierarchy>
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onTransformEnd(Matrix transform) {}
|
||||
public void onTransformEnd(Matrix transform) {
|
||||
if (null != transformationListener) {
|
||||
transformationListener.onTransformationEnd();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void setTransformationListener(
|
||||
TransformationListener transformationListener) {
|
||||
this.transformationListener = transformationListener;
|
||||
}
|
||||
|
||||
private final GestureListenerWrapper mTapListenerWrapper = new GestureListenerWrapper();
|
||||
|
||||
public ZoomableDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
|
||||
|
|
@ -397,4 +407,11 @@ public class ZoomableDraweeView extends DraweeView<GenericDraweeHierarchy>
|
|||
protected ZoomableController createZoomableController() {
|
||||
return AnimatedZoomableController.newInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this, If someone is willing to listen to scale change
|
||||
*/
|
||||
public interface TransformationListener{
|
||||
void onTransformationEnd();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
package fr.free.nrw.commons.nearby;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.CompoundButton;
|
||||
|
||||
|
|
@ -12,7 +10,6 @@ import androidx.appcompat.widget.AppCompatCheckBox;
|
|||
import java.util.List;
|
||||
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter;
|
||||
|
||||
/**
|
||||
* Base on https://stackoverflow.com/a/40939367/3950497 answer.
|
||||
|
|
@ -25,7 +22,7 @@ public class CheckBoxTriStates extends AppCompatCheckBox {
|
|||
|
||||
static public final int CHECKED = 1;
|
||||
|
||||
private int state;
|
||||
private int state=UNKNOWN;
|
||||
|
||||
private Callback callback;
|
||||
|
||||
|
|
@ -64,12 +61,6 @@ public class CheckBoxTriStates extends AppCompatCheckBox {
|
|||
*/
|
||||
private OnCheckedChangeListener clientListener;
|
||||
|
||||
/**
|
||||
* This flag is needed to avoid accidentally changing the current {@link #state} when
|
||||
* {@link #onRestoreInstanceState(Parcelable)} calls {@link #setChecked(boolean)}
|
||||
* evoking our {@link #privateListener} and therefore changing the real state.
|
||||
*/
|
||||
private boolean restoring;
|
||||
|
||||
public CheckBoxTriStates(Context context) {
|
||||
super(context);
|
||||
|
|
@ -91,7 +82,7 @@ public class CheckBoxTriStates extends AppCompatCheckBox {
|
|||
}
|
||||
|
||||
public void setState(int state) {
|
||||
if(!this.restoring && this.state != state) {
|
||||
if(this.state != state) {
|
||||
this.state = state;
|
||||
|
||||
if(this.clientListener != null) {
|
||||
|
|
@ -118,27 +109,6 @@ public class CheckBoxTriStates extends AppCompatCheckBox {
|
|||
super.setOnCheckedChangeListener(privateListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
|
||||
SavedState ss = new SavedState(superState);
|
||||
|
||||
ss.state = state;
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
this.restoring = true; // indicates that the ui is restoring its state
|
||||
SavedState ss = (SavedState) state;
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
setState(ss.state);
|
||||
requestLayout();
|
||||
this.restoring = false;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
state = UNKNOWN;
|
||||
updateBtn();
|
||||
|
|
@ -164,44 +134,4 @@ public class CheckBoxTriStates extends AppCompatCheckBox {
|
|||
setButtonDrawable(btnDrawable);
|
||||
|
||||
}
|
||||
|
||||
static class SavedState extends BaseSavedState {
|
||||
int state;
|
||||
|
||||
SavedState(Parcelable superState) {
|
||||
super(superState);
|
||||
}
|
||||
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
state = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeValue(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CheckboxTriState.SavedState{"
|
||||
+ Integer.toHexString(System.identityHashCode(this))
|
||||
+ " state=" + state + "}";
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Parcelable.Creator<SavedState> CREATOR =
|
||||
new Parcelable.Creator<SavedState>() {
|
||||
@Override
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -41,4 +41,17 @@ public class NearbyAdapterFactory {
|
|||
rendererAdapter.notifyDataSetChanged();
|
||||
rendererAdapter.diffUpdate(newPlaceList);
|
||||
}
|
||||
|
||||
public void clear(RVRendererAdapter<Place> rendererAdapter){
|
||||
rendererAdapter.clear();
|
||||
}
|
||||
|
||||
public void add(Place place, RVRendererAdapter<Place> rendererAdapter){
|
||||
rendererAdapter.add(place);
|
||||
}
|
||||
|
||||
public void update(RVRendererAdapter<Place> rendererAdapter){
|
||||
rendererAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.mapbox.mapboxsdk.annotations.Marker;
|
|||
public class NearbyMarker extends Marker {
|
||||
private final Place place;
|
||||
private NearbyBaseMarker nearbyBaseMarker;
|
||||
private boolean disabled;
|
||||
|
||||
/**
|
||||
* Creates a instance of {@link Marker} using the builder of Marker.
|
||||
|
|
@ -24,4 +25,12 @@ public class NearbyMarker extends Marker {
|
|||
public Place getPlace() {
|
||||
return place;
|
||||
}
|
||||
|
||||
public void setDisabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
public boolean isDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,13 @@
|
|||
package fr.free.nrw.commons.nearby.fragments;
|
||||
|
||||
import static fr.free.nrw.commons.contributions.MainActivity.CONTRIBUTIONS_TAB_POSITION;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED;
|
||||
import static fr.free.nrw.commons.nearby.Label.TEXT_TO_DESCRIPTION;
|
||||
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
|
|
@ -11,6 +19,8 @@ import android.content.res.Configuration;
|
|||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.Html;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
|
|
@ -26,14 +36,15 @@ import android.widget.RelativeLayout;
|
|||
import android.widget.SearchView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.chip.Chip;
|
||||
import com.google.android.material.chip.ChipGroup;
|
||||
|
|
@ -58,17 +69,6 @@ import com.mapbox.mapboxsdk.maps.UiSettings;
|
|||
import com.mapbox.pluginscalebar.ScaleBarOptions;
|
||||
import com.mapbox.pluginscalebar.ScaleBarPlugin;
|
||||
import com.pedrogomez.renderers.RVRendererAdapter;
|
||||
|
||||
import fr.free.nrw.commons.utils.DialogUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
|
|
@ -92,6 +92,7 @@ import fr.free.nrw.commons.nearby.NearbyMarker;
|
|||
import fr.free.nrw.commons.nearby.Place;
|
||||
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract;
|
||||
import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter;
|
||||
import fr.free.nrw.commons.utils.DialogUtil;
|
||||
import fr.free.nrw.commons.utils.ExecutorUtils;
|
||||
import fr.free.nrw.commons.utils.LayoutUtils;
|
||||
import fr.free.nrw.commons.utils.LocationUtils;
|
||||
|
|
@ -105,16 +106,13 @@ import fr.free.nrw.commons.wikidata.WikidataEditListener;
|
|||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static fr.free.nrw.commons.contributions.MainActivity.CONTRIBUTIONS_TAB_POSITION;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED;
|
||||
import static fr.free.nrw.commons.nearby.Label.TEXT_TO_DESCRIPTION;
|
||||
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
|
||||
|
||||
|
||||
public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||
implements NearbyParentFragmentContract.View,
|
||||
|
|
@ -154,6 +152,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
MapView mapView;
|
||||
@BindView(R.id.rv_nearby_list)
|
||||
RecyclerView rvNearbyList;
|
||||
@BindView(R.id.tv_attribution)
|
||||
AppCompatTextView tvAttribution;
|
||||
|
||||
@Inject LocationServiceManager locationManager;
|
||||
@Inject NearbyController nearbyController;
|
||||
|
|
@ -236,8 +236,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
UiSettings uiSettings = mapBoxMap.getUiSettings();
|
||||
uiSettings.setCompassGravity(Gravity.BOTTOM | Gravity.LEFT);
|
||||
uiSettings.setCompassMargins(12, 0, 0, 24);
|
||||
uiSettings.setLogoEnabled(true);
|
||||
uiSettings.setAttributionEnabled(true);
|
||||
uiSettings.setLogoEnabled(false);
|
||||
uiSettings.setAttributionEnabled(false);
|
||||
uiSettings.setRotateGesturesEnabled(false);
|
||||
NearbyParentFragment.this.isMapBoxReady=true;
|
||||
performMapReadyActions();
|
||||
|
|
@ -260,6 +260,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
scaleBarPlugin.create(scaleBarOptions);
|
||||
});
|
||||
});
|
||||
|
||||
tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution)));
|
||||
tvAttribution.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -624,6 +627,18 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
adapterFactory.updateAdapterData(placeList, (RVRendererAdapter<Place>) rvNearbyList.getAdapter());
|
||||
}
|
||||
|
||||
public void clearNearbyList() {
|
||||
adapterFactory.clear((RVRendererAdapter<Place>) rvNearbyList.getAdapter());
|
||||
}
|
||||
|
||||
public void updateNearbyList() {
|
||||
adapterFactory.update((RVRendererAdapter<Place>) rvNearbyList.getAdapter());
|
||||
}
|
||||
|
||||
public void addPlaceToNearbyList(Place place) {
|
||||
adapterFactory.add(place, (RVRendererAdapter<Place>) rvNearbyList.getAdapter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public fr.free.nrw.commons.location.LatLng getLastLocation() {
|
||||
return lastKnownLocation;
|
||||
|
|
@ -636,7 +651,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
|
||||
@Override
|
||||
public boolean isCurrentLocationMarkerVisible() {
|
||||
if (latLngBounds == null) {
|
||||
if (latLngBounds == null || currentLocationMarker==null) {
|
||||
Timber.d("Map projection bounds are null");
|
||||
return false;
|
||||
} else {
|
||||
|
|
@ -1078,7 +1093,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
|
||||
@Override
|
||||
public void filterOutAllMarkers() {
|
||||
hideAllMArkers();
|
||||
hideAllMarkers();
|
||||
updateNearbyList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1089,6 +1105,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
for (MarkerPlaceGroup markerPlaceGroup : NearbyController.markerLabelList) {
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation);
|
||||
}
|
||||
updateNearbyList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1100,65 +1117,44 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
* @param filterForAllNoneType true if we filter places with all none button
|
||||
*/
|
||||
@Override
|
||||
public void filterMarkersByLabels(List<Label> selectedLabels, boolean displayExists,
|
||||
boolean displayNeedsPhoto,
|
||||
boolean filterForPlaceState,
|
||||
boolean filterForAllNoneType) {
|
||||
if (selectedLabels.size() == 0 && filterForPlaceState) { // If nothing is selected, display all
|
||||
// remove the previous markers before updating them
|
||||
hideAllMArkers();
|
||||
for (MarkerPlaceGroup markerPlaceGroup : NearbyController.markerLabelList) {
|
||||
if (displayExists && displayNeedsPhoto) {
|
||||
// Exists and needs photo
|
||||
if (markerPlaceGroup.getPlace().destroyed.trim().isEmpty() && markerPlaceGroup.getPlace().pic.trim().isEmpty()) {
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation);
|
||||
}
|
||||
} else if (displayExists && !displayNeedsPhoto) {
|
||||
// Exists and all included needs and doesn't needs photo
|
||||
if (markerPlaceGroup.getPlace().destroyed.trim().isEmpty()) {
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation);
|
||||
}
|
||||
} else if (!displayExists && displayNeedsPhoto) {
|
||||
// All and only needs photo
|
||||
if (markerPlaceGroup.getPlace().pic.trim().isEmpty()) {
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation);
|
||||
}
|
||||
} else if (!displayExists && !displayNeedsPhoto) {
|
||||
// all
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation);
|
||||
}
|
||||
public void filterMarkersByLabels(List<Label> selectedLabels,
|
||||
boolean displayExists,
|
||||
boolean displayNeedsPhoto,
|
||||
boolean filterForPlaceState,
|
||||
boolean filterForAllNoneType) {
|
||||
|
||||
hideAllMarkers();
|
||||
for (MarkerPlaceGroup markerPlaceGroup : NearbyController.markerLabelList) {
|
||||
Place place = markerPlaceGroup.getPlace();
|
||||
|
||||
// When label filter is engaged
|
||||
// then compare it against place's label
|
||||
if (selectedLabels != null && (selectedLabels.size() != 0 || !filterForPlaceState)
|
||||
&& !selectedLabels.contains(place.getLabel())) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// First remove all the markers
|
||||
hideAllMArkers();
|
||||
for (MarkerPlaceGroup markerPlaceGroup : NearbyController.markerLabelList) {
|
||||
for (Label label : selectedLabels) {
|
||||
if (markerPlaceGroup.getPlace().getLabel().toString().equals(label.toString())) {
|
||||
|
||||
if (displayExists && displayNeedsPhoto) {
|
||||
// Exists and needs photo
|
||||
if (markerPlaceGroup.getPlace().destroyed.trim().isEmpty() && markerPlaceGroup.getPlace().pic.trim().isEmpty()) {
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation);
|
||||
}
|
||||
} else if (displayExists && !displayNeedsPhoto) {
|
||||
// Exists and all included needs and doesn't needs photo
|
||||
if (markerPlaceGroup.getPlace().destroyed.trim().isEmpty()) {
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation);
|
||||
}
|
||||
} else if (!displayExists && displayNeedsPhoto) {
|
||||
// All and only needs photo
|
||||
if (markerPlaceGroup.getPlace().pic.trim().isEmpty()) {
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation);
|
||||
}
|
||||
} else if (!displayExists && !displayNeedsPhoto) {
|
||||
// all
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation);
|
||||
}
|
||||
}
|
||||
if (displayExists && displayNeedsPhoto) {
|
||||
// Exists and needs photo
|
||||
if (place.destroyed.trim().isEmpty() && place.pic.trim().isEmpty()) {
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), place, NearbyController.currentLocation);
|
||||
}
|
||||
} else if (displayExists && !displayNeedsPhoto) {
|
||||
// Exists and all included needs and doesn't needs photo
|
||||
if (place.destroyed.trim().isEmpty()) {
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), place, NearbyController.currentLocation);
|
||||
}
|
||||
} else if (!displayExists && displayNeedsPhoto) {
|
||||
// All and only needs photo
|
||||
if (place.pic.trim().isEmpty()) {
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), place, NearbyController.currentLocation);
|
||||
}
|
||||
} else if (!displayExists && !displayNeedsPhoto) {
|
||||
// all
|
||||
updateMarker(markerPlaceGroup.getIsBookmarked(), place, NearbyController.currentLocation);
|
||||
}
|
||||
}
|
||||
updateNearbyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1173,6 +1169,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
* @param curLatLng current location
|
||||
*/
|
||||
public void updateMarker(boolean isBookmarked, Place place, @Nullable fr.free.nrw.commons.location.LatLng curLatLng) {
|
||||
addPlaceToNearbyList(place);
|
||||
|
||||
VectorDrawableCompat vectorDrawable;
|
||||
if (isBookmarked) {
|
||||
vectorDrawable = VectorDrawableCompat.create(
|
||||
|
|
@ -1210,6 +1208,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
nearbyBaseMarker.icon(IconFactory.getInstance(getContext())
|
||||
.fromBitmap(icon));
|
||||
marker.setIcon(IconFactory.getInstance(getContext()).fromBitmap(icon));
|
||||
|
||||
if(marker instanceof NearbyMarker){
|
||||
((NearbyMarker) marker).setDisabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1219,10 +1221,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
* but it is transparent more than grey(as the name of the icon might suggest)
|
||||
* since grey icon may lead the users to believe that it is disabled or prohibited contribution
|
||||
*/
|
||||
private void hideAllMArkers() {
|
||||
if(currentLocationMarker==null){
|
||||
return;
|
||||
}
|
||||
|
||||
private void hideAllMarkers() {
|
||||
VectorDrawableCompat vectorDrawable;
|
||||
vectorDrawable = VectorDrawableCompat.create(
|
||||
getContext().getResources(), R.drawable.ic_custom_greyed_out_marker, getContext().getTheme());
|
||||
|
|
@ -1230,9 +1230,13 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
for (Marker marker : mapBox.getMarkers()) {
|
||||
if (!marker.equals(currentLocationMarker)) {
|
||||
marker.setIcon(IconFactory.getInstance(getContext()).fromBitmap(icon));
|
||||
if(marker instanceof NearbyMarker){
|
||||
((NearbyMarker) marker).setDisabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
addCurrentLocationMarker(NearbyController.currentLocation);
|
||||
clearNearbyList();
|
||||
}
|
||||
|
||||
private void addNearbyMarkersToMapBoxMap(List<NearbyBaseMarker> nearbyBaseMarkers, Marker selectedMarker) {
|
||||
|
|
@ -1252,10 +1256,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
});
|
||||
|
||||
mapBox.setOnMarkerClickListener(marker -> {
|
||||
if (marker instanceof NearbyMarker) {
|
||||
if (marker instanceof NearbyMarker && !((NearbyMarker) marker).isDisabled()) {
|
||||
presenter.markerSelected(marker);
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -284,7 +284,11 @@ public class NearbyParentFragmentPresenter
|
|||
nearbyParentFragmentView.setRecyclerViewAdapterItemsGreyedOut();
|
||||
break;
|
||||
case CHECKED:
|
||||
nearbyParentFragmentView.displayAllMarkers();
|
||||
// Despite showing all labels NearbyFilterState still should be applied
|
||||
nearbyParentFragmentView.filterMarkersByLabels(selectedLabels,
|
||||
NearbyFilterState.getInstance().isExistsSelected(),
|
||||
NearbyFilterState.getInstance().isNeedPhotoSelected(),
|
||||
filterForPlaceState, false);
|
||||
nearbyParentFragmentView.setRecyclerViewAdapterAllSelected();
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ public class Prefs {
|
|||
public static final String MANAGED_EXIF_TAGS = "managed_exif_tags";
|
||||
public static final String KEY_LANGUAGE_VALUE = "languageDescription";
|
||||
public static final String KEY_THEME_VALUE = "appThemePref";
|
||||
public static final String TELEMETRY_PREFERENCE = "telemetryPref";
|
||||
|
||||
public static class Licenses {
|
||||
public static final String CC_BY_SA_3 = "CC BY-SA 3.0";
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import com.google.android.material.snackbar.Snackbar;
|
|||
import com.karumi.dexter.Dexter;
|
||||
import com.karumi.dexter.listener.PermissionGrantedResponse;
|
||||
import com.karumi.dexter.listener.single.BasePermissionListener;
|
||||
import com.mapbox.mapboxsdk.Mapbox;
|
||||
import com.mapbox.mapboxsdk.maps.TelemetryDefinition;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||
|
|
@ -123,6 +125,24 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
findPreference("displayCampaignsCardView").setEnabled(false);
|
||||
uploadLimit.setEnabled(false);
|
||||
}
|
||||
|
||||
findPreference("telemetryOptOut").setOnPreferenceChangeListener(
|
||||
(preference, newValue) -> {
|
||||
telemetryOptInOut((boolean)newValue);
|
||||
defaultKvStore.putBoolean(Prefs.TELEMETRY_PREFERENCE,(boolean)newValue);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Opt in or out of MapBox telemetry
|
||||
* @param shouldOptIn
|
||||
*/
|
||||
private void telemetryOptInOut(boolean shouldOptIn){
|
||||
TelemetryDefinition telemetry = Mapbox.getTelemetry();
|
||||
if (telemetry != null) {
|
||||
telemetry.setUserTelemetryRequestState(shouldOptIn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package fr.free.nrw.commons.upload;
|
|||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import org.wikipedia.csrf.CsrfTokenClient;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -41,7 +43,15 @@ public class UploadClient {
|
|||
(bytesWritten, contentLength) -> notificationUpdater
|
||||
.onProgress(bytesWritten, contentLength));
|
||||
|
||||
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", filename, countingRequestBody);
|
||||
MultipartBody.Part filePart;
|
||||
try {
|
||||
filePart = MultipartBody.Part
|
||||
.createFormData("file", URLEncoder.encode(filename, "utf-8"), countingRequestBody);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
filePart = MultipartBody.Part
|
||||
.createFormData("file", filename, countingRequestBody);
|
||||
}
|
||||
RequestBody fileNameRequestBody = RequestBody.create(okhttp3.MultipartBody.FORM, filename);
|
||||
RequestBody tokenRequestBody;
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ public class UploadModel {
|
|||
contribution.setSource(item.source);
|
||||
contribution.setContentProviderUri(item.mediaUri);
|
||||
contribution.setDateUploaded(new Date());
|
||||
contribution.setHasInvalidLocation(item.hasInvalidLocation);
|
||||
|
||||
Timber.d("Created timestamp while building contribution is %s, %s",
|
||||
item.getCreatedTimestamp(),
|
||||
|
|
@ -221,6 +222,7 @@ public class UploadModel {
|
|||
private final String mimeType;
|
||||
private final String source;
|
||||
private ImageCoordinates gpsCoords;
|
||||
private boolean hasInvalidLocation;
|
||||
|
||||
public void setGpsCoords(ImageCoordinates gpsCoords) {
|
||||
this.gpsCoords = gpsCoords;
|
||||
|
|
@ -326,6 +328,10 @@ public class UploadModel {
|
|||
public int hashCode() {
|
||||
return mediaUri.hashCode();
|
||||
}
|
||||
|
||||
public void setHasInvalidLocation(boolean hasInvalidLocation) {
|
||||
this.hasInvalidLocation=hasInvalidLocation;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,7 +282,15 @@ public class UploadService extends HandlerService<Contribution> {
|
|||
Timber.d("Contribution upload success. Initiating Wikidata edit for"
|
||||
+ " entity id %s if necessary (if P18 is null). P18 value is %s",
|
||||
contribution.getWikiDataEntityId(), contribution.getP18Value());
|
||||
wikidataEditService.createClaimWithLogging(contribution.getWikiDataEntityId(), contribution.getWikiItemName(), canonicalFilename, contribution.getP18Value());
|
||||
if (!contribution.isHasInvalidLocation()) {
|
||||
wikidataEditService
|
||||
.createClaimWithLogging(contribution.getWikiDataEntityId(),
|
||||
contribution.getWikiItemName(), canonicalFilename,
|
||||
contribution.getP18Value());
|
||||
} else {
|
||||
Timber
|
||||
.d("Image location and nearby place location mismatched, so Wikidata item won't be edited");
|
||||
}
|
||||
contribution.setFilename(canonicalFilename);
|
||||
contribution.setImageUrl(uploadResult.getImageinfo().getOriginalUrl());
|
||||
contribution.setState(Contribution.STATE_COMPLETED);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import static fr.free.nrw.commons.utils.ImageUtils.getErrorMessageForResult;
|
|||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
|
|
@ -23,13 +24,19 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import com.github.chrisbanes.photoview.PhotoView;
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.drawable.ScalingUtils.ScaleType;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.jakewharton.rxbinding2.widget.RxTextView;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
import fr.free.nrw.commons.filepicker.UploadableFile;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.media.zoomControllers.zoomable.DoubleTapGestureListener;
|
||||
import fr.free.nrw.commons.media.zoomControllers.zoomable.ZoomableDraweeView;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
import fr.free.nrw.commons.settings.Prefs;
|
||||
import fr.free.nrw.commons.upload.Description;
|
||||
|
|
@ -44,6 +51,7 @@ import fr.free.nrw.commons.utils.DialogUtil;
|
|||
import fr.free.nrw.commons.utils.ImageUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
|
@ -69,7 +77,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
@BindView(R.id.rv_descriptions)
|
||||
RecyclerView rvDescriptions;
|
||||
@BindView(R.id.backgroundImage)
|
||||
PhotoView photoViewBackgroundImage;
|
||||
ZoomableDraweeView photoViewBackgroundImage;
|
||||
@BindView(R.id.btn_next)
|
||||
AppCompatButton btnNext;
|
||||
@BindView(R.id.btn_previous)
|
||||
|
|
@ -164,11 +172,26 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
btnCopyPreviousTitleDesc.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
attachImageViewScaleChangeListener();
|
||||
|
||||
addEtTitleTouchListener();
|
||||
}
|
||||
|
||||
private void showImageWithLocalUri(Uri imageUri) {
|
||||
if (imageUri != null) {
|
||||
GenericDraweeHierarchy hierarchy = GenericDraweeHierarchyBuilder.newInstance(getResources())
|
||||
.setActualImageScaleType(ScaleType.FIT_XY)
|
||||
.build();
|
||||
photoViewBackgroundImage.setHierarchy(hierarchy);
|
||||
photoViewBackgroundImage
|
||||
.setTapListener(new DoubleTapGestureListener(photoViewBackgroundImage));
|
||||
DraweeController controller = Fresco.newDraweeControllerBuilder()
|
||||
.setUri(Uri.fromFile(new File(imageUri.getPath())))
|
||||
.build();
|
||||
photoViewBackgroundImage.setTransformationListener(
|
||||
() -> expandCollapseMediaDetail(false));
|
||||
photoViewBackgroundImage.setController(controller);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the drawable click listener for Edit Text
|
||||
*/
|
||||
|
|
@ -176,11 +199,13 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
etTitle.setOnTouchListener((v, event) -> {
|
||||
//2 is for drawable right
|
||||
float twelveDpInPixels = convertDpToPixel(12, getContext());
|
||||
if (event.getAction() == MotionEvent.ACTION_UP && etTitle.getCompoundDrawables() != null
|
||||
&& etTitle.getCompoundDrawables().length > 2 && etTitle
|
||||
.getCompoundDrawables()[2].getBounds()
|
||||
.contains((int) (etTitle.getWidth() - (event.getX() + twelveDpInPixels)),
|
||||
(int) (event.getY() - twelveDpInPixels))) {
|
||||
if ((event.getAction() == MotionEvent.ACTION_UP)
|
||||
&& (etTitle.getCompoundDrawables() != null)
|
||||
&& (etTitle.getCompoundDrawables().length > 2)
|
||||
&& (etTitle.getCompoundDrawables()[2] != null)
|
||||
&& etTitle.getCompoundDrawables()[2].getBounds()
|
||||
.contains((int) (etTitle.getWidth() - (event.getX() + twelveDpInPixels)),
|
||||
(int) (event.getY() - twelveDpInPixels))) {
|
||||
showInfoAlert(R.string.media_detail_title, R.string.title_info);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -198,17 +223,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
return dp * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the scale change listener to the image view
|
||||
*/
|
||||
private void attachImageViewScaleChangeListener() {
|
||||
photoViewBackgroundImage.setOnScaleChangeListener(
|
||||
(scaleFactor, focusX, focusY) -> {
|
||||
//Whenever the uses plays with the image, lets collapse the media detail container
|
||||
expandCollapseLlMediaDetail(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* attach the presenter with the view
|
||||
*/
|
||||
|
|
@ -284,7 +298,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
}
|
||||
|
||||
descriptions = uploadItem.getDescriptions();
|
||||
photoViewBackgroundImage.setImageURI(uploadItem.getMediaUri());
|
||||
showImageWithLocalUri(uploadItem.getMediaUri());
|
||||
setDescriptionsInAdapter(descriptions);
|
||||
}
|
||||
|
||||
|
|
@ -393,14 +407,17 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
|
||||
@OnClick(R.id.rl_container_title)
|
||||
public void onRlContainerTitleClicked() {
|
||||
expandCollapseLlMediaDetail(!isExpanded);
|
||||
expandCollapseMediaDetail(!isExpanded);
|
||||
}
|
||||
|
||||
/**
|
||||
* show hide media detail based on
|
||||
* @param shouldExpand
|
||||
*/
|
||||
private void expandCollapseLlMediaDetail(boolean shouldExpand){
|
||||
private void expandCollapseMediaDetail(boolean shouldExpand){
|
||||
if (isExpanded == shouldExpand) {
|
||||
return;
|
||||
}
|
||||
llContainerMediaDetail.setVisibility(shouldExpand ? View.VISIBLE : View.GONE);
|
||||
isExpanded = !isExpanded;
|
||||
ibExpandCollapse.setRotation(ibExpandCollapse.getRotation() + 180);
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
|||
.observeOn(mainThreadScheduler)
|
||||
.subscribe(imageResult -> {
|
||||
view.showProgress(false);
|
||||
handleImageResult(imageResult);
|
||||
handleImageResult(imageResult, uploadItem);
|
||||
},
|
||||
throwable -> {
|
||||
view.showProgress(false);
|
||||
|
|
@ -165,13 +165,16 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
|||
/**
|
||||
* handles image quality verifications
|
||||
*
|
||||
* @param imageResult
|
||||
*/
|
||||
public void handleImageResult(Integer imageResult) {
|
||||
* @param imageResult
|
||||
* @param uploadItem
|
||||
*/
|
||||
public void handleImageResult(Integer imageResult,
|
||||
UploadItem uploadItem) {
|
||||
if (imageResult == IMAGE_KEEP || imageResult == IMAGE_OK) {
|
||||
view.onImageValidationSuccess();
|
||||
uploadItem.setHasInvalidLocation(false);
|
||||
} else {
|
||||
handleBadImage(imageResult);
|
||||
handleBadImage(imageResult, uploadItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -179,12 +182,14 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
|||
* Handle images, say empty title, duplicate file name, bad picture(in all other cases)
|
||||
*
|
||||
* @param errorCode
|
||||
* @param uploadItem
|
||||
*/
|
||||
public void handleBadImage(Integer errorCode) {
|
||||
public void handleBadImage(Integer errorCode,
|
||||
UploadItem uploadItem) {
|
||||
Timber.d("Handle bad picture with error code %d", errorCode);
|
||||
if (errorCode
|
||||
>= 8) { // If location of image and nearby does not match, then set shared preferences to disable wikidata edits
|
||||
repository.saveValue("Picture_Has_Correct_Location", false);
|
||||
>= 8) { // If location of image and nearby does not match, then set shared preferences to disable wikidata edits
|
||||
uploadItem.setHasInvalidLocation(true);
|
||||
}
|
||||
|
||||
switch (errorCode) {
|
||||
|
|
|
|||
|
|
@ -25,9 +25,10 @@ public class CommonsDateUtil {
|
|||
* Gets the timestamp pattern for a date
|
||||
* @return timestamp
|
||||
*/
|
||||
public static SimpleDateFormat getIso8601DateFormatTimestamp() {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT);
|
||||
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return simpleDateFormat;
|
||||
public static SimpleDateFormat getIso8601DateFormatTimestamp() {
|
||||
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX",
|
||||
Locale.ROOT);
|
||||
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return simpleDateFormat;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,11 +61,6 @@ public class WikidataEditService {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!(directKvStore.getBoolean("Picture_Has_Correct_Location", true))) {
|
||||
Timber.d("Image location and nearby place location mismatched, so Wikidata item won't be edited");
|
||||
return;
|
||||
}
|
||||
|
||||
if (p18Value != null && !p18Value.trim().isEmpty()) {
|
||||
Timber.d("Skipping creation of claim as p18Value is not empty, we won't override existing image");
|
||||
return;
|
||||
|
|
|
|||
9
app/src/main/res/drawable/bg_copy_wikitext_button.xml
Normal file
9
app/src/main/res/drawable/bg_copy_wikitext_button.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid
|
||||
android:color="@color/button_blue" />
|
||||
<corners
|
||||
android:radius="@dimen/progressbar_stroke" />
|
||||
</shape>
|
||||
|
|
@ -9,12 +9,9 @@
|
|||
<shape
|
||||
android:shape="rectangle">
|
||||
<solid
|
||||
android:color="@color/deleteButton"/>
|
||||
android:color="?attr/mediaDetailNominationBackground"/>
|
||||
<corners
|
||||
android:radius="@dimen/progressbar_stroke" />
|
||||
<stroke
|
||||
android:width="5px"
|
||||
android:color="@color/deleteRed" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
|
|
|
|||
9
app/src/main/res/drawable/ic_info_outline_dark_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_info_outline_dark_24dp.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="@dimen/half_standard_height"
|
||||
android:height="@dimen/half_standard_height"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/button_background_dark"
|
||||
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_map_dark_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_map_dark_24dp.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="@dimen/half_standard_height"
|
||||
android:height="@dimen/half_standard_height"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/button_background_dark"
|
||||
android:pathData="M20.5,3l-0.16,0.03L15,5.1 9,3 3.36,4.9c-0.21,0.07 -0.36,0.25 -0.36,0.48V20.5c0,0.28 0.22,0.5 0.5,0.5l0.16,-0.03L9,18.9l6,2.1 5.64,-1.9c0.21,-0.07 0.36,-0.25 0.36,-0.48V3.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM15,19l-6,-2.11V5l6,2.11V19z"/>
|
||||
</vector>
|
||||
|
|
@ -10,15 +10,15 @@
|
|||
android:id="@+id/mediaDetailCategoryItemText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/subBackground"
|
||||
android:background="?attr/mainBackground"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/overflow_button_dimen"
|
||||
android:padding="@dimen/quarter_standard_height"
|
||||
android:textColor="@android:color/white"
|
||||
android:padding="@dimen/small_gap"
|
||||
android:textColor="?attr/mediaDetailsText"
|
||||
android:textSize="@dimen/description_text_size"
|
||||
app:drawablePadding="@dimen/small_gap"
|
||||
app:drawableStart="@drawable/ic_info_outline_24dp"
|
||||
app:drawablePadding="@dimen/tiny_gap"
|
||||
app:drawableStart="?attr/iconInfo24"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
|||
|
|
@ -19,11 +19,10 @@
|
|||
/>
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/mediaDetailImage"
|
||||
android:id="@+id/mediaDetailImageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:actualImageScaleType="centerCrop"
|
||||
/>
|
||||
android:layout_height="@dimen/dimen_250"
|
||||
app:actualImageScaleType="none" />
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/mediaDetailScrollView"
|
||||
|
|
@ -40,257 +39,200 @@
|
|||
|
||||
<!-- Placeholder. Height gets set at runtime based on container size; the initial value is a hack to keep
|
||||
the detail info offscreen until it's placed properly. May be a better way to do this. -->
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/mediaDetailImageView"
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_250"
|
||||
app:actualImageScaleType="none" />
|
||||
android:orientation="vertical"
|
||||
android:background="@android:color/transparent"
|
||||
android:id="@+id/mediaDetailImageViewSpacer"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/fragmentCategorisationBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
android:background="?attr/mainBackground"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/subBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
android:background="@color/primaryDarkColor"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/quarter_standard_height">
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/tiny_gap"
|
||||
android:text="@string/media_detail_title"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/normal_text"
|
||||
android:textStyle="bold" />
|
||||
style="@style/MediaDetailTextLabelTitle"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/media_detail_title" />
|
||||
|
||||
<TextView
|
||||
style="@style/MediaDetailTextBody"
|
||||
android:id="@+id/mediaDetailTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:background="?attr/subBackground"
|
||||
android:padding="@dimen/small_gap"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/description_text_size"
|
||||
android:layout_height="match_parent"
|
||||
tools:text="Title of the media" />
|
||||
</LinearLayout>
|
||||
|
||||
<fr.free.nrw.commons.media.MediaDetailSpacer
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/small_gap" />
|
||||
|
||||
<LinearLayout
|
||||
style="@style/MediaDetailContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/authorLinearLayout"
|
||||
android:background="?attr/subBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/tiny_gap"
|
||||
android:text="@string/media_detail_author"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/normal_text"
|
||||
android:textStyle="bold" />
|
||||
style="@style/MediaDetailTextLabelGeneric"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/media_detail_author" />
|
||||
|
||||
<TextView
|
||||
style="@style/MediaDetailTextBody"
|
||||
android:id="@+id/mediaDetailAuthor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:background="?attr/subBackground"
|
||||
android:padding="@dimen/small_gap"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/description_text_size"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
tools:text="Media author user name goes here." />
|
||||
</LinearLayout>
|
||||
|
||||
<fr.free.nrw.commons.media.MediaDetailSpacer
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/small_gap" />
|
||||
|
||||
<LinearLayout
|
||||
style="@style/MediaDetailContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/subBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/tiny_gap"
|
||||
android:text="@string/media_detail_description"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/normal_text"
|
||||
android:textStyle="bold" />
|
||||
style="@style/MediaDetailTextLabelGeneric"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/media_detail_description" />
|
||||
|
||||
<fr.free.nrw.commons.ui.widget.HtmlTextView
|
||||
android:id="@+id/mediaDetailDesc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="70"
|
||||
android:layout_gravity="start"
|
||||
android:background="?attr/subBackground"
|
||||
android:padding="@dimen/small_gap"
|
||||
android:textColor="@android:color/white"
|
||||
android:textColor="?attr/mediaDetailsText"
|
||||
android:textSize="@dimen/description_text_size"
|
||||
tools:text="Description of the media goes here. This can potentially be fairly long, and will need to wrap across multiple lines. We hope it looks nice though." />
|
||||
</LinearLayout>
|
||||
|
||||
<fr.free.nrw.commons.media.MediaDetailSpacer
|
||||
<View
|
||||
android:background="?attr/mediaDetailSpacerColor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/small_gap" />
|
||||
android:layout_height="@dimen/tiny_gap"/>
|
||||
|
||||
<LinearLayout
|
||||
style="@style/MediaDetailContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/subBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/tiny_gap"
|
||||
android:text="@string/media_detail_license"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/normal_text"
|
||||
android:textStyle="bold" />
|
||||
style="@style/MediaDetailTextLabelGeneric"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/media_detail_license" />
|
||||
|
||||
<fr.free.nrw.commons.ui.widget.CompatTextView
|
||||
android:id="@+id/mediaDetailLicense"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="70"
|
||||
android:layout_gravity="start"
|
||||
android:background="?attr/subBackground"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="@dimen/small_gap"
|
||||
android:textColor="@android:color/white"
|
||||
android:textColor="?attr/mediaDetailsText"
|
||||
android:textSize="@dimen/description_text_size"
|
||||
app:drawablePadding="@dimen/tiny_gap"
|
||||
app:drawableStart="@drawable/ic_info_outline_24dp"
|
||||
app:drawableStart="?attr/iconInfo24"
|
||||
tools:text="License link" />
|
||||
</LinearLayout>
|
||||
|
||||
<fr.free.nrw.commons.media.MediaDetailSpacer
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/small_gap" />
|
||||
|
||||
<LinearLayout
|
||||
style="@style/MediaDetailContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/subBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/tiny_gap"
|
||||
android:text="@string/media_detail_coordinates"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/normal_text"
|
||||
android:textStyle="bold" />
|
||||
style="@style/MediaDetailTextLabelGeneric"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/media_detail_coordinates" />
|
||||
|
||||
<fr.free.nrw.commons.ui.widget.CompatTextView
|
||||
android:id="@+id/mediaDetailCoordinates"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="70"
|
||||
android:layout_gravity="start"
|
||||
android:background="?attr/subBackground"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="@dimen/small_gap"
|
||||
android:textColor="@android:color/white"
|
||||
android:textColor="?attr/mediaDetailsText"
|
||||
android:textSize="@dimen/description_text_size"
|
||||
app:drawablePadding="@dimen/tiny_gap"
|
||||
app:drawableStart="@drawable/ic_map_white_24dp"
|
||||
app:drawableStart="?attr/iconMap24"
|
||||
tools:text="Coordinates link" />
|
||||
</LinearLayout>
|
||||
|
||||
<fr.free.nrw.commons.media.MediaDetailSpacer
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/small_gap" />
|
||||
|
||||
<LinearLayout
|
||||
style="@style/MediaDetailContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/subBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap"
|
||||
android:orientation="horizontal"
|
||||
android:textStyle="bold">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:paddingBottom="@dimen/tiny_gap"
|
||||
android:text="@string/detail_panel_cats_label"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/normal_text"
|
||||
android:textStyle="bold" />
|
||||
style="@style/MediaDetailTextLabelGeneric"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/detail_panel_cats_label" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/mediaDetailCategoryContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="70"
|
||||
android:orientation="vertical" />
|
||||
</LinearLayout>
|
||||
|
||||
<fr.free.nrw.commons.media.MediaDetailSpacer
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/small_gap" />
|
||||
|
||||
<LinearLayout
|
||||
style="@style/MediaDetailContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/subBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/tiny_gap"
|
||||
android:text="@string/media_detail_uploaded_date"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/normal_text"
|
||||
android:textStyle="bold" />
|
||||
style="@style/MediaDetailTextLabelGeneric"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/media_detail_uploaded_date" />
|
||||
|
||||
<TextView
|
||||
style="@style/MediaDetailTextBody"
|
||||
android:id="@+id/mediaDetailuploadeddate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:background="?attr/subBackground"
|
||||
android:padding="@dimen/small_gap"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/description_text_size"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
tools:text="Uploaded date" />
|
||||
</LinearLayout>
|
||||
|
||||
<fr.free.nrw.commons.media.MediaDetailSpacer
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/small_gap" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/nominatedDeletionBanner"
|
||||
android:background="@color/deleteRed"
|
||||
android:background="?attr/mediaDetailNominationBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap"
|
||||
android:padding="@dimen/quarter_standard_height"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -299,6 +241,7 @@
|
|||
android:textColor="@color/primaryTextColor"
|
||||
android:textSize="@dimen/normal_text"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/seeMore"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -310,35 +253,23 @@
|
|||
android:textStyle="bold"/>
|
||||
</LinearLayout>
|
||||
|
||||
<fr.free.nrw.commons.media.MediaDetailSpacer
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/small_gap" />
|
||||
|
||||
<LinearLayout
|
||||
style="@style/MediaDetailContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/subBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/tiny_gap"
|
||||
android:text="@string/media_detail_discussion"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/normal_text"
|
||||
android:textStyle="bold" />
|
||||
style="@style/MediaDetailTextLabelGeneric"
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/media_detail_discussion" />
|
||||
|
||||
<TextView
|
||||
style="@style/MediaDetailTextBody"
|
||||
android:id="@+id/mediaDetailDisc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:background="?attr/subBackground"
|
||||
android:padding="@dimen/small_gap"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/description_text_size" />
|
||||
android:layout_width="@dimen/widget_margin"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
|
|
@ -346,7 +277,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/standard_gap"
|
||||
android:background="@color/button_blue"
|
||||
android:background="@drawable/bg_copy_wikitext_button"
|
||||
android:text="@string/copy_wikicode"
|
||||
android:textColor="@color/primaryTextColor" />
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
<!-- I have done this intentionally, the mapview because of some elevation or something,
|
||||
sometimes hangs over the drawer layout and sometimes draws its onPaused state over the contributions, this seems to be the probable fix -->
|
||||
<FrameLayout
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/nearby_filter">
|
||||
|
|
@ -40,7 +40,19 @@
|
|||
android:layout_height="match_parent"
|
||||
android:background="@android:color/transparent" />
|
||||
|
||||
</FrameLayout>
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tv_attribution"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:text="@string/map_attribution"
|
||||
android:textAlignment="center"
|
||||
android:textSize="10sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
<Button
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.github.chrisbanes.photoview.PhotoView
|
||||
<fr.free.nrw.commons.media.zoomControllers.zoomable.ZoomableDraweeView
|
||||
android:id="@+id/backgroundImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:actualImageScaleType="fitXY" />
|
||||
android:scaleType="fitXY"
|
||||
/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@
|
|||
<attr name="mainTabBackground" format="reference"/>
|
||||
<attr name="mainCardBackground" format="reference"/>
|
||||
<attr name="mainScreenNearbyPermissionbutton" format="reference"/>
|
||||
<attr name="iconInfo24" format="reference" />
|
||||
<attr name="iconMap24" format="reference" />
|
||||
<attr name="mediaDetailsText" format="reference" />
|
||||
<attr name="mediaDetailsHeadingText" format="reference" />
|
||||
<attr name="mediaDetailNominationBackground" format="reference" />
|
||||
<attr name="mediaDetailSpacerColor" format="reference" />
|
||||
<attr name="icon" format="reference"/>
|
||||
<attr name="aboutIconsColor" format="reference"/>
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
<color name="primaryTextColor">#ffffff</color>
|
||||
<color name="secondaryTextColor">#000000</color>
|
||||
|
||||
<color name="deleteRed">#90960a0a</color>
|
||||
<color name="deleteRed">#D32F2F</color>
|
||||
<color name="deleteRedDark">#90960a0a</color>
|
||||
<color name="deleteButton">#44000000</color>
|
||||
<color name="deleteButtonDark">#88000000</color>
|
||||
<color name="deleteButtonLight">#44ffffff</color>
|
||||
|
|
|
|||
|
|
@ -610,5 +610,7 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="ask_to_turn_location_on">Turn on location?</string>
|
||||
<string name="nearby_needs_location">Nearby needs location enabled to work properly</string>
|
||||
<string name="use_location_from_similar_image">Did you shoot these two pictures at the same place? Do you want to use the latitude/longitude of the picture on the right?</string>
|
||||
|
||||
<string name="mapbox_telemetry">Telemetry Opt Out</string>
|
||||
<string name="telemetry_opt_out_summary">Send anonymized location and usage data to Mapbox when using Nearby feature</string>
|
||||
<string name="map_attribution" translatable="false"><![CDATA[© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> <a href="https://www.mapbox.com/map-feedback/">Improve this map</a>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@
|
|||
<item name="textEnabled">@color/enabled_button_text_color_dark</item>
|
||||
<item name="mainCardBackground">@color/main_background_dark</item>
|
||||
<item name="mainScreenNearbyPermissionbutton">@style/DarkFlatNearbyPermissionButton</item>
|
||||
<item name="iconInfo24">@drawable/ic_info_outline_24dp</item>
|
||||
<item name="iconMap24" >@drawable/ic_map_white_24dp</item>
|
||||
<item name="mediaDetailsText" >@color/white</item>
|
||||
<item name="mediaDetailsHeadingText">@color/layout_light_grey</item>
|
||||
<item name="mediaDetailNominationBackground">@color/deleteRedDark</item>
|
||||
<item name="mediaDetailSpacerColor">@color/browser_actions_divider_color</item>
|
||||
</style>
|
||||
|
||||
<style name="LightAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
|
|
@ -69,6 +75,12 @@
|
|||
<item name="textEnabled">@color/enabled_button_text_color_light</item>
|
||||
<item name="mainCardBackground">@color/primaryDarkColor</item>
|
||||
<item name="mainScreenNearbyPermissionbutton">@style/LightFlatNearbyPermissionButton</item>
|
||||
<item name="iconInfo24">@drawable/ic_info_outline_dark_24dp</item>
|
||||
<item name="iconMap24">@drawable/ic_map_dark_24dp</item>
|
||||
<item name="mediaDetailsText">@color/enabled_button_text_color_light</item>
|
||||
<item name="mediaDetailsHeadingText">@color/primaryDarkColor</item>
|
||||
<item name="mediaDetailNominationBackground">@color/deleteRed</item>
|
||||
<item name="mediaDetailSpacerColor">@color/divider_grey</item>
|
||||
</style>
|
||||
|
||||
<style name="WhiteSearchBarTheme" parent="DarkAppTheme">
|
||||
|
|
@ -129,4 +141,35 @@
|
|||
<item name="centerRegion">#906078</item>
|
||||
</style>
|
||||
|
||||
<style name="MediaDetailContainer">
|
||||
<item name="android:paddingLeft">@dimen/quarter_standard_height</item>
|
||||
<item name="android:paddingRight">@dimen/quarter_standard_height</item>
|
||||
<item name="android:paddingTop">@dimen/tiny_gap</item>
|
||||
<item name="android:paddingBottom">@dimen/tiny_gap</item>
|
||||
</style>
|
||||
|
||||
<style name="MediaDetailTextLabel">
|
||||
<item name="android:layout_weight">30</item>
|
||||
<item name="android:paddingTop">@dimen/dimen_6</item>
|
||||
<item name="android:paddingLeft">@dimen/tiny_gap</item>
|
||||
<item name="android:textSize">@dimen/normal_text</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
</style>
|
||||
|
||||
<style name="MediaDetailTextLabelTitle" parent="@style/MediaDetailTextLabel">
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="MediaDetailTextLabelGeneric" parent="@style/MediaDetailTextLabel">
|
||||
<item name="android:textColor">?attr/mediaDetailsHeadingText</item>
|
||||
</style>
|
||||
|
||||
<style name="MediaDetailTextBody">
|
||||
<item name="android:layout_weight">70</item>
|
||||
<item name="android:layout_gravity">start</item>
|
||||
<item name="android:padding">@dimen/small_gap</item>
|
||||
<item name="android:textColor">?attr/mediaDetailsText</item>
|
||||
<item name="android:textSize">@dimen/description_text_size</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
@ -85,6 +85,13 @@
|
|||
android:summary="@string/manage_exif_tags_summary"
|
||||
android:title="@string/manage_exif_tags" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="telemetryOptOut"
|
||||
app:singleLineTitle="false"
|
||||
android:summary="@string/telemetry_opt_out_summary"
|
||||
android:title="@string/mapbox_telemetry" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<!-- The key 'allowGps' was used before and has since been removed based on the discussion at #1599.
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ class CategoriesModelTest {
|
|||
@Mock
|
||||
internal var categoryInterface: CategoryInterface? = null
|
||||
|
||||
@Mock
|
||||
internal var categoryItem: CategoryItem? = null
|
||||
|
||||
@Spy
|
||||
internal lateinit var gson: Gson
|
||||
|
||||
|
|
@ -43,28 +40,6 @@ class CategoriesModelTest {
|
|||
MockitoAnnotations.initMocks(this)
|
||||
}
|
||||
|
||||
// Test Case for verifying that Categories search (MW api calls) are case-insensitive
|
||||
@Test
|
||||
fun searchAllFoundCaseTest() {
|
||||
val mwQueryPage = Mockito.mock(MwQueryPage::class.java)
|
||||
Mockito.`when`(mwQueryPage.title()).thenReturn("Category:Test")
|
||||
val mwQueryResult = Mockito.mock(MwQueryResult::class.java)
|
||||
Mockito.`when`(mwQueryResult.pages()).thenReturn(listOf(mwQueryPage))
|
||||
val mockResponse = Mockito.mock(MwQueryResponse::class.java)
|
||||
Mockito.`when`(mockResponse.query()).thenReturn(mwQueryResult)
|
||||
val categoriesModel: CategoriesModel = CategoriesModel(categoryClient,null,null)
|
||||
|
||||
Mockito.`when`(categoryInterface!!.searchCategoriesForPrefix(ArgumentMatchers.anyString(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt()))
|
||||
.thenReturn(Observable.just(mockResponse))
|
||||
|
||||
// Checking if both return "Test"
|
||||
val actualCategoryName = categoriesModel!!.searchAll("tes",null).blockingFirst()
|
||||
assertEquals("Test", actualCategoryName.getName())
|
||||
|
||||
val actualCategoryNameCaps = categoriesModel!!.searchAll("Tes",null).blockingFirst()
|
||||
assertEquals("Test", actualCategoryNameCaps.getName())
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing the substring search algorithm for Categories search
|
||||
* To be more precise it tests the In Between substring( ex: searching `atte`
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ class CategoryClientTest {
|
|||
{ fail("SearchCategories returned element when it shouldn't have.") },
|
||||
{ s -> throw s })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchCategoriesForPrefixFound() {
|
||||
val mwQueryPage = Mockito.mock(MwQueryPage::class.java)
|
||||
|
|
@ -93,7 +92,6 @@ class CategoryClientTest {
|
|||
{ fail("SearchCategories returned element when it shouldn't have.") },
|
||||
{ s -> throw s })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getParentCategoryListFound() {
|
||||
val mwQueryPage = Mockito.mock(MwQueryPage::class.java)
|
||||
|
|
|
|||
|
|
@ -109,20 +109,20 @@ class UploadMediaPresenterTest {
|
|||
@Test
|
||||
fun handleImageResult() {
|
||||
//Positive case test
|
||||
uploadMediaPresenter.handleImageResult(IMAGE_KEEP)
|
||||
uploadMediaPresenter.handleImageResult(IMAGE_KEEP, uploadItem)
|
||||
verify(view).onImageValidationSuccess()
|
||||
|
||||
//Duplicate file name
|
||||
uploadMediaPresenter.handleImageResult(FILE_NAME_EXISTS)
|
||||
uploadMediaPresenter.handleImageResult(FILE_NAME_EXISTS, uploadItem)
|
||||
verify(view).showDuplicatePicturePopup()
|
||||
|
||||
//Empty Title test
|
||||
uploadMediaPresenter.handleImageResult(EMPTY_TITLE)
|
||||
uploadMediaPresenter.handleImageResult(EMPTY_TITLE, uploadItem)
|
||||
verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
|
||||
|
||||
//Bad Picture test
|
||||
//Empty Title test
|
||||
uploadMediaPresenter.handleImageResult(-7)
|
||||
uploadMediaPresenter.handleImageResult(-7, uploadItem)
|
||||
verify(view).showBadImagePopup(ArgumentMatchers.anyInt())
|
||||
|
||||
}
|
||||
|
|
@ -158,8 +158,8 @@ class UploadMediaPresenterTest {
|
|||
*/
|
||||
@Test
|
||||
fun handleBadImageBaseTestInvalidLocation() {
|
||||
uploadMediaPresenter.handleBadImage(8)
|
||||
verify(repository).saveValue(ArgumentMatchers.anyString(), eq(false))
|
||||
uploadMediaPresenter.handleBadImage(8, uploadItem)
|
||||
verify(uploadItem).setHasInvalidLocation(true)
|
||||
verify(view).showBadImagePopup(8)
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ class UploadMediaPresenterTest {
|
|||
*/
|
||||
@Test
|
||||
fun handleBadImageBaseTestEmptyTitle() {
|
||||
uploadMediaPresenter.handleBadImage(-3)
|
||||
uploadMediaPresenter.handleBadImage(-3, uploadItem)
|
||||
verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
|
||||
}
|
||||
|
||||
|
|
@ -177,7 +177,7 @@ class UploadMediaPresenterTest {
|
|||
*/
|
||||
@Test
|
||||
fun handleBadImageBaseTestFileNameExists() {
|
||||
uploadMediaPresenter.handleBadImage(-4)
|
||||
uploadMediaPresenter.handleBadImage(-4, uploadItem)
|
||||
verify(view).showDuplicatePicturePopup()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package fr.free.nrw.commons.utils
|
||||
|
||||
import org.hamcrest.core.IsEqual.equalTo
|
||||
import org.junit.Assert.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
class CommonsDateUtilTest {
|
||||
|
||||
@Test
|
||||
fun `Iso8601DateFormatTimestamp parses legal date`() {
|
||||
val iso8601DateFormatTimestamp = CommonsDateUtil
|
||||
.getIso8601DateFormatTimestamp()
|
||||
val parsedDate = iso8601DateFormatTimestamp
|
||||
.parse("2020-04-07T14:21:57Z")
|
||||
assertThat(
|
||||
"2020-04-07T14:21:57Z",
|
||||
equalTo(iso8601DateFormatTimestamp.format(parsedDate))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -50,14 +50,6 @@ class WikidataEditServiceTest {
|
|||
verifyZeroInteractions(wikidataClient!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun noClaimsWhenLocationIsNotCorrect() {
|
||||
`when`(directKvStore!!.getBoolean("Picture_Has_Correct_Location", true))
|
||||
.thenReturn(false)
|
||||
wikidataEditService!!.createClaimWithLogging("Q1", "","Test.jpg","")
|
||||
verifyZeroInteractions(wikidataClient!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createClaimWithLogging() {
|
||||
`when`(directKvStore!!.getBoolean("Picture_Has_Correct_Location", true))
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ buildscript {
|
|||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.1'
|
||||
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||
classpath "com.hiya:jacoco-android:0.2"
|
||||
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ LEAK_CANARY_VERSION=1.6.2
|
|||
DAGGER_VERSION=2.21
|
||||
ROOM_VERSION=2.2.3
|
||||
PREFERENCE_VERSION=1.1.0
|
||||
OKHTTP_VERSION=3.12.1
|
||||
|
||||
systemProp.http.proxyPort=0
|
||||
systemProp.http.proxyHost=
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue