diff --git a/app/build.gradle.kts b/app/build.gradle.kts index af0a5171b..e72fcfcfc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -79,7 +79,7 @@ configure { resValue("string", "app_name", "NewPipe $suffix") } isMinifyEnabled = true - isShrinkResources = false // disabled to fix F-Droid"s reproducible build + isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" @@ -88,13 +88,9 @@ configure { } lint { - checkReleaseBuilds = false - // Or, if you prefer, you can continue to check for errors in release builds, - // but continue the build even when errors are found: + lintConfig = file("lint.xml") + // Continue the debug build even when errors are found abortOnError = false - // suppress false warning ("Resource IDs will be non-final in Android Gradle Plugin version - // 5.0, avoid using them in switch case statements"), which affects only library projects - disable += "NonConstantResourceId" } compileOptions { diff --git a/app/lint.xml b/app/lint.xml new file mode 100644 index 000000000..9497c22ca --- /dev/null +++ b/app/lint.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 8dac39682..3c0018d99 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -309,25 +309,21 @@ public class MainActivity extends AppCompatActivity { } private boolean drawerItemSelected(final MenuItem item) { - switch (item.getGroupId()) { - case R.id.menu_services_group: - changeService(item); - break; - case R.id.menu_tabs_group: - tabSelected(item); - break; - case R.id.menu_kiosks_group: - try { - kioskSelected(item); - } catch (final Exception e) { - ErrorUtil.showUiErrorSnackbar(this, "Selecting drawer kiosk", e); - } - break; - case R.id.menu_options_about_group: - optionsAboutSelected(item); - break; - default: - return false; + final int groupId = item.getGroupId(); + if (groupId == R.id.menu_services_group) { + changeService(item); + } else if (groupId == R.id.menu_tabs_group) { + tabSelected(item); + } else if (groupId == R.id.menu_kiosks_group) { + try { + kioskSelected(item); + } catch (final Exception e) { + ErrorUtil.showUiErrorSnackbar(this, "Selecting drawer kiosk", e); + } + } else if (groupId == R.id.menu_options_about_group) { + optionsAboutSelected(item); + } else { + return false; } mainBinding.getRoot().closeDrawers(); diff --git a/app/src/main/java/org/schabi/newpipe/NewVersionWorker.kt b/app/src/main/java/org/schabi/newpipe/NewVersionWorker.kt index fb48d3f70..4cdcc6c69 100644 --- a/app/src/main/java/org/schabi/newpipe/NewVersionWorker.kt +++ b/app/src/main/java/org/schabi/newpipe/NewVersionWorker.kt @@ -82,7 +82,9 @@ class NewVersionWorker( ) val notificationManager = NotificationManagerCompat.from(applicationContext) - notificationManager.notify(2000, notificationBuilder.build()) + if (notificationManager.areNotificationsEnabled()) { + notificationManager.notify(2000, notificationBuilder.build()) + } } @Throws(IOException::class, ReCaptchaException::class) diff --git a/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java b/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java index e6177f6a3..3eeb912c8 100644 --- a/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java +++ b/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java @@ -41,50 +41,50 @@ public final class QueueItemMenuUtil { } popupMenu.setOnMenuItemClickListener(menuItem -> { - switch (menuItem.getItemId()) { - case R.id.menu_item_remove: - final int index = playQueue.indexOf(item); - playQueue.remove(index); - return true; - case R.id.menu_item_details: - // playQueue is null since we don't want any queue change - NavigationHelper.openVideoDetail(context, item.getServiceId(), - item.getUrl(), item.getTitle(), null, - false); - return true; - case R.id.menu_item_append_playlist: - PlaylistDialog.createCorrespondingDialog( - context, - List.of(new StreamEntity(item)), - dialog -> dialog.show( - fragmentManager, - "QueueItemMenuUtil@append_playlist" - ) - ); + final int itemId = menuItem.getItemId(); + if (itemId == R.id.menu_item_remove) { + final int index = playQueue.indexOf(item); + playQueue.remove(index); + return true; + } else if (itemId == R.id.menu_item_details) { + // playQueue is null since we don't want any queue change + NavigationHelper.openVideoDetail(context, item.getServiceId(), + item.getUrl(), item.getTitle(), null, + false); + return true; + } else if (itemId == R.id.menu_item_append_playlist) { + PlaylistDialog.createCorrespondingDialog( + context, + List.of(new StreamEntity(item)), + dialog -> dialog.show( + fragmentManager, + "QueueItemMenuUtil@append_playlist" + ) + ); - return true; - case R.id.menu_item_channel_details: - SparseItemUtil.fetchUploaderUrlIfSparse(context, item.getServiceId(), - item.getUrl(), item.getUploaderUrl(), - // An intent must be used here. - // Opening with FragmentManager transactions is not working, - // as PlayQueueActivity doesn't use fragments. - uploaderUrl -> NavigationHelper.openChannelFragmentUsingIntent( - context, item.getServiceId(), uploaderUrl, item.getUploader() - )); - return true; - case R.id.menu_item_share: - shareText(context, item.getTitle(), item.getUrl(), - item.getThumbnails()); - return true; - case R.id.menu_item_download: - fetchStreamInfoAndSaveToDatabase(context, item.getServiceId(), item.getUrl(), - info -> { - final DownloadDialog downloadDialog = new DownloadDialog(context, - info); - downloadDialog.show(fragmentManager, "downloadDialog"); - }); - return true; + return true; + } else if (itemId == R.id.menu_item_channel_details) { + SparseItemUtil.fetchUploaderUrlIfSparse(context, item.getServiceId(), + item.getUrl(), item.getUploaderUrl(), + // An intent must be used here. + // Opening with FragmentManager transactions is not working, + // as PlayQueueActivity doesn't use fragments. + uploaderUrl -> NavigationHelper.openChannelFragmentUsingIntent( + context, item.getServiceId(), uploaderUrl, item.getUploader() + )); + return true; + } else if (itemId == R.id.menu_item_share) { + shareText(context, item.getTitle(), item.getUrl(), + item.getThumbnails()); + return true; + } else if (itemId == R.id.menu_item_download) { + fetchStreamInfoAndSaveToDatabase(context, item.getServiceId(), item.getUrl(), + info -> { + final DownloadDialog downloadDialog = new DownloadDialog(context, + info); + downloadDialog.show(fragmentManager, "downloadDialog"); + }); + return true; } return false; }); diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java index 741bda246..91fac7d7b 100644 --- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java @@ -16,6 +16,7 @@ import android.os.IBinder; import android.provider.Settings; import android.util.Log; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; @@ -31,7 +32,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.view.menu.ActionMenuItemView; import androidx.appcompat.widget.Toolbar; import androidx.collection.SparseArrayCompat; import androidx.documentfile.provider.DocumentFile; @@ -113,7 +113,7 @@ public class DownloadDialog extends DialogFragment private StoredDirectoryHelper mainStorageAudio = null; private StoredDirectoryHelper mainStorageVideo = null; private DownloadManager downloadManager = null; - private ActionMenuItemView okButton = null; + private MenuItem okButton = null; private Context context = null; private boolean askForSavePath; @@ -558,17 +558,13 @@ public class DownloadDialog extends DialogFragment } boolean flag = true; - switch (checkedId) { - case R.id.audio_button: - setupAudioSpinner(); - break; - case R.id.video_button: - setupVideoSpinner(); - break; - case R.id.subtitle_button: - setupSubtitleSpinner(); - flag = false; - break; + if (checkedId == R.id.audio_button) { + setupAudioSpinner(); + } else if (checkedId == R.id.video_button) { + setupVideoSpinner(); + } else if (checkedId == R.id.subtitle_button) { + setupSubtitleSpinner(); + flag = false; } dialogBinding.threads.setEnabled(flag); @@ -585,29 +581,26 @@ public class DownloadDialog extends DialogFragment + "position = [" + position + "], id = [" + id + "]"); } - switch (parent.getId()) { - case R.id.quality_spinner: - switch (dialogBinding.videoAudioGroup.getCheckedRadioButtonId()) { - case R.id.video_button: - selectedVideoIndex = position; - onVideoStreamSelected(); - break; - case R.id.subtitle_button: - selectedSubtitleIndex = position; - break; - } - onItemSelectedSetFileName(); - break; - case R.id.audio_track_spinner: - final boolean trackChanged = selectedAudioTrackIndex != position; - selectedAudioTrackIndex = position; - if (trackChanged) { - updateSecondaryStreams(); - fetchStreamsSize(); - } - break; - case R.id.audio_stream_spinner: - selectedAudioIndex = position; + final int parentId = parent.getId(); + if (parentId == R.id.quality_spinner) { + final int checkedRadioButtonId = dialogBinding.videoAudioGroup + .getCheckedRadioButtonId(); + if (checkedRadioButtonId == R.id.video_button) { + selectedVideoIndex = position; + onVideoStreamSelected(); + } else if (checkedRadioButtonId == R.id.subtitle_button) { + selectedSubtitleIndex = position; + } + onItemSelectedSetFileName(); + } else if (parentId == R.id.audio_track_spinner) { + final boolean trackChanged = selectedAudioTrackIndex != position; + selectedAudioTrackIndex = position; + if (trackChanged) { + updateSecondaryStreams(); + fetchStreamsSize(); + } + } else if (parentId == R.id.audio_stream_spinner) { + selectedAudioIndex = position; } } @@ -622,23 +615,20 @@ public class DownloadDialog extends DialogFragment || prevFileName.startsWith(getString(R.string.caption_file_name, fileName, ""))) { // only update the file name field if it was not edited by the user - switch (dialogBinding.videoAudioGroup.getCheckedRadioButtonId()) { - case R.id.audio_button: - case R.id.video_button: - if (!prevFileName.equals(fileName)) { - // since the user might have switched between audio and video, the correct - // text might already be in place, so avoid resetting the cursor position - dialogBinding.fileName.setText(fileName); - } - break; - - case R.id.subtitle_button: - final String setSubtitleLanguageCode = subtitleStreamsAdapter - .getItem(selectedSubtitleIndex).getLanguageTag(); - // this will reset the cursor position, which is bad UX, but it can't be avoided - dialogBinding.fileName.setText(getString( - R.string.caption_file_name, fileName, setSubtitleLanguageCode)); - break; + final int radioButtonId = dialogBinding.videoAudioGroup + .getCheckedRadioButtonId(); + if (radioButtonId == R.id.audio_button || radioButtonId == R.id.video_button) { + if (!prevFileName.equals(fileName)) { + // since the user might have switched between audio and video, the correct + // text might already be in place, so avoid resetting the cursor position + dialogBinding.fileName.setText(fileName); + } + } else if (radioButtonId == R.id.subtitle_button) { + final String setSubtitleLanguageCode = subtitleStreamsAdapter + .getItem(selectedSubtitleIndex).getLanguageTag(); + // this will reset the cursor position, which is bad UX, but it can't be avoided + dialogBinding.fileName.setText(getString( + R.string.caption_file_name, fileName, setSubtitleLanguageCode)); } } } @@ -770,47 +760,44 @@ public class DownloadDialog extends DialogFragment filenameTmp = getNameEditText().concat("."); - switch (dialogBinding.videoAudioGroup.getCheckedRadioButtonId()) { - case R.id.audio_button: - selectedMediaType = getString(R.string.last_download_type_audio_key); - mainStorage = mainStorageAudio; - format = audioStreamsAdapter.getItem(selectedAudioIndex).getFormat(); - size = getWrappedAudioStreams().getSizeInBytes(selectedAudioIndex); - if (format == MediaFormat.WEBMA_OPUS) { - mimeTmp = "audio/ogg"; - filenameTmp += "opus"; - } else if (format != null) { - mimeTmp = format.mimeType; - filenameTmp += format.getSuffix(); - } - break; - case R.id.video_button: - selectedMediaType = getString(R.string.last_download_type_video_key); - mainStorage = mainStorageVideo; - format = videoStreamsAdapter.getItem(selectedVideoIndex).getFormat(); - size = wrappedVideoStreams.getSizeInBytes(selectedVideoIndex); - if (format != null) { - mimeTmp = format.mimeType; - filenameTmp += format.getSuffix(); - } - break; - case R.id.subtitle_button: - selectedMediaType = getString(R.string.last_download_type_subtitle_key); - mainStorage = mainStorageVideo; // subtitle & video files go together - format = subtitleStreamsAdapter.getItem(selectedSubtitleIndex).getFormat(); - size = wrappedSubtitleStreams.getSizeInBytes(selectedSubtitleIndex); - if (format != null) { - mimeTmp = format.mimeType; - } + final int checkedRadioButtonId = dialogBinding.videoAudioGroup.getCheckedRadioButtonId(); + if (checkedRadioButtonId == R.id.audio_button) { + selectedMediaType = getString(R.string.last_download_type_audio_key); + mainStorage = mainStorageAudio; + format = audioStreamsAdapter.getItem(selectedAudioIndex).getFormat(); + size = getWrappedAudioStreams().getSizeInBytes(selectedAudioIndex); + if (format == MediaFormat.WEBMA_OPUS) { + mimeTmp = "audio/ogg"; + filenameTmp += "opus"; + } else if (format != null) { + mimeTmp = format.mimeType; + filenameTmp += format.getSuffix(); + } + } else if (checkedRadioButtonId == R.id.video_button) { + selectedMediaType = getString(R.string.last_download_type_video_key); + mainStorage = mainStorageVideo; + format = videoStreamsAdapter.getItem(selectedVideoIndex).getFormat(); + size = wrappedVideoStreams.getSizeInBytes(selectedVideoIndex); + if (format != null) { + mimeTmp = format.mimeType; + filenameTmp += format.getSuffix(); + } + } else if (checkedRadioButtonId == R.id.subtitle_button) { + selectedMediaType = getString(R.string.last_download_type_subtitle_key); + mainStorage = mainStorageVideo; // subtitle & video files go together + format = subtitleStreamsAdapter.getItem(selectedSubtitleIndex).getFormat(); + size = wrappedSubtitleStreams.getSizeInBytes(selectedSubtitleIndex); + if (format != null) { + mimeTmp = format.mimeType; + } - if (format == MediaFormat.TTML) { - filenameTmp += MediaFormat.SRT.getSuffix(); - } else if (format != null) { - filenameTmp += format.getSuffix(); - } - break; - default: - throw new RuntimeException("No stream selected"); + if (format == MediaFormat.TTML) { + filenameTmp += MediaFormat.SRT.getSuffix(); + } else if (format != null) { + filenameTmp += format.getSuffix(); + } + } else { + throw new RuntimeException("No stream selected"); } if (!askForSavePath && (mainStorage == null @@ -1057,59 +1044,56 @@ public class DownloadDialog extends DialogFragment long nearLength = 0; // more download logic: select muxer, subtitle converter, etc. - switch (dialogBinding.videoAudioGroup.getCheckedRadioButtonId()) { - case R.id.audio_button: - kind = 'a'; - selectedStream = audioStreamsAdapter.getItem(selectedAudioIndex); + final int checkedRadioButtonId = dialogBinding.videoAudioGroup.getCheckedRadioButtonId(); + if (checkedRadioButtonId == R.id.audio_button) { + kind = 'a'; + selectedStream = audioStreamsAdapter.getItem(selectedAudioIndex); - if (selectedStream.getFormat() == MediaFormat.M4A) { - psName = Postprocessing.ALGORITHM_M4A_NO_DASH; - } else if (selectedStream.getFormat() == MediaFormat.WEBMA_OPUS) { - psName = Postprocessing.ALGORITHM_OGG_FROM_WEBM_DEMUXER; + if (selectedStream.getFormat() == MediaFormat.M4A) { + psName = Postprocessing.ALGORITHM_M4A_NO_DASH; + } else if (selectedStream.getFormat() == MediaFormat.WEBMA_OPUS) { + psName = Postprocessing.ALGORITHM_OGG_FROM_WEBM_DEMUXER; + } + } else if (checkedRadioButtonId == R.id.video_button) { + kind = 'v'; + selectedStream = videoStreamsAdapter.getItem(selectedVideoIndex); + + final SecondaryStreamHelper secondary = videoStreamsAdapter + .getAllSecondary() + .get(wrappedVideoStreams.getStreamsList().indexOf(selectedStream)); + + if (secondary != null) { + secondaryStream = secondary.getStream(); + + if (selectedStream.getFormat() == MediaFormat.MPEG_4) { + psName = Postprocessing.ALGORITHM_MP4_FROM_DASH_MUXER; + } else { + psName = Postprocessing.ALGORITHM_WEBM_MUXER; } - break; - case R.id.video_button: - kind = 'v'; - selectedStream = videoStreamsAdapter.getItem(selectedVideoIndex); - final SecondaryStreamHelper secondary = videoStreamsAdapter - .getAllSecondary() - .get(wrappedVideoStreams.getStreamsList().indexOf(selectedStream)); + final long videoSize = wrappedVideoStreams.getSizeInBytes( + (VideoStream) selectedStream); - if (secondary != null) { - secondaryStream = secondary.getStream(); - - if (selectedStream.getFormat() == MediaFormat.MPEG_4) { - psName = Postprocessing.ALGORITHM_MP4_FROM_DASH_MUXER; - } else { - psName = Postprocessing.ALGORITHM_WEBM_MUXER; - } - - final long videoSize = wrappedVideoStreams.getSizeInBytes( - (VideoStream) selectedStream); - - // set nearLength, only, if both sizes are fetched or known. This probably - // does not work on slow networks but is later updated in the downloader - if (secondary.getSizeInBytes() > 0 && videoSize > 0) { - nearLength = secondary.getSizeInBytes() + videoSize; - } + // set nearLength, only, if both sizes are fetched or known. This probably + // does not work on slow networks but is later updated in the downloader + if (secondary.getSizeInBytes() > 0 && videoSize > 0) { + nearLength = secondary.getSizeInBytes() + videoSize; } - break; - case R.id.subtitle_button: - threads = 1; // use unique thread for subtitles due small file size - kind = 's'; - selectedStream = subtitleStreamsAdapter.getItem(selectedSubtitleIndex); + } + } else if (checkedRadioButtonId == R.id.subtitle_button) { + threads = 1; // use unique thread for subtitles due small file size + kind = 's'; + selectedStream = subtitleStreamsAdapter.getItem(selectedSubtitleIndex); - if (selectedStream.getFormat() == MediaFormat.TTML) { - psName = Postprocessing.ALGORITHM_TTML_CONVERTER; - psArgs = new String[] { - selectedStream.getFormat().getSuffix(), - "false" // ignore empty frames - }; - } - break; - default: - return; + if (selectedStream.getFormat() == MediaFormat.TTML) { + psName = Postprocessing.ALGORITHM_TTML_CONVERTER; + psArgs = new String[]{ + selectedStream.getFormat().getSuffix(), + "false" // ignore empty frames + }; + } + } else { + return; } if (secondaryStream == null) { diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt index 7facb5d85..0fa302623 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt @@ -134,8 +134,11 @@ class ErrorUtil { ) ) - NotificationManagerCompat.from(context) - .notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build()) + val notificationManager = NotificationManagerCompat.from(context) + if (notificationManager.areNotificationsEnabled()) { + notificationManager + .notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build()) + } ContextCompat.getMainExecutor(context).execute { // since the notification is silent, also show a toast, otherwise the user is confused diff --git a/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java b/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java index 51a0ff1e6..811671039 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java @@ -126,6 +126,7 @@ public class ReCaptchaActivity extends AppCompatActivity { } @Override + @SuppressLint("MissingSuperCall") // saveCookiesAndFinish method handles back navigation public void onBackPressed() { saveCookiesAndFinish(); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index d75d14b4a..878ceb139 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -160,34 +160,29 @@ public class ChannelFragment extends BaseStateFragment @Override public boolean onMenuItemSelected(@NonNull final MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_item_notify: - final boolean value = !item.isChecked(); - item.setEnabled(false); - setNotify(value); - break; - case R.id.action_settings: - NavigationHelper.openSettings(requireContext()); - break; - case R.id.menu_item_rss: - if (currentInfo != null) { - ShareUtils.openUrlInApp(requireContext(), currentInfo.getFeedUrl()); - } - break; - case R.id.menu_item_openInBrowser: - if (currentInfo != null) { - ShareUtils.openUrlInBrowser(requireContext(), - currentInfo.getOriginalUrl()); - } - break; - case R.id.menu_item_share: - if (currentInfo != null) { - ShareUtils.shareText(requireContext(), name, - currentInfo.getOriginalUrl(), currentInfo.getAvatars()); - } - break; - default: - return false; + final int itemId = item.getItemId(); + if (itemId == R.id.menu_item_notify) { + final boolean value = !item.isChecked(); + item.setEnabled(false); + setNotify(value); + } else if (itemId == R.id.action_settings) { + NavigationHelper.openSettings(requireContext()); + } else if (itemId == R.id.menu_item_rss) { + if (currentInfo != null) { + ShareUtils.openUrlInApp(requireContext(), currentInfo.getFeedUrl()); + } + } else if (itemId == R.id.menu_item_openInBrowser) { + if (currentInfo != null) { + ShareUtils.openUrlInBrowser(requireContext(), + currentInfo.getOriginalUrl()); + } + } else if (itemId == R.id.menu_item_share) { + if (currentInfo != null) { + ShareUtils.shareText(requireContext(), name, + currentInfo.getOriginalUrl(), currentInfo.getAvatars()); + } + } else { + return false; } return true; } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java index 6410fb9ee..ee6a0922c 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java @@ -232,35 +232,30 @@ public class PlaylistFragment extends BaseListInfoFragment dialog.show(getFM(), TAG) - )); - } - break; - default: - return super.onOptionsItemSelected(item); + final int itemId = item.getItemId(); + if (itemId == R.id.action_settings) { + NavigationHelper.openSettings(requireContext()); + } else if (itemId == R.id.menu_item_openInBrowser) { + ShareUtils.openUrlInBrowser(requireContext(), url); + } else if (itemId == R.id.menu_item_share) { + ShareUtils.shareText(requireContext(), name, url, + currentInfo == null ? List.of() : currentInfo.getThumbnails()); + } else if (itemId == R.id.menu_item_bookmark) { + onBookmarkClicked(); + } else if (itemId == R.id.menu_item_append_playlist) { + if (currentInfo != null) { + disposables.add(PlaylistDialog.createCorrespondingDialog( + getContext(), + getPlayQueue() + .getStreams() + .stream() + .map(StreamEntity::new) + .collect(Collectors.toList()), + dialog -> dialog.show(getFM(), TAG) + )); + } + } else { + return super.onOptionsItemSelected(item); } return true; } diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index ac076f1b8..89b89a800 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -255,7 +255,7 @@ class FeedFragment : BaseStateFragment() { viewModel.getShowFutureItemsFromPreferences() ) - AlertDialog.Builder(context!!) + AlertDialog.Builder(requireContext()) .setTitle(R.string.feed_hide_streams_title) .setMultiChoiceItems(dialogItems, checkedDialogItems) { _, which, isChecked -> checkedDialogItems[which] = isChecked diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationHelper.kt b/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationHelper.kt index d2d16a755..aa03aafc5 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationHelper.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationHelper.kt @@ -92,8 +92,10 @@ class NotificationHelper(val context: Context) { // Show individual stream notifications, set channel icon only if there is actually // one showStreamNotifications(newStreams, data.serviceId, data.url, bitmap) - // Show summary notification - manager.notify(data.pseudoId, summaryBuilder.build()) + // Show summary notification if enabled + if (manager.areNotificationsEnabled()) { + manager.notify(data.pseudoId, summaryBuilder.build()) + } iconLoadingTargets.remove(this) // allow it to be garbage-collected } @@ -101,8 +103,10 @@ class NotificationHelper(val context: Context) { override fun onBitmapFailed(e: Exception, errorDrawable: Drawable) { // Show individual stream notifications showStreamNotifications(newStreams, data.serviceId, data.url, null) - // Show summary notification - manager.notify(data.pseudoId, summaryBuilder.build()) + // Show summary notification if enabled + if (manager.areNotificationsEnabled()) { + manager.notify(data.pseudoId, summaryBuilder.build()) + } iconLoadingTargets.remove(this) // allow it to be garbage-collected } @@ -124,9 +128,12 @@ class NotificationHelper(val context: Context) { channelUrl: String, channelIcon: Bitmap? ) { - for (stream in newStreams) { - val notification = createStreamNotification(stream, serviceId, channelUrl, channelIcon) - manager.notify(stream.url.hashCode(), notification) + if (manager.areNotificationsEnabled()) { + newStreams.forEach { stream -> + val notification = + createStreamNotification(stream, serviceId, channelUrl, channelIcon) + manager.notify(stream.url.hashCode(), notification) + } } } diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt b/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt index 48ad5df94..bd128b3bc 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt @@ -185,7 +185,9 @@ class FeedLoadService : Service() { } } - notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()) + if (notificationManager.areNotificationsEnabled()) { + notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()) + } } // ///////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/dialog/FeedGroupDialog.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/dialog/FeedGroupDialog.kt index 7a256c166..b0ccaa3c5 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/dialog/FeedGroupDialog.kt +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/dialog/FeedGroupDialog.kt @@ -506,7 +506,7 @@ class FeedGroupDialog : DialogFragment(), BackPressable { private fun hideKeyboardSearch() { inputMethodManager.hideSoftInputFromWindow( searchLayoutBinding.toolbarSearchEditText.windowToken, - InputMethodManager.RESULT_UNCHANGED_SHOWN + InputMethodManager.HIDE_NOT_ALWAYS ) searchLayoutBinding.toolbarSearchEditText.clearFocus() } @@ -523,7 +523,7 @@ class FeedGroupDialog : DialogFragment(), BackPressable { private fun hideKeyboard() { inputMethodManager.hideSoftInputFromWindow( feedGroupCreateBinding.groupNameInput.windowToken, - InputMethodManager.RESULT_UNCHANGED_SHOWN + InputMethodManager.HIDE_NOT_ALWAYS ) feedGroupCreateBinding.groupNameInput.clearFocus() } diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java index b7c11b160..850409e25 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java @@ -144,7 +144,9 @@ public abstract class BaseImportExportService extends Service { notificationBuilder.setContentText(text); } - notificationManager.notify(getNotificationId(), notificationBuilder.build()); + if (notificationManager.areNotificationsEnabled()) { + notificationManager.notify(getNotificationId(), notificationBuilder.build()); + } } protected void stopService() { @@ -174,7 +176,10 @@ public abstract class BaseImportExportService extends Service { .setContentTitle(title) .setStyle(new NotificationCompat.BigTextStyle().bigText(textOrEmpty)) .setContentText(textOrEmpty); - notificationManager.notify(getNotificationId(), notificationBuilder.build()); + + if (notificationManager.areNotificationsEnabled()) { + notificationManager.notify(getNotificationId(), notificationBuilder.build()); + } } protected NotificationCompat.Builder createNotification() { diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java index 06b33f861..b6bb84ec6 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java +++ b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java @@ -127,39 +127,39 @@ public final class PlayQueueActivity extends AppCompatActivity @Override public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - return true; - case R.id.action_settings: - NavigationHelper.openSettings(this); - return true; - case R.id.action_append_playlist: - PlaylistDialog.showForPlayQueue(player, getSupportFragmentManager()); - return true; - case R.id.action_playback_speed: - openPlaybackParameterDialog(); - return true; - case R.id.action_mute: - player.toggleMute(); - return true; - case R.id.action_system_audio: - startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS)); - return true; - case R.id.action_switch_main: + final int itemId = item.getItemId(); + if (itemId == android.R.id.home) { + finish(); + return true; + } else if (itemId == R.id.action_settings) { + NavigationHelper.openSettings(this); + return true; + } else if (itemId == R.id.action_append_playlist) { + PlaylistDialog.showForPlayQueue(player, getSupportFragmentManager()); + return true; + } else if (itemId == R.id.action_playback_speed) { + openPlaybackParameterDialog(); + return true; + } else if (itemId == R.id.action_mute) { + player.toggleMute(); + return true; + } else if (itemId == R.id.action_system_audio) { + startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS)); + return true; + } else if (itemId == R.id.action_switch_main) { + this.player.setRecovery(); + NavigationHelper.playOnMainPlayer(this, player.getPlayQueue(), true); + return true; + } else if (itemId == R.id.action_switch_popup) { + if (PermissionHelper.isPopupEnabledElseAsk(this)) { this.player.setRecovery(); - NavigationHelper.playOnMainPlayer(this, player.getPlayQueue(), true); - return true; - case R.id.action_switch_popup: - if (PermissionHelper.isPopupEnabledElseAsk(this)) { - this.player.setRecovery(); - NavigationHelper.playOnPopupPlayer(this, player.getPlayQueue(), true); - } - return true; - case R.id.action_switch_background: - this.player.setRecovery(); - NavigationHelper.playOnBackgroundPlayer(this, player.getPlayQueue(), true); - return true; + NavigationHelper.playOnPopupPlayer(this, player.getPlayQueue(), true); + } + return true; + } else if (itemId == R.id.action_switch_background) { + this.player.setRecovery(); + NavigationHelper.playOnBackgroundPlayer(this, player.getPlayQueue(), true); + return true; } if (item.getGroupId() == MENU_ID_AUDIO_TRACK) { diff --git a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java index 9b9c47b0e..be98abb7a 100644 --- a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java +++ b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java @@ -72,7 +72,9 @@ public final class NotificationUtil { notificationBuilder = createNotification(); } updateNotification(); - notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + if (notificationManager.areNotificationsEnabled()) { + notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + } } public synchronized void updateThumbnail() { @@ -84,7 +86,9 @@ public final class NotificationUtil { } setLargeIcon(notificationBuilder); - notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + if (notificationManager.areNotificationsEnabled()) { + notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + } } } diff --git a/app/src/main/java/org/schabi/newpipe/util/KeyboardUtil.java b/app/src/main/java/org/schabi/newpipe/util/KeyboardUtil.java index a709dc32e..679f3e042 100644 --- a/app/src/main/java/org/schabi/newpipe/util/KeyboardUtil.java +++ b/app/src/main/java/org/schabi/newpipe/util/KeyboardUtil.java @@ -48,7 +48,7 @@ public final class KeyboardUtil { final InputMethodManager imm = ContextCompat.getSystemService(activity, InputMethodManager.class); imm.hideSoftInputFromWindow(editText.getWindowToken(), - InputMethodManager.RESULT_UNCHANGED_SHOWN); + InputMethodManager.HIDE_NOT_ALWAYS); editText.clearFocus(); } diff --git a/app/src/main/java/org/schabi/newpipe/views/FocusOverlayView.java b/app/src/main/java/org/schabi/newpipe/views/FocusOverlayView.java index 29c38511c..9e06211f2 100644 --- a/app/src/main/java/org/schabi/newpipe/views/FocusOverlayView.java +++ b/app/src/main/java/org/schabi/newpipe/views/FocusOverlayView.java @@ -40,7 +40,6 @@ import android.view.Window; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; -import androidx.appcompat.view.WindowCallbackWrapper; import org.schabi.newpipe.R; @@ -232,7 +231,7 @@ public final class FocusOverlayView extends Drawable implements // Unfortunately many such forms of "scrolling" do not count as scrolling for purpose // of dispatching ViewTreeObserver callbacks, so we have to intercept them by directly // receiving keys from Window. - window.setCallback(new WindowCallbackWrapper(window.getCallback()) { + window.setCallback(new SimpleWindowCallback(window.getCallback()) { @Override public boolean dispatchKeyEvent(final KeyEvent event) { final boolean res = super.dispatchKeyEvent(event); diff --git a/app/src/main/java/org/schabi/newpipe/views/SimpleWindowCallback.kt b/app/src/main/java/org/schabi/newpipe/views/SimpleWindowCallback.kt new file mode 100644 index 000000000..46f58d24c --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/views/SimpleWindowCallback.kt @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2026 NewPipe e.V. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package org.schabi.newpipe.views + +import android.os.Build +import android.view.KeyEvent +import android.view.KeyboardShortcutGroup +import android.view.Menu +import android.view.Window +import androidx.annotation.RequiresApi + +/** + * Simple window callback class to allow intercepting key events + * @see FocusOverlayView.setupOverlay + */ +open class SimpleWindowCallback(private val baseCallback: Window.Callback) : + Window.Callback by baseCallback { + + override fun dispatchKeyEvent(event: KeyEvent?): Boolean { + return baseCallback.dispatchKeyEvent(event) + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun onPointerCaptureChanged(hasCapture: Boolean) { + baseCallback.onPointerCaptureChanged(hasCapture) + } + + @RequiresApi(Build.VERSION_CODES.N) + override fun onProvideKeyboardShortcuts( + data: List?, + menu: Menu?, + deviceId: Int + ) { + baseCallback.onProvideKeyboardShortcuts(data, menu, deviceId) + } +} diff --git a/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java b/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java index 1d2483e79..b79ff59c3 100644 --- a/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java +++ b/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java @@ -21,7 +21,7 @@ import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_FORBIDDEN; * Single-threaded fallback mode */ public class DownloadRunnableFallback extends Thread { - private static final String TAG = "DownloadRunnableFallback"; + private static final String TAG = "DLRunnableFallback"; private final DownloadMission mMission; diff --git a/app/src/main/java/us/shandian/giga/get/sqlite/FinishedMissionStore.java b/app/src/main/java/us/shandian/giga/get/sqlite/FinishedMissionStore.java index 704385212..215a6553b 100644 --- a/app/src/main/java/us/shandian/giga/get/sqlite/FinishedMissionStore.java +++ b/app/src/main/java/us/shandian/giga/get/sqlite/FinishedMissionStore.java @@ -102,14 +102,23 @@ public class FinishedMissionStore extends SQLiteOpenHelper { db.beginTransaction(); while (cursor.moveToNext()) { ContentValues values = new ContentValues(); - values.put(KEY_SOURCE, cursor.getString(cursor.getColumnIndex(KEY_SOURCE))); - values.put(KEY_DONE, cursor.getString(cursor.getColumnIndex(KEY_DONE))); - values.put(KEY_TIMESTAMP, cursor.getLong(cursor.getColumnIndex(KEY_TIMESTAMP))); - values.put(KEY_KIND, cursor.getString(cursor.getColumnIndex(KEY_KIND))); + values.put( + KEY_SOURCE, + cursor.getString(cursor.getColumnIndexOrThrow(KEY_SOURCE)) + ); + values.put( + KEY_DONE, + cursor.getString(cursor.getColumnIndexOrThrow(KEY_DONE)) + ); + values.put( + KEY_TIMESTAMP, + cursor.getLong(cursor.getColumnIndexOrThrow(KEY_TIMESTAMP)) + ); + values.put(KEY_KIND, cursor.getString(cursor.getColumnIndexOrThrow(KEY_KIND))); values.put(KEY_PATH, Uri.fromFile( new File( - cursor.getString(cursor.getColumnIndex(KEY_LOCATION)), - cursor.getString(cursor.getColumnIndex(KEY_NAME)) + cursor.getString(cursor.getColumnIndexOrThrow(KEY_LOCATION)), + cursor.getString(cursor.getColumnIndexOrThrow(KEY_NAME)) ) ).toString()); @@ -141,7 +150,8 @@ public class FinishedMissionStore extends SQLiteOpenHelper { } private FinishedMission getMissionFromCursor(Cursor cursor) { - String kind = Objects.requireNonNull(cursor).getString(cursor.getColumnIndex(KEY_KIND)); + String kind = Objects.requireNonNull(cursor) + .getString(cursor.getColumnIndexOrThrow(KEY_KIND)); if (kind == null || kind.isEmpty()) kind = "?"; String path = cursor.getString(cursor.getColumnIndexOrThrow(KEY_PATH)); diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java index 54ae2cfa4..45ffcb331 100644 --- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java +++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java @@ -632,103 +632,95 @@ public class MissionAdapter extends Adapter implements Handler.Callb DownloadMission mission = h.item.mission instanceof DownloadMission ? (DownloadMission) h.item.mission : null; if (mission != null) { - switch (id) { - case R.id.start: - h.status.setText(UNDEFINED_PROGRESS); - mDownloadManager.resumeMission(mission); - return true; - case R.id.pause: - mDownloadManager.pauseMission(mission); - return true; - case R.id.error_message_view: - showError(mission); - return true; - case R.id.queue: - boolean flag = !h.queue.isChecked(); - h.queue.setChecked(flag); - mission.setEnqueued(flag); - updateProgress(h); - return true; - case R.id.retry: - if (mission.isPsRunning()) { - mission.psContinue(true); - } else { - mDownloadManager.tryRecover(mission); - if (mission.storage.isInvalid()) - mRecover.tryRecover(mission); - else - recoverMission(mission); - } - return true; - case R.id.cancel: - mission.psContinue(false); - return false; + if (id == R.id.start) { + h.status.setText(UNDEFINED_PROGRESS); + mDownloadManager.resumeMission(mission); + return true; + } else if (id == R.id.pause) { + mDownloadManager.pauseMission(mission); + return true; + } else if (id == R.id.error_message_view) { + showError(mission); + return true; + } else if (id == R.id.queue) { + boolean flag = !h.queue.isChecked(); + h.queue.setChecked(flag); + mission.setEnqueued(flag); + updateProgress(h); + return true; + } else if (id == R.id.retry) { + if (mission.isPsRunning()) { + mission.psContinue(true); + } else { + mDownloadManager.tryRecover(mission); + if (mission.storage.isInvalid()) + mRecover.tryRecover(mission); + else + recoverMission(mission); + } + return true; + } else if (id == R.id.cancel) { + mission.psContinue(false); + return false; } } - switch (id) { - case R.id.menu_item_share: - shareFile(h.item.mission); - return true; - case R.id.delete: - // delete the entry and the file + if (id == R.id.menu_item_share) { + shareFile(h.item.mission); + return true; + } else if (id == R.id.delete) {// delete the entry and the file + mDeleter.append(h.item.mission, true); + applyChanges(); + checkMasterButtonsVisibility(); + return true; + } else if (id == R.id.delete_entry) {// just delete the entry + mDeleter.append(h.item.mission, false); + applyChanges(); + checkMasterButtonsVisibility(); + return true; + } else if (id == R.id.md5 || id == R.id.sha1) { + final StoredFileHelper storage = h.item.mission.storage; + if (!storage.existsAsFile()) { + Toast.makeText(mContext, R.string.missing_file, Toast.LENGTH_SHORT).show(); mDeleter.append(h.item.mission, true); applyChanges(); - checkMasterButtonsVisibility(); return true; - case R.id.delete_entry: - // just delete the entry - mDeleter.append(h.item.mission, false); - applyChanges(); - checkMasterButtonsVisibility(); - return true; - case R.id.md5: - case R.id.sha1: - final StoredFileHelper storage = h.item.mission.storage; - if (!storage.existsAsFile()) { - Toast.makeText(mContext, R.string.missing_file, Toast.LENGTH_SHORT).show(); - mDeleter.append(h.item.mission, true); - applyChanges(); - return true; - } - final NotificationManager notificationManager - = ContextCompat.getSystemService(mContext, NotificationManager.class); - final NotificationCompat.Builder progressNotificationBuilder - = new NotificationCompat.Builder(mContext, - mContext.getString(R.string.hash_channel_id)) - .setPriority(NotificationCompat.PRIORITY_HIGH) - .setSmallIcon(R.drawable.ic_newpipe_triangle_white) - .setContentTitle(mContext.getString(R.string.msg_calculating_hash)) - .setContentText(mContext.getString(R.string.msg_wait)) - .setProgress(0, 0, true) - .setOngoing(true); + } + final NotificationManager notificationManager + = ContextCompat.getSystemService(mContext, NotificationManager.class); + final NotificationCompat.Builder progressNotificationBuilder + = new NotificationCompat.Builder(mContext, + mContext.getString(R.string.hash_channel_id)) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setSmallIcon(R.drawable.ic_newpipe_triangle_white) + .setContentTitle(mContext.getString(R.string.msg_calculating_hash)) + .setContentText(mContext.getString(R.string.msg_wait)) + .setProgress(0, 0, true) + .setOngoing(true); - notificationManager.notify(HASH_NOTIFICATION_ID, progressNotificationBuilder - .build()); - compositeDisposable.add( - Observable.fromCallable(() -> Utility.checksum(storage, id)) - .subscribeOn(Schedulers.computation()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(result -> { - ShareUtils.copyToClipboard(mContext, result); - notificationManager.cancel(HASH_NOTIFICATION_ID); - }) - ); - return true; - case R.id.source: - /*Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(h.item.mission.source)); - mContext.startActivity(intent);*/ - try { - Intent intent = NavigationHelper.getIntentByLink(mContext, h.item.mission.source); - intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); - mContext.startActivity(intent); - } catch (Exception e) { - Log.w(TAG, "Selected item has a invalid source", e); - } - return true; - default: - return false; + notificationManager.notify(HASH_NOTIFICATION_ID, progressNotificationBuilder + .build()); + compositeDisposable.add( + Observable.fromCallable(() -> Utility.checksum(storage, id)) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + ShareUtils.copyToClipboard(mContext, result); + notificationManager.cancel(HASH_NOTIFICATION_ID); + }) + ); + return true; + } else if (id == R.id.source) { + try { + Intent intent = NavigationHelper.getIntentByLink(mContext, h.item.mission.source); + intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); + mContext.startActivity(intent); + } catch (Exception e) { + Log.w(TAG, "Selected item has a invalid source", e); + } + return true; } + return false; } public void applyChanges() { diff --git a/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java b/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java index 690ed4a97..ddd9ba426 100644 --- a/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java +++ b/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java @@ -186,23 +186,24 @@ public class MissionsFragment extends Fragment { @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.switch_mode: - mLinear = !mLinear; - updateList(); - return true; - case R.id.clear_list: - showClearDownloadHistoryPrompt(); - return true; - case R.id.start_downloads: - mBinder.getDownloadManager().startAllMissions(); - return true; - case R.id.pause_downloads: - mBinder.getDownloadManager().pauseAllMissions(false); - mAdapter.refreshMissionItems();// update items view - default: - return super.onOptionsItemSelected(item); + int itemId = item.getItemId(); + if (itemId == R.id.switch_mode) { + mLinear = !mLinear; + updateList(); + return true; + } else if (itemId == R.id.clear_list) { + showClearDownloadHistoryPrompt(); + return true; + } else if (itemId == R.id.start_downloads) { + mBinder.getDownloadManager().startAllMissions(); + return true; + } else if (itemId == R.id.pause_downloads) { + mBinder.getDownloadManager().pauseAllMissions(false); + mAdapter.refreshMissionItems();// update items view + + return super.onOptionsItemSelected(item); } + return super.onOptionsItemSelected(item); } public void showClearDownloadHistoryPrompt() { diff --git a/app/src/main/res/drawable/ic_smart_display.xml b/app/src/main/res/drawable/ic_smart_display.xml index d666a3b37..93d73aee5 100644 --- a/app/src/main/res/drawable/ic_smart_display.xml +++ b/app/src/main/res/drawable/ic_smart_display.xml @@ -5,6 +5,6 @@ android:viewportWidth="24" android:tint="@color/defaultIconTint"> diff --git a/app/src/main/res/layout-land/activity_player_queue_control.xml b/app/src/main/res/layout-land/activity_player_queue_control.xml index a5df5e566..ad2655380 100644 --- a/app/src/main/res/layout-land/activity_player_queue_control.xml +++ b/app/src/main/res/layout-land/activity_player_queue_control.xml @@ -122,8 +122,8 @@ android:focusable="true" android:scaleType="fitCenter" android:src="@drawable/exo_controls_rewind" - android:tint="?attr/colorAccent" - android:contentDescription="@string/rewind" /> + android:contentDescription="@string/rewind" + app:tint="?attr/colorAccent" /> + android:contentDescription="@string/pause" + app:tint="?attr/colorAccent" /> + android:contentDescription="@string/forward" + app:tint="?attr/colorAccent" /> + android:contentDescription="@string/notification_action_repeat" + app:tint="?attr/colorAccent" /> + android:contentDescription="@string/notification_action_shuffle" + app:tint="?attr/colorAccent" /> + app:tint="?attr/colorAccent" /> + app:tint="?attr/colorAccent" /> diff --git a/gradle.properties b/gradle.properties index a529a42c8..1a8297ddf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,3 @@ -android.nonFinalResIds=false android.useAndroidX=true org.gradle.jvmargs=-Xmx2048M --add-opens jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED systemProp.file.encoding=utf-8