diff --git a/CHANGELOG.md b/CHANGELOG.md index 74ab55660..5cde699ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Wikimedia Commons for Android +## v2.10.2 +- Fixed remaining issues with date image taken +- Fixed database crash + ## v2.10.1 - Fixed "stuck before category selection screen" bug - Fixed notification taps diff --git a/app/build.gradle b/app/build.gradle index f14681653..a8e8f39ff 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -104,8 +104,8 @@ android { defaultConfig { applicationId 'fr.free.nrw.commons' - versionCode 226 - versionName '2.10.1' + versionCode 243 + versionName '2.10.2' setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName()) minSdkVersion 19 diff --git a/app/src/main/java/fr/free/nrw/commons/Utils.java b/app/src/main/java/fr/free/nrw/commons/Utils.java index c912d9fcc..401901437 100644 --- a/app/src/main/java/fr/free/nrw/commons/Utils.java +++ b/app/src/main/java/fr/free/nrw/commons/Utils.java @@ -63,12 +63,8 @@ public class Utils { return R.string.license_name_cc_by_sa_four; case Prefs.Licenses.CC0: return R.string.license_name_cc0; - case Prefs.Licenses.CC_BY: // for backward compatibility to v2.1 - return R.string.license_name_cc_by_3_0; - case Prefs.Licenses.CC_BY_SA: // for backward compatibility to v2.1 - return R.string.license_name_cc_by_sa_3_0; } - throw new RuntimeException("Unrecognized license value: " + license); + throw new IllegalStateException("Unrecognized license value: " + license); } /** @@ -92,7 +88,7 @@ public class Utils { case Prefs.Licenses.CC0: return "https://creativecommons.org/publicdomain/zero/1.0/"; default: - throw new RuntimeException("Unrecognized license value: " + license); + throw new IllegalStateException("Unrecognized license value: " + license); } } diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesDao.java b/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesDao.java index 1d52b72e7..55da171fd 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesDao.java +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesDao.java @@ -6,17 +6,15 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.RemoteException; import androidx.annotation.NonNull; +import fr.free.nrw.commons.bookmarks.Bookmark; import java.util.ArrayList; import java.util.List; - import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; -import fr.free.nrw.commons.bookmarks.Bookmark; - import static fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider.BASE_URI; @Singleton @@ -121,6 +119,10 @@ public class BookmarkPicturesDao { * @return boolean : is bookmark in database ? */ public boolean findBookmark(Bookmark bookmark) { + if (bookmark == null) {//Avoiding NPE's + return false; + } + Cursor cursor = null; ContentProviderClient db = clientProvider.get(); try { diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.java b/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.java index a2eea20ea..76c0626fe 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.java @@ -259,10 +259,6 @@ public class Contribution extends Media { return "{{self|cc-by-sa-4.0}}"; case Prefs.Licenses.CC0: return "{{self|cc-zero}}"; - case Prefs.Licenses.CC_BY: - return "{{self|cc-by-3.0}}"; - case Prefs.Licenses.CC_BY_SA: - return "{{self|cc-by-sa-3.0}}"; } throw new RuntimeException("Unrecognized license value: " + license); diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.java index 111f58d89..2e9ca5327 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.java @@ -9,10 +9,9 @@ import android.net.Uri; import android.os.RemoteException; import androidx.annotation.Nullable; import android.text.TextUtils; +import fr.free.nrw.commons.settings.Prefs; import org.apache.commons.lang3.StringUtils; - -import fr.free.nrw.commons.settings.Prefs; import java.util.Date; import javax.inject.Inject; import javax.inject.Named; @@ -320,7 +319,7 @@ public class ContributionDao { try { db.execSQL(query); } catch (SQLiteException e) { - Timber.e(e, "Exception performing query: " + query); + Timber.e("Exception performing query: " + query + " message: " + e.getMessage()); } } diff --git a/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.java b/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.java index d84213b45..6ca0a13af 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.java @@ -2,26 +2,20 @@ package fr.free.nrw.commons.explore; import android.database.DataSetObserver; import android.os.Bundle; -import com.google.android.material.tabs.TabLayout; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; -import androidx.viewpager.widget.ViewPager; -import androidx.appcompat.widget.Toolbar; import android.text.TextUtils; import android.view.View; import android.widget.FrameLayout; import android.widget.SearchView; - -import com.jakewharton.rxbinding2.view.RxView; -import com.jakewharton.rxbinding2.widget.RxSearchView; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.viewpager.widget.ViewPager; import butterknife.BindView; import butterknife.ButterKnife; +import com.google.android.material.tabs.TabLayout; +import com.jakewharton.rxbinding2.view.RxView; +import com.jakewharton.rxbinding2.widget.RxSearchView; import fr.free.nrw.commons.Media; import fr.free.nrw.commons.R; import fr.free.nrw.commons.explore.categories.SearchCategoryFragment; @@ -29,8 +23,12 @@ import fr.free.nrw.commons.explore.images.SearchImageFragment; import fr.free.nrw.commons.explore.recentsearches.RecentSearchesFragment; import fr.free.nrw.commons.media.MediaDetailPagerFragment; import fr.free.nrw.commons.theme.NavigationBaseActivity; +import fr.free.nrw.commons.utils.FragmentUtils; import fr.free.nrw.commons.utils.ViewUtil; import io.reactivex.android.schedulers.AndroidSchedulers; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; /** * Represents search screen of this app @@ -109,8 +107,13 @@ public class SearchActivity extends NavigationBaseActivity implements MediaDetai viewPager.setVisibility(View.VISIBLE); tabLayout.setVisibility(View.VISIBLE); searchHistoryContainer.setVisibility(View.GONE); - searchImageFragment.updateImageList(query.toString()); - searchCategoryFragment.updateCategoryList(query.toString()); + if (FragmentUtils.isFragmentUIActive(searchImageFragment)) { + searchImageFragment.updateImageList(query.toString()); + } + + if (FragmentUtils.isFragmentUIActive(searchCategoryFragment)) { + searchCategoryFragment.updateCategoryList(query.toString()); + } }else { //Open RecentSearchesFragment recentSearchesFragment.updateRecentSearches(); @@ -261,4 +264,10 @@ public class SearchActivity extends NavigationBaseActivity implements MediaDetai searchImageFragment.addImagesToList(query); } } + + @Override protected void onDestroy() { + super.onDestroy(); + //Dispose the disposables when the activity is destroyed + compositeDisposable.dispose(); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/explore/images/SearchImageFragment.java b/app/src/main/java/fr/free/nrw/commons/explore/images/SearchImageFragment.java index 1dbaf5316..75a8666c2 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/images/SearchImageFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/explore/images/SearchImageFragment.java @@ -1,6 +1,5 @@ package fr.free.nrw.commons.explore.images; - import android.annotation.SuppressLint; import android.content.res.Configuration; import android.os.Bundle; @@ -228,8 +227,15 @@ public class SearchImageFragment extends CommonsDaggerSupportFragment { * Handles the UI updates for no internet scenario */ private void handleNoInternet() { - progressBar.setVisibility(GONE); - ViewUtil.showShortSnackbar(imagesRecyclerView, R.string.no_internet); + if (null + != getView()) {//We have exposed public methods to update our ui, we will have to add null checks until we make this lifecycle aware + if (null != progressBar) { + progressBar.setVisibility(GONE); + } + ViewUtil.showShortSnackbar(imagesRecyclerView, R.string.no_internet); + } else { + Timber.d("Attempt to update fragment ui after its view was destroyed"); + } } /** @@ -257,4 +263,9 @@ public class SearchImageFragment extends CommonsDaggerSupportFragment { return imagesAdapter.getItem(i); } } + + @Override public void onDestroyView() { + super.onDestroyView(); + compositeDisposable.clear(); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index f9a16aa4d..235393a76 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -52,6 +52,12 @@ import io.reactivex.Single; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.Locale; +import javax.inject.Inject; +import javax.inject.Provider; import timber.log.Timber; import static android.view.View.GONE; @@ -285,6 +291,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { detailProvider.unregisterDataSetObserver(dataObserver); dataObserver = null; } + compositeDisposable.clear(); super.onDestroyView(); } @@ -414,9 +421,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(s -> { - isDeleted = true; - enableDeleteButton(false); + if (getActivity() != null) { + isDeleted = true; + enableDeleteButton(false); + } })); + } @OnClick(R.id.seeMore) @@ -540,4 +550,5 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { nominatedForDeletion.setVisibility(GONE); } } + } 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 8d8720e9a..206b59321 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 @@ -5,7 +5,6 @@ import android.app.DownloadManager; import android.content.Intent; import android.database.DataSetObserver; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -15,14 +14,12 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.Toast; -import com.google.android.material.snackbar.Snackbar; import javax.inject.Inject; import javax.inject.Named; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentStatePagerAdapter; @@ -44,12 +41,12 @@ import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.utils.ImageUtils; import fr.free.nrw.commons.utils.NetworkUtils; +import fr.free.nrw.commons.utils.PermissionUtils; import fr.free.nrw.commons.utils.ViewUtil; import timber.log.Timber; -import static android.Manifest.permission.READ_EXTERNAL_STORAGE; +import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.content.Context.DOWNLOAD_SERVICE; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static fr.free.nrw.commons.Utils.handleWebUrl; public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment implements ViewPager.OnPageChangeListener { @@ -227,20 +224,19 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple // Modern Android updates the gallery automatically. Yay! req.allowScanningByMediaScanner(); req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + PermissionUtils.checkPermissionsAndPerformAction(getActivity(), WRITE_EXTERNAL_STORAGE, + () -> enqueueRequest(req), () -> Toast.makeText(getContext(), + R.string.download_failed_we_cannot_download_the_file_without_storage_permission, + Toast.LENGTH_SHORT).show(), R.string.storage_permission, + R.string.write_storage_permission_rationale); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && - ContextCompat.checkSelfPermission(getContext(), READ_EXTERNAL_STORAGE) - != PERMISSION_GRANTED - && getView() != null) { - Snackbar.make(getView(), R.string.read_storage_permission_rationale, - Snackbar.LENGTH_INDEFINITE).setAction(R.string.ok, - view -> ActivityCompat.requestPermissions(getActivity(), - new String[]{READ_EXTERNAL_STORAGE}, 1)).show(); - } else { - DownloadManager systemService = (DownloadManager) getActivity().getSystemService(DOWNLOAD_SERVICE); - if (systemService != null) { - systemService.enqueue(req); - } + } + + private void enqueueRequest(DownloadManager.Request req) { + DownloadManager systemService = + (DownloadManager) getActivity().getSystemService(DOWNLOAD_SERVICE); + if (systemService != null) { + systemService.enqueue(req); } } diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/CustomMwApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/CustomMwApi.java index 4038807bb..7500a97ee 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/CustomMwApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/CustomMwApi.java @@ -69,6 +69,10 @@ public class CustomMwApi { } public void setAuthCookie(String authCookie) { + if (authCookie == null) {//If the authCookie is null, no need to proceed + return; + } + this.authCookie = authCookie; this.isLoggedIn = true; String[] cookies = authCookie.split(";"); diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java index a82ccc7ca..a0da17732 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java @@ -319,10 +319,13 @@ public class OkHttpJsonApiClient { if (response.body() != null && response.isSuccessful()) { String json = response.body().string(); MwQueryResponse mwQueryResponse = gson.fromJson(json, MwQueryResponse.class); - putContinueValues(keyword, mwQueryResponse.continuation()); - if (mwQueryResponse.query() == null) { + if (null == mwQueryResponse + || null == mwQueryResponse.query() + || null == mwQueryResponse.query().pages()) { return mediaList; } + putContinueValues(keyword, mwQueryResponse.continuation()); + List pages = mwQueryResponse.query().pages(); for (MwQueryPage page : pages) { Media media = Media.from(page); 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 722733393..d059c862e 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 @@ -14,9 +14,5 @@ public class Prefs { public static final String CC_BY_SA_4 = "CC BY-SA 4.0"; public static final String CC_BY_4 = "CC BY 4.0"; public static final String CC0 = "CC0"; - - // kept for backward compatibility to v2.1 - @Deprecated public static final String CC_BY = "CC BY"; - @Deprecated public static final String CC_BY_SA = "CC BY-SA"; } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadPresenter.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadPresenter.java index f3f8f9fa7..a5515b947 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadPresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadPresenter.java @@ -2,18 +2,8 @@ package fr.free.nrw.commons.upload; import android.annotation.SuppressLint; import android.content.Context; - -import org.apache.commons.lang3.StringUtils; - -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - import fr.free.nrw.commons.R; +import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.category.CategoriesModel; import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.filepicker.UploadableFile; @@ -31,6 +21,7 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; +import org.apache.commons.lang3.StringUtils; import timber.log.Timber; import static fr.free.nrw.commons.upload.UploadModel.UploadItem; @@ -334,7 +325,15 @@ public class UploadPresenter { * Sets the list of licences and the default license. */ private void updateLicenses() { - String selectedLicense = directKvStore.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3); + String selectedLicense = directKvStore.getString(Prefs.DEFAULT_LICENSE, + Prefs.Licenses.CC_BY_SA_4);//CC_BY_SA_4 is the default one used by the commons web app + try {//I have to make sure that the stored default license was not one of the deprecated one's + Utils.licenseNameFor(selectedLicense); + } catch (IllegalStateException exception) { + Timber.e(exception.getMessage()); + selectedLicense = Prefs.Licenses.CC_BY_SA_4; + directKvStore.putString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_4); + } view.updateLicenses(uploadModel.getLicenses(), selectedLicense); view.updateLicenseSummary(selectedLicense, uploadModel.getCount()); } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/FragmentUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/FragmentUtils.java index 1dd4681f8..a01ff9251 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/FragmentUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/FragmentUtils.java @@ -10,6 +10,6 @@ public class FragmentUtils { * @return */ public static boolean isFragmentUIActive(Fragment fragment) { - return fragment.getActivity() != null && fragment.isAdded() && !fragment.isDetached() && !fragment.isRemoving(); + return fragment!=null && fragment.getActivity() != null && fragment.isAdded() && !fragment.isDetached() && !fragment.isRemoving(); } } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java index 4b63b9a87..81eaa0794 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/PermissionUtils.java @@ -14,7 +14,6 @@ import com.karumi.dexter.listener.PermissionDeniedResponse; import com.karumi.dexter.listener.PermissionGrantedResponse; import com.karumi.dexter.listener.PermissionRequest; import com.karumi.dexter.listener.single.BasePermissionListener; - import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.R; @@ -64,42 +63,68 @@ public class PermissionUtils { * @param rationaleTitle rationale title to be displayed when permission was denied * @param rationaleMessage rationale message to be displayed when permission was denied */ - public static void checkPermissionsAndPerformAction(Activity activity, - String permission, - Runnable onPermissionGranted, - @StringRes int rationaleTitle, - @StringRes int rationaleMessage) { - Dexter.withActivity(activity) - .withPermission(permission) - .withListener(new BasePermissionListener() { - @Override - public void onPermissionGranted(PermissionGrantedResponse response) { - onPermissionGranted.run(); - } + public static void checkPermissionsAndPerformAction(Activity activity, String permission, + Runnable onPermissionGranted, @StringRes int rationaleTitle, + @StringRes int rationaleMessage) { + checkPermissionsAndPerformAction(activity, permission, onPermissionGranted, null, + rationaleTitle, rationaleMessage); + } - @Override - public void onPermissionDenied(PermissionDeniedResponse response) { - if (response.isPermanentlyDenied()) { - DialogUtil.showAlertDialog(activity, - activity.getString(rationaleTitle), - activity.getString(rationaleMessage), - activity.getString(R.string.navigation_item_settings), - null, - () -> askUserToManuallyEnablePermissionFromSettings(activity), - null); + /** + * Checks for a particular permission and runs the corresponding runnables to perform an action when the permission is granted/denied + * Also, it shows a rationale if needed + * + * Sample usage: + * + * PermissionUtils.checkPermissionsAndPerformAction(activity, + * Manifest.permission.WRITE_EXTERNAL_STORAGE, + * () -> initiateCameraUpload(activity), + * () -> showMessage(), + * R.string.storage_permission_title, + * R.string.write_storage_permission_rationale); + * + * + * @param activity activity requesting permissions + * @param permission the permission being requests + * @param onPermissionGranted the runnable to be executed when the permission is granted + * @param onPermissionDenied the runnable to be executed when the permission is denied(but not permanently) + * @param rationaleTitle rationale title to be displayed when permission was denied + * @param rationaleMessage rationale message to be displayed when permission was denied + */ + + public static void checkPermissionsAndPerformAction(Activity activity, String permission, + Runnable onPermissionGranted, Runnable onPermissionDenied, @StringRes int rationaleTitle, + @StringRes int rationaleMessage) { + Dexter.withActivity(activity) + .withPermission(permission) + .withListener(new BasePermissionListener() { + @Override public void onPermissionGranted(PermissionGrantedResponse response) { + onPermissionGranted.run(); + } + + @Override public void onPermissionDenied(PermissionDeniedResponse response) { + if (response.isPermanentlyDenied()) { + DialogUtil.showAlertDialog(activity, activity.getString(rationaleTitle), + activity.getString(rationaleMessage), + activity.getString(R.string.navigation_item_settings), null, + () -> askUserToManuallyEnablePermissionFromSettings(activity), null); + } else { + if (null != onPermissionDenied) { + onPermissionDenied.run(); } } + } - @Override - public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) { - DialogUtil.showAlertDialog(activity, - activity.getString(rationaleTitle), - activity.getString(rationaleMessage), - activity.getString(android.R.string.ok), - activity.getString(android.R.string.cancel), - token::continuePermissionRequest, - token::cancelPermissionRequest); - } - }).check(); + @Override + public void onPermissionRationaleShouldBeShown(PermissionRequest permission, + PermissionToken token) { + DialogUtil.showAlertDialog(activity, activity.getString(rationaleTitle), + activity.getString(rationaleMessage), + activity.getString(android.R.string.ok), + activity.getString(android.R.string.cancel), + token::continuePermissionRequest, token::cancelPermissionRequest); + } + }) + .check(); } } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java index fed9829fe..3638a787e 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java @@ -6,6 +6,7 @@ import android.view.Display; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.Toast; +import timber.log.Timber; import com.google.android.material.snackbar.Snackbar; @@ -22,7 +23,13 @@ public class ViewUtil { return; } - ExecutorUtils.uiExecutor().execute(() -> Snackbar.make(view, messageResourceId, Snackbar.LENGTH_SHORT).show()); + ExecutorUtils.uiExecutor().execute(() -> { + try { + Snackbar.make(view, messageResourceId, Snackbar.LENGTH_SHORT).show(); + }catch (IllegalStateException e){ + Timber.e(e.getMessage()); + } + }); } public static void showLongToast(Context context, String text) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a87ed2e1b..c0494cfde 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -164,7 +164,7 @@ Refresh Requesting Storage Permission Required permission: Read external storage. App cannot access your gallery without this. - Required permission: Write external storage. App cannot access your camera without this. + Required permission: Write external storage. App cannot access your camera/gallery without this. Optional permission: Get current location for category suggestions OK Nearby Places @@ -534,4 +534,5 @@ Upload your first media by tapping on the add button. Images Uploaded via Nearby places are the images which are uploaded by discovering places on the map. This feature allows editors to send a Thank you notification to users who make useful edits – by using a small thank link on the history page or diff page. SKIP THIS IMAGE + Download Failed!!. We cannot download the file without external storage permission.