|
2 | 2 |
|
3 | 3 | import android.annotation.SuppressLint;
|
4 | 4 | import android.app.AlertDialog;
|
| 5 | +import android.app.DownloadManager; |
5 | 6 | import android.content.Intent;
|
6 | 7 | import android.database.DataSetObserver;
|
7 | 8 | import android.net.Uri;
|
8 | 9 | import android.os.Bundle;
|
| 10 | +import android.os.Environment; |
9 | 11 | import android.text.Editable;
|
10 | 12 | import android.text.TextWatcher;
|
11 | 13 | import android.util.TypedValue;
|
12 | 14 | import android.view.LayoutInflater;
|
| 15 | +import android.view.MenuItem; |
13 | 16 | import android.view.View;
|
14 | 17 | import android.view.ViewGroup;
|
15 | 18 | import android.view.ViewTreeObserver;
|
16 | 19 | import android.widget.ArrayAdapter;
|
17 | 20 | import android.widget.Button;
|
18 | 21 | import android.widget.EditText;
|
| 22 | +import android.widget.ImageView; |
19 | 23 | import android.widget.LinearLayout;
|
20 | 24 | import android.widget.ScrollView;
|
21 | 25 | import android.widget.Spinner;
|
|
44 | 48 | import fr.free.nrw.commons.MediaDataExtractor;
|
45 | 49 | import fr.free.nrw.commons.R;
|
46 | 50 | import fr.free.nrw.commons.Utils;
|
| 51 | +import fr.free.nrw.commons.bookmarks.Bookmark; |
| 52 | +import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider; |
| 53 | +import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao; |
47 | 54 | import fr.free.nrw.commons.category.CategoryDetailsActivity;
|
48 | 55 | import fr.free.nrw.commons.contributions.ContributionsFragment;
|
49 | 56 | import fr.free.nrw.commons.delete.DeleteHelper;
|
50 | 57 | import fr.free.nrw.commons.delete.ReasonBuilder;
|
51 | 58 | import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
52 | 59 | import fr.free.nrw.commons.ui.widget.CompatTextView;
|
53 | 60 | import fr.free.nrw.commons.ui.widget.HtmlTextView;
|
| 61 | +import fr.free.nrw.commons.utils.NetworkUtils; |
| 62 | +import fr.free.nrw.commons.utils.PermissionUtils; |
| 63 | +import fr.free.nrw.commons.utils.ViewUtil; |
54 | 64 | import fr.free.nrw.commons.utils.ViewUtilWrapper;
|
55 | 65 | import io.reactivex.Single;
|
56 | 66 | import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
61 | 71 | import org.wikipedia.util.StringUtil;
|
62 | 72 | import timber.log.Timber;
|
63 | 73 |
|
| 74 | +import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; |
| 75 | +import static android.content.Context.DOWNLOAD_SERVICE; |
64 | 76 | import static android.view.View.GONE;
|
65 | 77 | import static android.view.View.VISIBLE;
|
66 | 78 |
|
@@ -97,8 +109,12 @@ public static MediaDetailFragment forMedia(int index, boolean editable, boolean
|
97 | 109 | DeleteHelper deleteHelper;
|
98 | 110 | @Inject
|
99 | 111 | ViewUtilWrapper viewUtil;
|
| 112 | + @Inject |
| 113 | + BookmarkPicturesDao bookmarkDao; |
| 114 | + |
100 | 115 |
|
101 | 116 | private int initialListTop = 0;
|
| 117 | + private Bookmark bookmark; |
102 | 118 |
|
103 | 119 | @BindView(R.id.mediaDetailImage)
|
104 | 120 | SimpleDraweeView image;
|
@@ -130,6 +146,8 @@ public static MediaDetailFragment forMedia(int index, boolean editable, boolean
|
130 | 146 | Button delete;
|
131 | 147 | @BindView(R.id.mediaDetailScrollView)
|
132 | 148 | ScrollView scrollView;
|
| 149 | + @BindView(R.id.iv_bookmark_icon) |
| 150 | + ImageView ivBookmarkIcon; |
133 | 151 |
|
134 | 152 | private ArrayList<String> categoryNames;
|
135 | 153 | private boolean categoriesLoaded = false;
|
@@ -276,6 +294,15 @@ private void displayMediaDetails() {
|
276 | 294 | .observeOn(AndroidSchedulers.mainThread())
|
277 | 295 | .subscribe(this::setTextFields);
|
278 | 296 | compositeDisposable.add(disposable);
|
| 297 | + |
| 298 | + // Initialize bookmark object |
| 299 | + bookmark = new Bookmark( |
| 300 | + media.getFilename(), |
| 301 | + media.getCreator(), |
| 302 | + BookmarkPicturesContentProvider.uriForName(media.getFilename()) |
| 303 | + ); |
| 304 | + updateBookmarkState(); |
| 305 | + |
279 | 306 | }
|
280 | 307 |
|
281 | 308 | /**
|
@@ -445,6 +472,82 @@ private void onDeleteClicked(Spinner spinner) {
|
445 | 472 |
|
446 | 473 | }
|
447 | 474 |
|
| 475 | + @OnClick(R.id.ll_bookmark) |
| 476 | + public void onBookMarkClick(){ |
| 477 | + bookmarkDao.updateBookmark(bookmark); |
| 478 | + updateBookmarkState(); |
| 479 | + } |
| 480 | + |
| 481 | + private void updateBookmarkState() { |
| 482 | + boolean isBookmarked = bookmarkDao.findBookmark(bookmark); |
| 483 | + int icon = isBookmarked ? R.drawable.ic_star_filled_primary_dark_24dp : R.drawable.ic_star_border_primary_dark_24dp; |
| 484 | + ivBookmarkIcon.setImageResource(icon); |
| 485 | + } |
| 486 | + |
| 487 | + @OnClick(R.id.ll_share) |
| 488 | + public void onShareClick(){ |
| 489 | + Intent shareIntent = new Intent(Intent.ACTION_SEND); |
| 490 | + shareIntent.setType("text/plain"); |
| 491 | + shareIntent.putExtra(Intent.EXTRA_TEXT, media.getDisplayTitle() + " \n" + media.getPageTitle().getCanonicalUri()); |
| 492 | + startActivity(Intent.createChooser(shareIntent, "Share image via...")); |
| 493 | + } |
| 494 | + |
| 495 | + @OnClick(R.id.ll_download) |
| 496 | + public void onDownloadClick(){ |
| 497 | + if (!NetworkUtils.isInternetConnectionEstablished(getActivity())) { |
| 498 | + ViewUtil.showShortSnackbar(getView(), R.string.no_internet); |
| 499 | + return; |
| 500 | + } |
| 501 | + downloadMedia(media); |
| 502 | + } |
| 503 | + |
| 504 | + /** |
| 505 | + * Start the media file downloading to the local SD card/storage. |
| 506 | + * The file can then be opened in Gallery or other apps. |
| 507 | + * |
| 508 | + * @param m Media file to download |
| 509 | + */ |
| 510 | + private void downloadMedia(Media m) { |
| 511 | + String imageUrl = m.getImageUrl(), fileName = m.getFilename(); |
| 512 | + |
| 513 | + if (imageUrl == null |
| 514 | + || fileName == null |
| 515 | + || getContext() == null |
| 516 | + || getActivity() == null) { |
| 517 | + Timber.d("Skipping download media as either imageUrl %s or filename %s activity is null", imageUrl, fileName); |
| 518 | + return; |
| 519 | + } |
| 520 | + |
| 521 | + // Strip 'File:' from beginning of filename, we really shouldn't store it |
| 522 | + fileName = fileName.replaceFirst("^File:", ""); |
| 523 | + |
| 524 | + Uri imageUri = Uri.parse(imageUrl); |
| 525 | + |
| 526 | + DownloadManager.Request req = new DownloadManager.Request(imageUri); |
| 527 | + //These are not the image title and description fields, they are download descs for notifications |
| 528 | + req.setDescription(getString(R.string.app_name)); |
| 529 | + req.setTitle(m.getDisplayTitle()); |
| 530 | + req.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); |
| 531 | + |
| 532 | + // Modern Android updates the gallery automatically. Yay! |
| 533 | + req.allowScanningByMediaScanner(); |
| 534 | + req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); |
| 535 | + PermissionUtils.checkPermissionsAndPerformAction(getActivity(), WRITE_EXTERNAL_STORAGE, |
| 536 | + () -> enqueueRequest(req), () -> Toast.makeText(getContext(), |
| 537 | + R.string.download_failed_we_cannot_download_the_file_without_storage_permission, |
| 538 | + Toast.LENGTH_SHORT).show(), R.string.storage_permission, |
| 539 | + R.string.write_storage_permission_rationale); |
| 540 | + |
| 541 | + } |
| 542 | + |
| 543 | + private void enqueueRequest(DownloadManager.Request req) { |
| 544 | + DownloadManager systemService = |
| 545 | + (DownloadManager) getActivity().getSystemService(DOWNLOAD_SERVICE); |
| 546 | + if (systemService != null) { |
| 547 | + systemService.enqueue(req); |
| 548 | + } |
| 549 | + } |
| 550 | + |
448 | 551 | @OnClick(R.id.seeMore)
|
449 | 552 | public void onSeeMoreClicked(){
|
450 | 553 | if (nominatedForDeletion.getVisibility() == VISIBLE && getActivity() != null) {
|
|
0 commit comments