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 72789e1fcc..f674ca3e3c 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 @@ -2,20 +2,24 @@ import android.annotation.SuppressLint; import android.app.AlertDialog; +import android.app.DownloadManager; import android.content.Intent; import android.database.DataSetObserver; import android.net.Uri; import android.os.Bundle; +import android.os.Environment; import android.text.Editable; import android.text.TextWatcher; import android.util.TypedValue; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.Spinner; @@ -44,6 +48,9 @@ import fr.free.nrw.commons.MediaDataExtractor; import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; +import fr.free.nrw.commons.bookmarks.Bookmark; +import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider; +import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao; import fr.free.nrw.commons.category.CategoryDetailsActivity; import fr.free.nrw.commons.contributions.ContributionsFragment; import fr.free.nrw.commons.delete.DeleteHelper; @@ -51,6 +58,9 @@ import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.ui.widget.CompatTextView; import fr.free.nrw.commons.ui.widget.HtmlTextView; +import fr.free.nrw.commons.utils.NetworkUtils; +import fr.free.nrw.commons.utils.PermissionUtils; +import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.utils.ViewUtilWrapper; import io.reactivex.Single; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -61,6 +71,8 @@ import org.wikipedia.util.StringUtil; import timber.log.Timber; +import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; +import static android.content.Context.DOWNLOAD_SERVICE; import static android.view.View.GONE; import static android.view.View.VISIBLE; @@ -97,8 +109,12 @@ public static MediaDetailFragment forMedia(int index, boolean editable, boolean DeleteHelper deleteHelper; @Inject ViewUtilWrapper viewUtil; + @Inject + BookmarkPicturesDao bookmarkDao; + private int initialListTop = 0; + private Bookmark bookmark; @BindView(R.id.mediaDetailImage) SimpleDraweeView image; @@ -130,6 +146,8 @@ public static MediaDetailFragment forMedia(int index, boolean editable, boolean Button delete; @BindView(R.id.mediaDetailScrollView) ScrollView scrollView; + @BindView(R.id.iv_bookmark_icon) + ImageView ivBookmarkIcon; private ArrayList categoryNames; private boolean categoriesLoaded = false; @@ -276,6 +294,15 @@ private void displayMediaDetails() { .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::setTextFields); compositeDisposable.add(disposable); + + // Initialize bookmark object + bookmark = new Bookmark( + media.getFilename(), + media.getCreator(), + BookmarkPicturesContentProvider.uriForName(media.getFilename()) + ); + updateBookmarkState(); + } /** @@ -445,6 +472,82 @@ private void onDeleteClicked(Spinner spinner) { } + @OnClick(R.id.ll_bookmark) + public void onBookMarkClick(){ + bookmarkDao.updateBookmark(bookmark); + updateBookmarkState(); + } + + private void updateBookmarkState() { + boolean isBookmarked = bookmarkDao.findBookmark(bookmark); + int icon = isBookmarked ? R.drawable.ic_star_filled_primary_dark_24dp : R.drawable.ic_star_border_primary_dark_24dp; + ivBookmarkIcon.setImageResource(icon); + } + + @OnClick(R.id.ll_share) + public void onShareClick(){ + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_TEXT, media.getDisplayTitle() + " \n" + media.getPageTitle().getCanonicalUri()); + startActivity(Intent.createChooser(shareIntent, "Share image via...")); + } + + @OnClick(R.id.ll_download) + public void onDownloadClick(){ + if (!NetworkUtils.isInternetConnectionEstablished(getActivity())) { + ViewUtil.showShortSnackbar(getView(), R.string.no_internet); + return; + } + downloadMedia(media); + } + + /** + * Start the media file downloading to the local SD card/storage. + * The file can then be opened in Gallery or other apps. + * + * @param m Media file to download + */ + private void downloadMedia(Media m) { + String imageUrl = m.getImageUrl(), fileName = m.getFilename(); + + if (imageUrl == null + || fileName == null + || getContext() == null + || getActivity() == null) { + Timber.d("Skipping download media as either imageUrl %s or filename %s activity is null", imageUrl, fileName); + return; + } + + // Strip 'File:' from beginning of filename, we really shouldn't store it + fileName = fileName.replaceFirst("^File:", ""); + + Uri imageUri = Uri.parse(imageUrl); + + DownloadManager.Request req = new DownloadManager.Request(imageUri); + //These are not the image title and description fields, they are download descs for notifications + req.setDescription(getString(R.string.app_name)); + req.setTitle(m.getDisplayTitle()); + req.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); + + // 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); + + } + + private void enqueueRequest(DownloadManager.Request req) { + DownloadManager systemService = + (DownloadManager) getActivity().getSystemService(DOWNLOAD_SERVICE); + if (systemService != null) { + systemService.enqueue(req); + } + } + @OnClick(R.id.seeMore) public void onSeeMoreClicked(){ if (nominatedForDeletion.getVisibility() == VISIBLE && getActivity() != null) { 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 f34df4687d..fed5eab5e0 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 @@ -41,13 +41,8 @@ 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.WRITE_EXTERNAL_STORAGE; -import static android.content.Context.DOWNLOAD_SERVICE; import static fr.free.nrw.commons.Utils.handleWebUrl; public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment implements ViewPager.OnPageChangeListener { @@ -55,13 +50,11 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple @Inject MediaWikiApi mwApi; @Inject SessionManager sessionManager; @Inject @Named("default_preferences") JsonKvStore store; - @Inject BookmarkPicturesDao bookmarkDao; @BindView(R.id.mediaDetailsPager) ViewPager pager; private Boolean editable; private boolean isFeaturedImage; MediaDetailAdapter adapter; - private Bookmark bookmark; private MediaDetailProvider provider; public MediaDetailPagerFragment() { @@ -150,28 +143,10 @@ public boolean onOptionsItemSelected(MenuItem item) { Media m = provider.getMediaAtPosition(pager.getCurrentItem()); switch (item.getItemId()) { - case R.id.menu_bookmark_current_image: - bookmarkDao.updateBookmark(bookmark); - updateBookmarkState(item); - return true; - case R.id.menu_share_current_image: - Intent shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.setType("text/plain"); - shareIntent.putExtra(Intent.EXTRA_TEXT, m.getDisplayTitle() + " \n" + m.getPageTitle().getCanonicalUri()); - startActivity(Intent.createChooser(shareIntent, "Share image via...")); - return true; case R.id.menu_browser_current_image: // View in browser handleWebUrl(requireContext(), Uri.parse(m.getPageTitle().getMobileUri())); return true; - case R.id.menu_download_current_image: - // Download - if (!NetworkUtils.isInternetConnectionEstablished(getActivity())) { - ViewUtil.showShortSnackbar(getView(), R.string.no_internet); - return false; - } - downloadMedia(m); - return true; case R.id.menu_set_as_wallpaper: // Set wallpaper setWallpaper(m); @@ -194,52 +169,6 @@ private void setWallpaper(Media media) { ImageUtils.setWallpaperFromImageUrl(getActivity(), Uri.parse(media.getImageUrl())); } - /** - * Start the media file downloading to the local SD card/storage. - * The file can then be opened in Gallery or other apps. - * - * @param m Media file to download - */ - private void downloadMedia(Media m) { - String imageUrl = m.getImageUrl(), fileName = m.getFilename(); - - if (imageUrl == null - || fileName == null - || getContext() == null - || getActivity() == null) { - Timber.d("Skipping download media as either imageUrl %s or filename %s activity is null", imageUrl, fileName); - return; - } - - // Strip 'File:' from beginning of filename, we really shouldn't store it - fileName = fileName.replaceFirst("^File:", ""); - - Uri imageUri = Uri.parse(imageUrl); - - DownloadManager.Request req = new DownloadManager.Request(imageUri); - //These are not the image title and description fields, they are download descs for notifications - req.setDescription(getString(R.string.app_name)); - req.setTitle(m.getDisplayTitle()); - req.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); - - // 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); - - } - - private void enqueueRequest(DownloadManager.Request req) { - DownloadManager systemService = - (DownloadManager) getActivity().getSystemService(DOWNLOAD_SERVICE); - if (systemService != null) { - systemService.enqueue(req); - } - } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { @@ -256,33 +185,16 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { if (m != null) { // Enable default set of actions, then re-enable different set of actions only if it is a failed contrib menu.findItem(R.id.menu_browser_current_image).setEnabled(true).setVisible(true); - menu.findItem(R.id.menu_share_current_image).setEnabled(true).setVisible(true); - menu.findItem(R.id.menu_download_current_image).setEnabled(true).setVisible(true); - menu.findItem(R.id.menu_bookmark_current_image).setEnabled(true).setVisible(true); - - // Initialize bookmark object - bookmark = new Bookmark( - m.getFilename(), - m.getCreator(), - BookmarkPicturesContentProvider.uriForName(m.getFilename()) - ); - updateBookmarkState(menu.findItem(R.id.menu_bookmark_current_image)); if (m instanceof Contribution ) { Contribution c = (Contribution) m; switch (c.getState()) { case Contribution.STATE_FAILED: menu.findItem(R.id.menu_browser_current_image).setEnabled(false).setVisible(false); - menu.findItem(R.id.menu_share_current_image).setEnabled(false).setVisible(false); - menu.findItem(R.id.menu_download_current_image).setEnabled(false).setVisible(false); - menu.findItem(R.id.menu_bookmark_current_image).setEnabled(false).setVisible(false); break; case Contribution.STATE_IN_PROGRESS: case Contribution.STATE_QUEUED: menu.findItem(R.id.menu_browser_current_image).setEnabled(false).setVisible(false); - menu.findItem(R.id.menu_share_current_image).setEnabled(false).setVisible(false); - menu.findItem(R.id.menu_download_current_image).setEnabled(false).setVisible(false); - menu.findItem(R.id.menu_bookmark_current_image).setEnabled(false).setVisible(false); break; case Contribution.STATE_COMPLETED: // Default set of menu items works fine. Treat same as regular media object @@ -294,12 +206,6 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { } } - private void updateBookmarkState(MenuItem item) { - boolean isBookmarked = bookmarkDao.findBookmark(bookmark); - int icon = isBookmarked ? R.drawable.ic_round_star_filled_24px : R.drawable.ic_round_star_border_24px; - item.setIcon(icon); - } - public void showImage(int i) { Handler handler = new Handler(); handler.postDelayed(() -> pager.setCurrentItem(i), 5); diff --git a/app/src/main/res/drawable-hdpi/ic_mode_edit_primary_dark_24dp.png b/app/src/main/res/drawable-hdpi/ic_mode_edit_primary_dark_24dp.png new file mode 100644 index 0000000000..b9b6da79b6 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_mode_edit_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_star_border_primary_dark_24dp.png b/app/src/main/res/drawable-hdpi/ic_star_border_primary_dark_24dp.png new file mode 100644 index 0000000000..783de43f02 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_star_border_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_star_filled_primary_dark_24dp.png b/app/src/main/res/drawable-hdpi/ic_star_filled_primary_dark_24dp.png new file mode 100644 index 0000000000..13388bd6bb Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_star_filled_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_mode_edit_primary_dark_24dp.png b/app/src/main/res/drawable-mdpi/ic_mode_edit_primary_dark_24dp.png new file mode 100644 index 0000000000..7e6fc7e9e7 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_mode_edit_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_star_border_primary_dark_24dp.png b/app/src/main/res/drawable-mdpi/ic_star_border_primary_dark_24dp.png new file mode 100644 index 0000000000..e5140eba20 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_star_border_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_star_filled_primary_dark_24dp.png b/app/src/main/res/drawable-mdpi/ic_star_filled_primary_dark_24dp.png new file mode 100644 index 0000000000..1ee5a5ac7b Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_star_filled_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_mode_edit_primary_dark_24dp.png b/app/src/main/res/drawable-xhdpi/ic_mode_edit_primary_dark_24dp.png new file mode 100644 index 0000000000..4d30acca0e Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_mode_edit_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_star_border_primary_dark_24dp.png b/app/src/main/res/drawable-xhdpi/ic_star_border_primary_dark_24dp.png new file mode 100644 index 0000000000..28e9016398 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_star_border_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_star_filled_primary_dark_24dp.png b/app/src/main/res/drawable-xhdpi/ic_star_filled_primary_dark_24dp.png new file mode 100644 index 0000000000..b32501a7d1 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_star_filled_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_mode_edit_primary_dark_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_mode_edit_primary_dark_24dp.png new file mode 100644 index 0000000000..4c719d96ff Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_mode_edit_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_star_border_primary_dark_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_star_border_primary_dark_24dp.png new file mode 100644 index 0000000000..dd7f6330fe Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_star_border_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_star_filled_primary_dark_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_star_filled_primary_dark_24dp.png new file mode 100644 index 0000000000..da3041b73b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_star_filled_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_mode_edit_primary_dark_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_mode_edit_primary_dark_24dp.png new file mode 100644 index 0000000000..1f76a5eb25 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_mode_edit_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_star_border_primary_dark_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_star_border_primary_dark_24dp.png new file mode 100644 index 0000000000..3acaab3671 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_star_border_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_star_filled_primary_dark_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_star_filled_primary_dark_24dp.png new file mode 100644 index 0000000000..309508c6dc Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_star_filled_primary_dark_24dp.png differ diff --git a/app/src/main/res/drawable/bg_delete_button.xml b/app/src/main/res/drawable/bg_delete_button.xml index 199940e1b2..9e699052c8 100644 --- a/app/src/main/res/drawable/bg_delete_button.xml +++ b/app/src/main/res/drawable/bg_delete_button.xml @@ -9,12 +9,9 @@ + android:color="@color/deleteRed"/> - + android:radius="2dp" /> @@ -25,7 +22,7 @@ + android:radius="2dp" /> diff --git a/app/src/main/res/drawable/copy_to_wikitext_button.xml b/app/src/main/res/drawable/copy_to_wikitext_button.xml new file mode 100644 index 0000000000..01ce5bce99 --- /dev/null +++ b/app/src/main/res/drawable/copy_to_wikitext_button.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_file_download_primary_dark_24dp.xml b/app/src/main/res/drawable/ic_file_download_primary_dark_24dp.xml new file mode 100644 index 0000000000..d8aa76399e --- /dev/null +++ b/app/src/main/res/drawable/ic_file_download_primary_dark_24dp.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/drawable/ic_share_primary_dark_24dp.xml b/app/src/main/res/drawable/ic_share_primary_dark_24dp.xml new file mode 100644 index 0000000000..c61a55a144 --- /dev/null +++ b/app/src/main/res/drawable/ic_share_primary_dark_24dp.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/layout/detail_category_item.xml b/app/src/main/res/layout/detail_category_item.xml index 02fb6c80f5..f7880a59e4 100644 --- a/app/src/main/res/layout/detail_category_item.xml +++ b/app/src/main/res/layout/detail_category_item.xml @@ -13,12 +13,9 @@ android:background="?attr/subBackground" 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:textColor="@color/linkColor" + android:paddingBottom="@dimen/small_gap" android:textSize="@dimen/description_text_size" - app:drawablePadding="@dimen/small_gap" - app:drawableStart="@drawable/ic_info_outline_24dp" /> diff --git a/app/src/main/res/layout/fragment_media_detail.xml b/app/src/main/res/layout/fragment_media_detail.xml index 5c325aaaff..a6819fc4fd 100644 --- a/app/src/main/res/layout/fragment_media_detail.xml +++ b/app/src/main/res/layout/fragment_media_detail.xml @@ -8,6 +8,12 @@ android:background="?attr/mainBackground" > + + + - - - - + android:layout_height="wrap_content" + android:adjustViewBounds="true" + android:scaleType="fitXY" + /> + android:background="@color/primaryDarkColor" + > - + + + + + android:layout_gravity="center" + android:gravity="center" + android:padding="@dimen/standard_gap" + android:layout_height="wrap_content"> - + - - - + android:text="BOOKMARK" + android:textColor="@color/primaryDarkColor" + /> + + android:layout_gravity="center" + android:gravity="center" + android:layout_height="wrap_content"> - + - - - + android:text="DOWNLOAD" + android:textColor="@color/primaryDarkColor" + /> + + android:layout_gravity="center" + android:gravity="center" + android:layout_height="wrap_content"> + + - - + android:text="SHARE" + android:textColor="@color/primaryDarkColor" + /> + - + - + + + + + android:text="@string/media_detail_description" + /> - - - - + - - + + + + + + + + + + android:textStyle="bold" + android:textColor="@color/black" + android:text="Categories" + /> - - - - + - + - + + + + + + + android:text="@string/media_detail_author" + android:textColor="@color/black" + android:textStyle="bold" + /> + + - - - - + - + + + + + - + + + + + android:textStyle="bold" + android:textColor="@color/black" + android:text="@string/media_detail_coordinates" + /> - - - + - + - + + - - - + android:text="@string/media_detail_uploaded_date" + android:textStyle="bold" + android:textColor="@color/black" + /> + + - + - + + + android:text="@string/media_detail_discussion" + android:textStyle="bold" + android:textColor="@color/black" + /> + + - + - - +