From ddd3e1212ac6e61e55e8887047f175e18892150c Mon Sep 17 00:00:00 2001 From: Ashish Date: Mon, 14 Sep 2020 16:41:46 +0530 Subject: [PATCH] Sync master with release (#3922) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #3624 DateTimeFormat wrong - match pattern returned from servers (#3625) * Revert "Fixes: #3179 Make category search non case-sensitive (#3326)" (#3636) Simply lower casing the name of the category sent to the server doesn't result in the server doing a case insensitive category search. In fact, it reduces the category search space as only categories that has a lower case character is searched even if the search text contains upper case characters. The test case did not catch this issue as the first character of the title is case insensitive[1]. So, revert the changes done in commit afdeaae0757d4d7773921169eb65d3ba9916834a. See further disucssion in the issue thread of #3179 starting from [2]. [1]: https://www.mediawiki.org/wiki/Manual:Page_title [2]: https://github.com/commons-app/apps-android-commons/issues/3179#issuecomment-605462140 * Bugfix/security exception (#3627) * Fixes #3626 * Check is file is actually created before writing to file, file picker android * Handle Security exception * Fixes #3436 and #2881: Media Detail design Overhaul (#3505) * ic_map_dark_24dp: map icon for white background * ic_info_outline_dark_24dp: info icon for dark background * MediaDetailFragment: update the spacer as per image aspect ratio * fragment_media_detail: design overhaul * fragment_media_detail: remove redundant background color statements * make requested changes * add dark mode support * minor ui tweak * white map icon in dark mode * make rquested changes * make requested changes to layout * fix misalignment of category list * subtle amendments * convert comments to javadocs * minor amendments * minor changes * add styles for media detail * Media detail fragment refactored * make suggested changes * minor name fix * fix the delete button border * Fixes #3639 (Fix Save State implementation of CheckBoxTriState ) (#3686) * Add #3723 and #3721 to 2.13 release, fix conflicts Conflicts were caused by merging #3723 before #3721 , so I just rolled both into one commit. * Fix NullPointer when clicking on image in MediaDetailFragment (#3730)… (#3739) * Update changelog.md * Versioning for v2.13 * Fixes #3705 (Crash when viewing pic I just uploaded) (#3782) * Fixes #3705 * Let the MediaDetailPager fragment know when the contributions have been updated * Handle NPE, null check on adapter in MediaDetailPagerFragment * Fixed BookmarkLocationsDao DB migration (#3793) * Fixes #3725 (#3795) * Downgraded okhttp version to support Api 19 devices * Handled null CompoundDrawable[2] in etTitle-> UploadMediaDetailsFragment (#3828) * DownSample Upload image to be shown in UploadMediaDetailFragment to handle OOM, Bitmap Too large exception (#3830) * Fixes #3829 * DownSample Upload image to be shown in UploadMediaDetailFragment to handle OOM, Bitmap Too large exception * removed unused imports, handled possible exceptions * Let Fresco handle the downsampling of image * invalidate in onTransformEnd * Expose an interface TransformationListener in ZoomableDraweeView to listen to transformation change end * removed photoView dependency * removed unused imports in ZoomableActivity * Bugfix, expand/collapse * changed functio name * Bugfix/p18 uploads (#3869) * updated gradle plugin version * BugFix #3856 * Do not use preference for deciding acceptable lat long for nearby uploads, instead save the corresponding location in the Contribution via UploadItem * Marshall contribution's hasInvalidLocation * reset un-related changes * Fixed test cases * Minor code formatting and docs * Fixes #3882 (#3883) * Make hasInvalidLocation non-null integer with default value 0 Co-authored-by: Ashish Kumar * Fixes #3766, Added OPENSTREET attribution (#3889) * Fixes #3766 * Added OPENSTREET attribution in nearby * Added custom text attribution in Nearby * Deleted unused class CustomBorderTextView * review suggested changes * modified telemetry summary string * Versioning and changelog for v2.13.1 (#3908) * Update changelog.md * Versioning for v2.13.1 * Fixes #3914 (#3915) * Verify user login before setting upload count * fixed compile-time error * fix erros * delete emptied files * remove empty file CategoriesModel.java Co-authored-by: Seán Mac Gillicuddy Co-authored-by: Kaartic Sivaraam Co-authored-by: Kshitij Bhardwaj <44129798+kbhardwaj123@users.noreply.github.com> Co-authored-by: Vitaly V. Pinchuk Co-authored-by: Josephine Lim Co-authored-by: Ashish Kumar --- CHANGELOG.md | 12 + app/build.gradle | 15 +- .../locations/BookmarkLocationsDao.java | 56 ++- .../nrw/commons/contributions/Contribution.kt | 15 +- .../contributions/ContributionsFragment.java | 21 +- .../ContributionsListFragment.java | 2 +- .../commons/di/CommonsApplicationModule.java | 20 +- .../free/nrw/commons/di/NetworkingModule.java | 2 +- .../nrw/commons/filepicker/FilePicker.java | 4 +- .../nrw/commons/filepicker/PickedFiles.java | 9 +- .../media/MediaDetailPagerFragment.java | 4 +- .../nrw/commons/media/ZoomableActivity.java | 7 - .../zoomable/ZoomableDraweeView.java | 19 +- .../nrw/commons/nearby/CheckBoxTriStates.java | 74 +-- .../fragments/NearbyParentFragment.java | 15 +- .../fr/free/nrw/commons/settings/Prefs.java | 1 + .../commons/settings/SettingsFragment.java | 20 + .../free/nrw/commons/upload/UploadItem.java | 9 + .../free/nrw/commons/upload/UploadModel.java | 8 + .../nrw/commons/upload/UploadService.java | 11 +- .../UploadMediaDetailFragment.java | 70 +-- .../mediaDetails/UploadMediaPresenter.java | 12 +- .../main/res/layout/fragment_media_detail.xml | 440 +++++++++--------- .../res/layout/fragment_nearby_parent.xml | 16 +- .../fragment_upload_media_detail_fragment.xml | 236 +++++----- app/src/main/res/values/strings.xml | 3 + app/src/main/res/xml/preferences.xml | 7 + .../commons/category/CategoryClientTest.kt | 2 - .../upload/UploadMediaPresenterTest.kt | 1 - .../wikidata/WikidataEditServiceTest.kt | 4 +- gradle.properties | 1 + 31 files changed, 604 insertions(+), 512 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1586f0db4..383f725d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Wikimedia Commons for Android +## 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 diff --git a/app/build.gradle b/app/build.gradle index dd64aa19b..ff349217f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,7 +21,9 @@ dependencies { // Utils implementation 'in.yuvi:http.fluent:1.3' implementation 'com.google.code.gson:gson:2.8.5' - implementation 'com.squareup.okhttp3:okhttp:4.8.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,6 +37,7 @@ 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' implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-scalebar-v9:0.4.0' @@ -51,7 +54,7 @@ dependencies { testImplementation "androidx.paging:paging-common-ktx:$PAGING_VERSION" implementation "androidx.paging:paging-rxjava2-ktx:$PAGING_VERSION" implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02" - implementation 'com.squareup.okhttp3:okhttp-ws:3.4.1' + implementation "com.squareup.okhttp3:okhttp-ws:$OKHTTP_VERSION" // Logging implementation 'ch.acra:acra-dialog:5.3.0' @@ -60,7 +63,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.5.0" + implementation "com.squareup.okhttp3:logging-interceptor:$OKHTTP_VERSION" // Dependency injector implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION" @@ -81,7 +84,7 @@ dependencies { testImplementation 'junit:junit:4.13' testImplementation 'org.robolectric:robolectric:4.3' testImplementation 'androidx.test:core:1.2.0' - testImplementation "com.squareup.okhttp3:mockwebserver:4.8.0" + testImplementation "com.squareup.okhttp3:mockwebserver:$OKHTTP_VERSION" testImplementation "org.powermock:powermock-module-junit4:2.0.0-beta.5" testImplementation "org.powermock:powermock-api-mockito2:2.0.0-beta.5" testImplementation 'org.mockito:mockito-core:2.23.0' @@ -139,8 +142,8 @@ android { defaultConfig { //applicationId 'fr.free.nrw.commons' - versionCode 561 - versionName '2.12.3' + versionCode 775 + versionName '2.13.1' setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName()) minSdkVersion 19 diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.java b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.java index 4b9fe4b55..c58482f76 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.java +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.java @@ -248,24 +248,44 @@ public class BookmarkLocationsDao { public static void onUpdate(SQLiteDatabase db, int from, int to) { Timber.d("bookmarksLocations db is updated from:"+from+", to:"+to); - switch (from) { - case 7: onCreate(db); - case 8: // No change - case 9: // No change - case 10: - try { - db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_pic STRING;"); - } catch (SQLiteException exception){ - Timber.e(exception); - } - case 11: // No change - case 12: - try { - db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_destroyed STRING;"); - }catch (SQLiteException exception){ - Timber.e(exception); - } - break; + if (from == to) { + return; + } + if (from < 7) { + // doesn't exist yet + from++; + onUpdate(db, from, to); + return; + } + if (from == 7) { + // table added in version 8 + onCreate(db); + from++; + onUpdate(db, from, to); + return; + } + if (from == 8) { + from++; + onUpdate(db, from, to); + return; + } + 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 necessary then + try { + db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_pic STRING;"); + }catch (SQLiteException exception){ + Timber.e(exception);// + } + return; + } + if (from == 12) { + try { + db.execSQL( + "ALTER TABLE bookmarksLocations ADD COLUMN location_destroyed STRING;"); + } catch (SQLiteException exception) { + Timber.e(exception); + } } } } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt b/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt index 592ec9126..72f534c4d 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt +++ b/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt @@ -38,7 +38,8 @@ data class Contribution constructor( val localUri: Uri? = null, var dataLength: Long = 0, var dateCreated: Date? = null, - var dateModified: Date? = null + var dateModified: Date? = null, + var hasInvalidLocation : Int = 0 ) : Parcelable { fun completeWith(media: Media): Contribution { @@ -65,6 +66,18 @@ data class Contribution constructor( wikidataPlace = from(item.place) ) + /** + * Set this true when ImageProcessor has said that the location is invalid + * @param hasInvalidLocation + */ + fun setHasInvalidLocation(hasInvalidLocation: Boolean) { + this.hasInvalidLocation = if (hasInvalidLocation) 1 else 0 + } + + fun hasInvalidLocation(): Boolean { + return hasInvalidLocation == 1 + } + companion object { const val STATE_COMPLETED = -1 const val STATE_FAILED = 1 diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java index 13c9a10c2..ad7e7f8c7 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java @@ -22,6 +22,15 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; 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; + +import javax.inject.Inject; +import javax.inject.Named; + import butterknife.BindView; import butterknife.ButterKnife; import fr.free.nrw.commons.Media; @@ -83,6 +92,9 @@ public class ContributionsFragment @Inject ContributionsPresenter contributionsPresenter; + @Inject + SessionManager sessionManager; + private LatLng curLatLng; private boolean firstLocationUpdate = true; @@ -143,7 +155,14 @@ public class ContributionsFragment initFragments(); - if (!ConfigUtils.isBetaFlavour()) { + if(shouldShowMediaDetailsFragment){ + showMediaDetailPagerFragment(); + }else{ + showContributionsListFragment(); + } + + if (!ConfigUtils.isBetaFlavour() && sessionManager.isUserLoggedIn() + && sessionManager.getCurrentAccount() != null) { setUploadCount(); } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java index 998b5d510..4a435b28f 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java @@ -132,7 +132,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl getSpanCount(getResources().getConfiguration().orientation)); rvContributionsList.setLayoutManager(layoutManager); contributionsListPresenter.setup(); - contributionsListPresenter.contributionList.observe(this, adapter::submitList); + contributionsListPresenter.contributionList.observe(this.getViewLifecycleOwner(), adapter::submitList); rvContributionsList.setAdapter(adapter); } diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java index c76c54673..753836a6c 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java @@ -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.google.gson.Gson; import dagger.Module; import dagger.Provides; @@ -49,6 +51,15 @@ public class CommonsApplicationModule { private Context applicationContext; public static final String IO_THREAD="io_thread"; 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; @@ -103,11 +114,6 @@ public class CommonsApplicationModule { return context.getContentResolver().acquireContentProviderClient(BuildConfig.CATEGORY_AUTHORITY); } - /** - * This method is used to provide instance of DepictsContentProviderClient - * @param context context - * @return DepictsContentProviderClient*/ - /** * This method is used to provide instance of RecentSearchContentProviderClient * which provides content of Recent Searches from database @@ -224,9 +230,11 @@ public class CommonsApplicationModule { @Provides @Singleton public AppDatabase provideAppDataBase() { - return Room.databaseBuilder(applicationContext, AppDatabase.class, "commons_room.db") + appDatabase = Room.databaseBuilder(applicationContext, AppDatabase.class, "commons_room.db") + .addMigrations(MIGRATION_1_2) .fallbackToDestructiveMigration() .build(); + return appDatabase; } @Provides diff --git a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java index 84fdfe53a..f537b6f80 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java @@ -76,7 +76,7 @@ public class NetworkingModule { HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(message -> { Timber.tag("OkHttp").v(message); }); - httpLoggingInterceptor.level(BuildConfig.DEBUG ? Level.BODY: Level.BASIC); + httpLoggingInterceptor.setLevel(BuildConfig.DEBUG ? Level.BODY: Level.BASIC); return httpLoggingInterceptor; } diff --git a/app/src/main/java/fr/free/nrw/commons/filepicker/FilePicker.java b/app/src/main/java/fr/free/nrw/commons/filepicker/FilePicker.java index 5d168d6b1..698e2d51f 100644 --- a/app/src/main/java/fr/free/nrw/commons/filepicker/FilePicker.java +++ b/app/src/main/java/fr/free/nrw/commons/filepicker/FilePicker.java @@ -166,7 +166,7 @@ public class FilePicker implements Constants { public static List 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 getFilesFromGalleryPictures(Intent data, Activity activity) throws IOException { + private static List getFilesFromGalleryPictures(Intent data, Activity activity) throws IOException, SecurityException { List files = new ArrayList<>(); ClipData clipData = data.getClipData(); if (clipData == null) { diff --git a/app/src/main/java/fr/free/nrw/commons/filepicker/PickedFiles.java b/app/src/main/java/fr/free/nrw/commons/filepicker/PickedFiles.java index 86da1326b..01e68c940 100644 --- a/app/src/main/java/fr/free/nrw/commons/filepicker/PickedFiles.java +++ b/app/src/main/java/fr/free/nrw/commons/filepicker/PickedFiles.java @@ -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); } diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java index e1112f957..84147eef9 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java @@ -295,7 +295,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 diff --git a/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.java b/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.java index 089d16a0a..63b582550 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.java @@ -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; diff --git a/app/src/main/java/fr/free/nrw/commons/media/zoomControllers/zoomable/ZoomableDraweeView.java b/app/src/main/java/fr/free/nrw/commons/media/zoomControllers/zoomable/ZoomableDraweeView.java index 3cb2b2f91..02d93622b 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/zoomControllers/zoomable/ZoomableDraweeView.java +++ b/app/src/main/java/fr/free/nrw/commons/media/zoomControllers/zoomable/ZoomableDraweeView.java @@ -47,6 +47,7 @@ public class ZoomableDraweeView extends DraweeView private boolean mIsDialtoneEnabled = false; private boolean mZoomingEnabled = true; + private TransformationListener transformationListener; private final ControllerListener mControllerListener = new BaseControllerListener() { @@ -73,9 +74,18 @@ public class ZoomableDraweeView extends DraweeView } @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 protected ZoomableController createZoomableController() { return AnimatedZoomableController.newInstance(); } + + /** + * Use this, If someone is willing to listen to scale change + */ + public interface TransformationListener{ + void onTransformationEnd(); + } } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/CheckBoxTriStates.java b/app/src/main/java/fr/free/nrw/commons/nearby/CheckBoxTriStates.java index e8fc70873..db2c1f5d9 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/CheckBoxTriStates.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/CheckBoxTriStates.java @@ -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 CREATOR = - new Parcelable.Creator() { - @Override - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } - - @Override - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; - } } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java index 90fe7f598..05086dd9b 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java @@ -19,6 +19,8 @@ import android.graphics.Bitmap; import android.graphics.drawable.VectorDrawable; 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; @@ -39,6 +41,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; +import androidx.appcompat.widget.AppCompatTextView; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -75,7 +78,6 @@ import fr.free.nrw.commons.auth.LoginActivity; import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao; import fr.free.nrw.commons.contributions.ContributionController; import fr.free.nrw.commons.contributions.MainActivity; -import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.location.LocationServiceManager; @@ -154,6 +156,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment @BindView(R.id.rv_nearby_list) RecyclerView rvNearbyList; @BindView(R.id.no_results_message) TextView noResultsView; + @BindView(R.id.tv_attribution) + AppCompatTextView tvAttribution; @Inject LocationServiceManager locationManager; @Inject NearbyController nearbyController; @@ -235,8 +239,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment final 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); isMapBoxReady =true; performMapReadyActions(); @@ -259,6 +263,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment scaleBarPlugin.create(scaleBarOptions); }); }); + + tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution))); + tvAttribution.setMovementMethod(LinkMovementMethod.getInstance()); } /** @@ -659,7 +666,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 { diff --git a/app/src/main/java/fr/free/nrw/commons/settings/Prefs.java b/app/src/main/java/fr/free/nrw/commons/settings/Prefs.java index 8f625205c..1e09bc37e 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/Prefs.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/Prefs.java @@ -9,6 +9,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"; diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java index 53cf8d7fe..9013cebca 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java @@ -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; @@ -85,6 +87,24 @@ public class SettingsFragment extends PreferenceFragmentCompat { findPreference("displayLocationPermissionForCardView").setEnabled(false); findPreference("displayCampaignsCardView").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); + } } /** diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadItem.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadItem.java index 140edad24..13a797006 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadItem.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadItem.java @@ -22,6 +22,8 @@ public class UploadItem { private final long createdTimestamp; private final String createdTimestampSource; private final BehaviorSubject imageQuality; + private boolean hasInvalidLocation; + @SuppressLint("CheckResult") UploadItem(final Uri mediaUri, @@ -103,4 +105,11 @@ public class UploadItem { this.gpsCoords = gpsCoords; } + public void setHasInvalidLocation(boolean hasInvalidLocation) { + this.hasInvalidLocation=hasInvalidLocation; + } + + public boolean hasInvalidLocation() { + return hasInvalidLocation; + } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java index 6bf18bde9..b15e9ffab 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java @@ -141,6 +141,13 @@ public class UploadModel { { final Contribution contribution = new Contribution( item, sessionManager, newListOf(selectedDepictions), newListOf(selectedCategories)); + + contribution.setHasInvalidLocation(item.hasInvalidLocation()); + + Timber.d("Created timestamp while building contribution is %s, %s", + item.getCreatedTimestamp(), + new Date(item.getCreatedTimestamp())); + if (item.getCreatedTimestamp() != -1L) { contribution.setDateCreated(new Date(item.getCreatedTimestamp())); contribution.setDateCreatedSource(item.getCreatedTimestampSource()); @@ -188,4 +195,5 @@ public class UploadModel { public List getSelectedDepictions() { return selectedDepictions; } + } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java index 57e044019..909155303 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java @@ -22,6 +22,7 @@ import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.di.CommonsApplicationModule; import fr.free.nrw.commons.di.CommonsDaggerService; import fr.free.nrw.commons.media.MediaClient; +import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.wikidata.WikidataEditService; import io.reactivex.Observable; import io.reactivex.Scheduler; @@ -350,8 +351,14 @@ public class UploadService extends CommonsDaggerService { .add(wikidataEditService.addDepictionsAndCaptions(uploadResult, contribution)); WikidataPlace wikidataPlace = contribution.getWikidataPlace(); if (wikidataPlace != null && wikidataPlace.getImageValue() == null) { - wikidataEditService.createClaim(wikidataPlace, uploadResult.getFilename(), - contribution.getMedia().getCaptions()); + if (!contribution.hasInvalidLocation()) { + wikidataEditService.createClaim(wikidataPlace, uploadResult.getFilename(), + contribution.getMedia().getCaptions()); + } else { + ViewUtil.showShortToast(this, getString(R.string.wikidata_edit_failure)); + Timber + .d("Image location and nearby place location mismatched, so Wikidata item won't be edited"); + } } saveCompletedContribution(contribution, uploadResult); } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.java index 5a7506e93..0ffa54eea 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.java @@ -45,7 +45,7 @@ import org.apache.commons.lang3.StringUtils; import timber.log.Timber; public class UploadMediaDetailFragment extends UploadBaseFragment implements - UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener { + UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener { @BindView(R.id.tv_title) TextView tvTitle; @@ -98,7 +98,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { + @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_upload_media_detail_fragment, container, false); } @@ -111,7 +111,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements private void init() { tvTitle.setText(getString(R.string.step_count, callback.getIndexInViewFlipper(this) + 1, - callback.getTotalNumberOfSteps())); + callback.getTotalNumberOfSteps())); initRecyclerView(); initPresenter(); presenter.receiveImage(uploadableFile, place); @@ -140,10 +140,10 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements */ private void attachImageViewScaleChangeListener() { photoViewBackgroundImage.setOnScaleChangeListener( - (scaleFactor, focusX, focusY) -> { - //Whenever the uses plays with the image, lets collapse the media detail container - expandCollapseLlMediaDetail(false); - }); + (scaleFactor, focusX, focusY) -> { + //Whenever the uses plays with the image, lets collapse the media detail container + expandCollapseLlMediaDetail(false); + }); } /** @@ -228,16 +228,16 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements @Override public void onNearbyPlaceFound(UploadItem uploadItem, Place place) { DialogUtil.showAlertDialog(getActivity(), - getString(R.string.upload_nearby_place_found_title), - String.format(Locale.getDefault(), - getString(R.string.upload_nearby_place_found_description), - place.getName()), - () -> { - presenter.onUserConfirmedUploadIsOfPlace(place, callback.getIndexInViewFlipper(this)); - }, - () -> { + getString(R.string.upload_nearby_place_found_title), + String.format(Locale.getDefault(), + getString(R.string.upload_nearby_place_found_description), + place.getName()), + () -> { + presenter.onUserConfirmedUploadIsOfPlace(place, callback.getIndexInViewFlipper(this)); + }, + () -> { - }); + }); } @Override @@ -264,16 +264,16 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements public void showDuplicatePicturePopup(UploadItem uploadItem) { String uploadTitleFormat = getString(R.string.upload_title_duplicate); DialogUtil.showAlertDialog(getActivity(), - getString(R.string.duplicate_image_found), - String.format(Locale.getDefault(), - uploadTitleFormat, - uploadItem.getFileName()), - getString(R.string.upload), - getString(R.string.cancel), - () -> { - uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP); - onNextButtonClicked(); - }, null); + getString(R.string.duplicate_image_found), + String.format(Locale.getDefault(), + uploadTitleFormat, + uploadItem.getFileName()), + getString(R.string.upload), + getString(R.string.cancel), + () -> { + uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP); + onNextButtonClicked(); + }, null); } @@ -283,16 +283,16 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements String errorMessageForResult = getErrorMessageForResult(getContext(), errorCode); if (!StringUtils.isBlank(errorMessageForResult)) { DialogUtil.showAlertDialog(getActivity(), - getString(R.string.upload_problem_image), - errorMessageForResult, - getString(R.string.upload), - getString(R.string.cancel), + getString(R.string.upload_problem_image), + errorMessageForResult, + getString(R.string.upload), + getString(R.string.cancel), () -> { - uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP); - onNextButtonClicked(); - }, - () -> deleteThisPicture() - ); + uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP); + onNextButtonClicked(); + }, + () -> deleteThisPicture() + ); } //If the error message is null, we will probably not show anything } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaPresenter.java b/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaPresenter.java index ab1c229e8..69ba6b025 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaPresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaPresenter.java @@ -134,7 +134,7 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt .observeOn(mainThreadScheduler) .subscribe(imageResult -> { view.showProgress(false); - handleImageResult(imageResult, uploadItem); + handleImageResult(imageResult, uploadItem); }, throwable -> { view.showProgress(false); @@ -201,6 +201,7 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt UploadItem uploadItem) { if (imageResult == IMAGE_KEEP || imageResult == IMAGE_OK) { view.onImageValidationSuccess(); + uploadItem.setHasInvalidLocation(false); } else { handleBadImage(imageResult, uploadItem); } @@ -212,11 +213,12 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt * @param errorCode * @param uploadItem */ - public void handleBadImage(Integer errorCode, UploadItem uploadItem) { + public void handleBadImage(Integer errorCode, + UploadItem uploadItem) { Timber.d("Handle bad picture with error code %d", errorCode); - // If location of image and nearby does not match, then set shared preferences to disable wikidata edits - if (errorCode >= 8) { - defaultKVStore.putBoolean("Picture_Has_Correct_Location", false); + if (errorCode + >= 8) { // If location of image and nearby does not match + uploadItem.setHasInvalidLocation(true); } switch (errorCode) { diff --git a/app/src/main/res/layout/fragment_media_detail.xml b/app/src/main/res/layout/fragment_media_detail.xml index 863f2cb4f..d8af6179e 100644 --- a/app/src/main/res/layout/fragment_media_detail.xml +++ b/app/src/main/res/layout/fragment_media_detail.xml @@ -1,12 +1,12 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/mainBackground" + > + android:id="@+id/mediaDetailImageFailed" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center" + android:src="@android:drawable/ic_menu_close_clear_cancel" + android:visibility="gone" + android:contentDescription="@string/mediaimage_failed" + /> + android:id="@+id/mediaDetailImageView" + android:layout_width="match_parent" + android:layout_height="@dimen/dimen_250" + app:actualImageScaleType="none" /> + android:id="@+id/mediaDetailScrollView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@android:color/transparent" + android:cacheColorHint="@android:color/transparent" + android:fillViewport="true"> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + android:layout_width="match_parent" + android:layout_height="wrap_content" > + android:id="@+id/mediaDetailImageViewLandscape" + android:layout_width="match_parent" + android:layout_height="@dimen/dimen_250" + app:actualImageScaleType="none" + android:visibility="gone" /> @@ -77,32 +77,32 @@ + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/mainBackground" + android:orientation="vertical"> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@color/primaryDarkColor" + android:orientation="horizontal" + android:padding="@dimen/quarter_standard_height"> + style="@style/MediaDetailTextLabelTitle" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:text="@string/media_detail_title" /> + style="@style/MediaDetailTextBody" + android:id="@+id/mediaDetailTitle" + android:layout_width="@dimen/widget_margin" + android:textColor="@android:color/white" + android:layout_height="match_parent" + tools:text="Title of the media" /> + style="@style/MediaDetailContainer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/authorLinearLayout" + android:orientation="horizontal"> + style="@style/MediaDetailTextLabelGeneric" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:text="@string/media_detail_author" /> + style="@style/MediaDetailTextBody" + android:id="@+id/mediaDetailAuthor" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + tools:text="Media author user name goes here." /> + style="@style/MediaDetailContainer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + style="@style/MediaDetailTextLabelGeneric" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:text="@string/media_detail_description" /> + android:id="@+id/mediaDetailDesc" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:layout_weight="70" + android:layout_gravity="start" + android:padding="@dimen/small_gap" + 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." /> + android:background="?attr/mediaDetailSpacerColor" + android:layout_width="match_parent" + android:layout_height="@dimen/tiny_gap"/> + style="@style/MediaDetailContainer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + style="@style/MediaDetailTextLabelGeneric" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:text="@string/media_detail_license" /> + android:id="@+id/mediaDetailLicense" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:layout_weight="70" + android:layout_gravity="start" + android:foreground="?attr/selectableItemBackground" + android:gravity="center_vertical" + android:padding="@dimen/small_gap" + android:textColor="?attr/mediaDetailsText" + android:textSize="@dimen/description_text_size" + android:drawablePadding="@dimen/tiny_gap" + android:drawableStart="?attr/iconInfo24" + tools:text="License link" /> + style="@style/MediaDetailContainer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + style="@style/MediaDetailTextLabelGeneric" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:text="@string/media_detail_coordinates" /> + android:id="@+id/mediaDetailCoordinates" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:layout_weight="70" + android:layout_gravity="start" + android:foreground="?attr/selectableItemBackground" + android:gravity="center_vertical" + android:padding="@dimen/small_gap" + android:textColor="?attr/mediaDetailsText" + android:textSize="@dimen/description_text_size" + android:drawablePadding="@dimen/tiny_gap" + android:drawableStart="?attr/iconMap24" + tools:text="Coordinates link" /> - + - + + style="@style/MediaDetailContainer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:textStyle="bold"> + style="@style/MediaDetailTextLabelGeneric" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:text="@string/detail_panel_cats_label" /> + android:id="@+id/mediaDetailCategoryContainer" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:layout_weight="70" + android:orientation="vertical"> @@ -310,90 +310,90 @@ android:background="@drawable/ic_baseline_edit_24" /> + style="@style/MediaDetailContainer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + style="@style/MediaDetailTextLabelGeneric" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:text="@string/media_detail_uploaded_date" /> + style="@style/MediaDetailTextBody" + android:id="@+id/mediaDetailuploadeddate" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + tools:text="Uploaded date" /> + android:id="@+id/nominatedDeletionBanner" + android:background="?attr/mediaDetailNominationBackground" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="@dimen/quarter_standard_height" + android:visibility="gone"> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:text="@string/nominated_for_deletion" + android:textColor="@color/primaryTextColor" + android:textSize="@dimen/normal_text" + android:textStyle="bold"/> + android:id="@+id/seeMore" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:paddingTop="@dimen/standard_gap" + android:textColor="@color/primaryTextColor" + android:textSize="@dimen/normal_text" + android:textStyle="bold"/> + style="@style/MediaDetailContainer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + style="@style/MediaDetailTextLabelGeneric" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" + android:text="@string/media_detail_discussion" /> + style="@style/MediaDetailTextBody" + android:id="@+id/mediaDetailDisc" + android:layout_width="@dimen/widget_margin" + android:layout_height="match_parent" />