Conflicts:
	README.md
	app/build.gradle
	app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt
	app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt
	app/src/main/java/code/name/monkey/retromusic/fragments/player/lockscreen/LockScreenPlayerControlsFragment.kt
	app/src/main/java/code/name/monkey/retromusic/interfaces/CabHolder.kt
	app/src/main/java/code/name/monkey/retromusic/interfaces/MainActivityFragmentCallbacks.kt
	app/src/main/java/code/name/monkey/retromusic/interfaces/MusicServiceEventListener.kt
	app/src/main/java/code/name/monkey/retromusic/interfaces/PaletteColorHolder.kt
	app/src/main/java/code/name/monkey/retromusic/util/AppRater.kt
	app/src/main/java/io/github/muntashirakon/music/App.kt
	app/src/main/java/io/github/muntashirakon/music/Constants.kt
	app/src/main/java/io/github/muntashirakon/music/HomeSection.kt
	app/src/main/java/io/github/muntashirakon/music/MainModule.kt
	app/src/main/java/io/github/muntashirakon/music/activities/DriveModeActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/LicenseActivity.java
	app/src/main/java/io/github/muntashirakon/music/activities/LockScreenActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/LyricsActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/MainActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/PermissionActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/PlayingQueueActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/SettingsActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/ShareInstagramStory.kt
	app/src/main/java/io/github/muntashirakon/music/activities/UserInfoActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/WhatsNewActivity.java
	app/src/main/java/io/github/muntashirakon/music/activities/base/AbsBaseActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/base/AbsMusicServiceActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/base/AbsSlidingMusicPanelActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/base/AbsThemeActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/bugreport/BugReportActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/bugreport/model/DeviceInfo.java
	app/src/main/java/io/github/muntashirakon/music/activities/bugreport/model/Report.java
	app/src/main/java/io/github/muntashirakon/music/activities/saf/SAFGuideActivity.java
	app/src/main/java/io/github/muntashirakon/music/activities/tageditor/AbsTagEditorActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/tageditor/AlbumTagEditorActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/tageditor/SongTagEditorActivity.kt
	app/src/main/java/io/github/muntashirakon/music/activities/tageditor/WriteTagsAsyncTask.java
	app/src/main/java/io/github/muntashirakon/music/adapter/CategoryInfoAdapter.java
	app/src/main/java/io/github/muntashirakon/music/adapter/ContributorAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/GenreAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/HomeAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/SearchAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/SongFileAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/TranslatorsAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/album/AlbumAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/album/AlbumCoverPagerAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/album/HorizontalAlbumAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/artist/ArtistAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/base/AbsMultiSelectAdapter.java
	app/src/main/java/io/github/muntashirakon/music/adapter/base/MediaEntryViewHolder.java
	app/src/main/java/io/github/muntashirakon/music/adapter/playlist/LegacyPlaylistAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/playlist/PlaylistAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/song/AbsOffsetSongAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/song/OrderablePlaylistSongAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/song/PlayingQueueAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/song/PlaylistSongAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/song/ShuffleButtonSongAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/song/SimpleSongAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/song/SongAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/appshortcuts/AppShortcutIconGenerator.kt
	app/src/main/java/io/github/muntashirakon/music/appshortcuts/AppShortcutLauncherActivity.kt
	app/src/main/java/io/github/muntashirakon/music/appshortcuts/DynamicShortcutManager.kt
	app/src/main/java/io/github/muntashirakon/music/appshortcuts/shortcuttype/BaseShortcutType.kt
	app/src/main/java/io/github/muntashirakon/music/appshortcuts/shortcuttype/LastAddedShortcutType.kt
	app/src/main/java/io/github/muntashirakon/music/appshortcuts/shortcuttype/ShuffleAllShortcutType.kt
	app/src/main/java/io/github/muntashirakon/music/appshortcuts/shortcuttype/TopTracksShortcutType.kt
	app/src/main/java/io/github/muntashirakon/music/appwidgets/AppWidgetBig.kt
	app/src/main/java/io/github/muntashirakon/music/appwidgets/AppWidgetCard.kt
	app/src/main/java/io/github/muntashirakon/music/appwidgets/AppWidgetClassic.kt
	app/src/main/java/io/github/muntashirakon/music/appwidgets/AppWidgetSmall.kt
	app/src/main/java/io/github/muntashirakon/music/appwidgets/AppWidgetText.kt
	app/src/main/java/io/github/muntashirakon/music/appwidgets/BootReceiver.kt
	app/src/main/java/io/github/muntashirakon/music/appwidgets/base/BaseAppWidget.kt
	app/src/main/java/io/github/muntashirakon/music/db/BlackListStoreDao.kt
	app/src/main/java/io/github/muntashirakon/music/db/BlackListStoreEntity.kt
	app/src/main/java/io/github/muntashirakon/music/db/HistoryDao.kt
	app/src/main/java/io/github/muntashirakon/music/db/HistoryEntity.kt
	app/src/main/java/io/github/muntashirakon/music/db/LyricsDao.kt
	app/src/main/java/io/github/muntashirakon/music/db/LyricsEntity.kt
	app/src/main/java/io/github/muntashirakon/music/db/PlayCountDao.kt
	app/src/main/java/io/github/muntashirakon/music/db/PlayCountEntity.kt
	app/src/main/java/io/github/muntashirakon/music/db/PlaylistDao.kt
	app/src/main/java/io/github/muntashirakon/music/db/PlaylistEntity.kt
	app/src/main/java/io/github/muntashirakon/music/db/PlaylistWithSongs.kt
	app/src/main/java/io/github/muntashirakon/music/db/RetroDatabase.kt
	app/src/main/java/io/github/muntashirakon/music/db/SongEntity.kt
	app/src/main/java/io/github/muntashirakon/music/db/SongExtension.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/AddToPlaylistDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/BlacklistFolderChooserDialog.java
	app/src/main/java/io/github/muntashirakon/music/dialogs/CreatePlaylistDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/DeletePlaylistDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/DeleteSongsDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/ImportPlaylistDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/LyricsDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/RemoveSongFromPlaylistDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/RenamePlaylistDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/SavePlaylistDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/SleepTimerDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/SongDetailDialog.kt
	app/src/main/java/io/github/muntashirakon/music/dialogs/SongShareDialog.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/ActivityEx.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/ColorExt.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/CursorExtensions.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/DialogExtension.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/DimenExtension.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/DrawableExt.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/FragmentExt.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/NavigationExtensions.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/PaletteEX.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/Preference.kt
	app/src/main/java/io/github/muntashirakon/music/extensions/ViewExtensions.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/AlbumCoverStyle.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/CoroutineViewModel.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/DetailListFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/LibraryViewModel.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/MiniPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/NowPlayingScreen.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/VolumeFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/about/AboutFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumDetailsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumDetailsViewModel.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistDetailsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistDetailsViewModel.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsMainActivityFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsMusicServiceFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsPlayerControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsRecyclerViewCustomGridSizeFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsRecyclerViewFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/folder/FoldersFragment.java
	app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenreDetailsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenreDetailsViewModel.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenresFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/home/HomeFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/library/LibraryFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/NowPlayingPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/PlayerAlbumCoverFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/adaptive/AdaptiveFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/adaptive/AdaptivePlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/blur/BlurPlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/blur/BlurPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/card/CardFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/card/CardPlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/cardblur/CardBlurFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/cardblur/CardBlurPlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/circle/CirclePlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/classic/ClassicPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/color/ColorFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/color/ColorPlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/fit/FitFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/fit/FitPlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/flat/FlatPlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/flat/FlatPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/full/FullPlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/full/FullPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/gradient/GradientPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/home/HomePlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/lockscreen/LockScreenControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/lockscreen/LockScreenPlayerControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/material/MaterialControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/material/MaterialFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/normal/PlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/normal/PlayerPlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/peak/PeakPlayerControlFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/peak/PeakPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/plain/PlainPlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/plain/PlainPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/simple/SimplePlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/simple/SimplePlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/tiny/TinyPlaybackControlsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/player/tiny/TinyPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistDetailsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistDetailsViewModel.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/search/SearchFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/search/SearchViewModel.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/settings/AbsSettingsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/settings/AudioSettings.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/settings/ImageSettingFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/settings/MainSettingsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/settings/NotificationSettingsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/settings/NowPlayingSettingsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/settings/OtherSettingsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/settings/PersonalizeSettingsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/settings/ThemeSettingsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/songs/SongsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/glide/AlbumGlideRequest.java
	app/src/main/java/io/github/muntashirakon/music/glide/ArtistGlideRequest.java
	app/src/main/java/io/github/muntashirakon/music/glide/BlurTransformation.kt
	app/src/main/java/io/github/muntashirakon/music/glide/ProfileBannerGlideRequest.java
	app/src/main/java/io/github/muntashirakon/music/glide/RetroMusicColoredTarget.kt
	app/src/main/java/io/github/muntashirakon/music/glide/RetroMusicGlideModule.kt
	app/src/main/java/io/github/muntashirakon/music/glide/SingleColorTarget.kt
	app/src/main/java/io/github/muntashirakon/music/glide/SongGlideRequest.java
	app/src/main/java/io/github/muntashirakon/music/glide/UserProfileGlideRequest.java
	app/src/main/java/io/github/muntashirakon/music/glide/artistimage/ArtistImageLoader.kt
	app/src/main/java/io/github/muntashirakon/music/glide/palette/BitmapPaletteTranscoder.java
	app/src/main/java/io/github/muntashirakon/music/helper/HorizontalAdapterHelper.kt
	app/src/main/java/io/github/muntashirakon/music/helper/MusicPlayerRemote.kt
	app/src/main/java/io/github/muntashirakon/music/helper/MusicProgressViewUpdateHelper.kt
	app/src/main/java/io/github/muntashirakon/music/helper/PlayPauseButtonOnClickHandler.kt
	app/src/main/java/io/github/muntashirakon/music/helper/SearchQueryHelper.kt
	app/src/main/java/io/github/muntashirakon/music/helper/ShuffleHelper.kt
	app/src/main/java/io/github/muntashirakon/music/helper/StopWatch.kt
	app/src/main/java/io/github/muntashirakon/music/helper/menu/GenreMenuHelper.kt
	app/src/main/java/io/github/muntashirakon/music/helper/menu/PlaylistMenuHelper.kt
	app/src/main/java/io/github/muntashirakon/music/helper/menu/SongMenuHelper.kt
	app/src/main/java/io/github/muntashirakon/music/helper/menu/SongsMenuHelper.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/CabHolder.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/Callbacks.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/ICabHolder.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/IMainActivityFragmentCallbacks.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/IMusicServiceEventListener.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/IPaletteColorHolder.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/MainActivityFragmentCallbacks.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/MusicServiceEventListener.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/PaletteColorHolder.kt
	app/src/main/java/io/github/muntashirakon/music/lyrics/LrcView.java
	app/src/main/java/io/github/muntashirakon/music/model/Artist.kt
	app/src/main/java/io/github/muntashirakon/music/model/lyrics/Lyrics.java
	app/src/main/java/io/github/muntashirakon/music/providers/BlacklistStore.java
	app/src/main/java/io/github/muntashirakon/music/providers/MusicPlaybackQueueStore.java
	app/src/main/java/io/github/muntashirakon/music/repository/GenreRepository.kt
	app/src/main/java/io/github/muntashirakon/music/repository/PlaylistSongsLoader.kt
	app/src/main/java/io/github/muntashirakon/music/repository/Repository.kt
	app/src/main/java/io/github/muntashirakon/music/repository/RoomRepository.kt
	app/src/main/java/io/github/muntashirakon/music/repository/SongRepository.kt
	app/src/main/java/io/github/muntashirakon/music/service/MultiPlayer.java
	app/src/main/java/io/github/muntashirakon/music/service/MusicService.java
	app/src/main/java/io/github/muntashirakon/music/service/PlaybackHandler.java
	app/src/main/java/io/github/muntashirakon/music/util/FileUtil.java
	app/src/main/java/io/github/muntashirakon/music/util/NavigationUtil.java
	app/src/main/java/io/github/muntashirakon/music/util/PlaylistsUtil.java
	app/src/main/java/io/github/muntashirakon/music/util/PreferenceUtil.kt
	app/src/main/java/io/github/muntashirakon/music/util/RetroUtil.java
	app/src/main/java/io/github/muntashirakon/music/util/SAFUtil.java
	app/src/main/java/io/github/muntashirakon/music/util/color/MediaNotificationProcessor.java
	app/src/main/java/io/github/muntashirakon/music/util/color/NotificationColorUtil.java
	app/src/main/java/io/github/muntashirakon/music/views/BaselineGridTextView.java
	app/src/main/java/io/github/muntashirakon/music/views/BreadCrumbLayout.java
	app/src/main/java/io/github/muntashirakon/music/views/CircularImageView.java
	app/src/main/java/io/github/muntashirakon/music/views/ContributorsView.java
	app/src/main/java/io/github/muntashirakon/music/views/NetworkImageView.java
	app/src/main/java/io/github/muntashirakon/music/views/SeekArc.java
	app/src/main/res/layout-land/fragment_home.xml
	app/src/main/res/layout-xlarge-land/fragment_blur.xml
	app/src/main/res/layout/activity_lock_screen.xml
	app/src/main/res/layout/activity_user_info.xml
	app/src/main/res/layout/fragment_banner_home.xml
	app/src/main/res/layout/fragment_classic_player.xml
	app/src/main/res/layout/fragment_folder.xml
	app/src/main/res/layout/fragment_home.xml
	app/src/main/res/layout/item_image.xml
	app/src/main/res/layout/sliding_music_panel_layout.xml
	app/src/main/res/navigation/now_playing.xml
This commit is contained in:
Muntashir Al-Islam 2020-10-15 19:16:23 +06:00
commit 3c0fc790d1
442 changed files with 18453 additions and 14559 deletions

View file

@ -40,7 +40,7 @@ Dark and Just Black for AMOLED displays. Select your favorite accent
color from a color palette. color from a color palette.
### 🏠 Home ### 🏠 Home
Where you can have your recently/top played artists, albums and Where you can view your recently/top played artists, albums and
favorite songs. No other music player has this feature. favorite songs. No other music player has this feature.
### 📦 Included Features ### 📦 Included Features
@ -49,33 +49,32 @@ favorite songs. No other music player has this feature.
- Driving Mode - Driving Mode
- Headset/Bluetooth support - Headset/Bluetooth support
- Music duration filter - Music duration filter
- Folder support - Play song by folder - Folder support - Play songs by folder
- Gapless playback - Gapless playback
- Volume controls - Volume controls
- Carousel effect for an album cover - Carousel effect for album covers
- Home screen widgets - Home screen widgets
- Lock screen playback controls - Lock screen playback controls
- Lyrics screen (download and sync with music) - Lyrics screen (download and sync with music)
- Sleep Timer - Sleep timer
- Easy drag to sort playlist & play queue - Easy drag to sort playlist & play queue
- Tag editor - Tag editor
- Create, edit and import playlists - Create, edit and import playlists
- Playing queue with reorder - Playing queue with reorder
- User profile - User profile
- 30 Languages support - 30+ languages support
- Browse and play your music by songs, albums, artists, playlists and - Browse and play your music by songs, albums, artists, playlists and
genre genre
- Smart Auto Playlists - Recently played, most played and history - Smart Auto Playlists - Recently played, most played and history
- Build your own playlist on the go - Build your playlist on the go
We are trying our best to bring you the best user experience. The app is regulary being updated for bug fixes and new features. We are trying our best to bring you the best user experience. The app is regularly being updated for bug fixes and new features.
### 🗂️ License ### 🗂️ License
Metro is released under the GNU General Public License v3.0 Metro is released under the GNU General Public License v3.0
(GPLv3), which can be found here: [License](LICENSE.md) (GPLv3), which can be found [here](LICENSE.md)
>Please note: Retro Music player is an offline music player app. It > Please note: Metro is an offline music player app. It doesn't support music downloading or online music streaming.
>doesn't support music downloading or online music streaming.

View file

@ -6,7 +6,7 @@ apply plugin: "androidx.navigation.safeargs.kotlin"
android { android {
compileSdkVersion 29 compileSdkVersion 29
buildToolsVersion = '30.0.1' buildToolsVersion = '30.0.2'
defaultConfig { defaultConfig {
minSdkVersion 21 minSdkVersion 21
@ -16,8 +16,8 @@ android {
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
applicationId 'io.github.muntashirakon.Music' applicationId 'io.github.muntashirakon.Music'
versionCode 10445 versionCode 10503
versionName '3.5.11' versionName '4.0.010'
multiDexEnabled true multiDexEnabled true
} }
@ -134,4 +134,6 @@ dependencies {
implementation 'me.jorgecastillo:androidcolorx:0.2.0' implementation 'me.jorgecastillo:androidcolorx:0.2.0'
implementation 'org.jsoup:jsoup:1.11.1' implementation 'org.jsoup:jsoup:1.11.1'
debugImplementation 'com.amitshekhar.android:debug-db:1.0.6' debugImplementation 'com.amitshekhar.android:debug-db:1.0.6'
} }
apply from: '../spotless.gradle'

View file

@ -26,13 +26,11 @@
-dontwarn java.lang.invoke.* -dontwarn java.lang.invoke.*
-dontwarn **$$Lambda$* -dontwarn **$$Lambda$*
-dontwarn javax.annotation.**
# RetroFit # RetroFit
-dontwarn retrofit.** -dontwarn retrofit.**
-keep class retrofit.** { *; } -keep class retrofit.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-dontwarn javax.annotation.**
# Glide # Glide
-keep public class * implements com.bumptech.glide.module.GlideModule -keep public class * implements com.bumptech.glide.module.GlideModule
@ -41,14 +39,24 @@
public *; public *;
} }
# OkHttp
-keepattributes Signature
-keepattributes *Annotation*
-keep interface com.squareup.okhttp3.** { *; }
-dontwarn com.squareup.okhttp3.**
-dontwarn #-dontwarn
-ignorewarnings #-ignorewarnings
-dontshrink
-dontobfuscate
#-dontwarn android.support.v8.renderscript.* -dontwarn org.jaudiotagger.**
#-keepclassmembers class android.support.v8.renderscript.RenderScript { -keep class org.jaudiotagger.** { *; }
# native *** rsn*(...);
# native *** n*(...);
#}
#-keep class org.jaudiotagger.** { *; } -keepclassmembers enum * { *; }
-keepattributes *Annotation*, Signature, Exception
-keepnames class androidx.navigation.fragment.NavHostFragment
-keepnames class code.name.monkey.retromusic.model.Home
-keep class * extends androidx.fragment.app.Fragment{}
-keepnames class * extends android.os.Parcelable
-keepnames class * extends java.io.Serializable

View file

@ -88,4 +88,9 @@
<item name="android:letterSpacing">0.0125</item> <item name="android:letterSpacing">0.0125</item>
<item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:textColor">?android:attr/textColorPrimary</item>
</style> </style>
<style name="circleImageView" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">5%</item>
</style>
</resources> </resources>

View file

@ -5,6 +5,7 @@
android:installLocation="auto"> android:installLocation="auto">
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@ -116,11 +117,7 @@
<activity android:name=".activities.ShareInstagramStory" /> <activity android:name=".activities.ShareInstagramStory" />
<activity android:name=".activities.DriveModeActivity" /> <activity android:name=".activities.DriveModeActivity" />
<activity android:name=".activities.PermissionActivity" /> <activity android:name=".activities.PermissionActivity" />
<activity android:name=".activities.LockScreenActivity" />
<activity
android:name=".activities.LockScreenActivity"
android:noHistory="true"
android:showOnLockScreen="true" />
<activity <activity
android:name=".appshortcuts.AppShortcutLauncherActivity" android:name=".appshortcuts.AppShortcutLauncherActivity"

View file

@ -3,24 +3,30 @@
"name": "Hemanth Savarala", "name": "Hemanth Savarala",
"summary": "Lead Developer & Designer", "summary": "Lead Developer & Designer",
"link": "https://github.com/h4h13", "link": "https://github.com/h4h13",
"profile_image": "https://i.imgur.com/AoVs9oj.jpg" "image": "https://i.imgur.com/AoVs9oj.jpg"
}, },
{ {
"name": "Lennart Glamann", "name": "Lennart Glamann",
"summary": "Play Store banner and Images", "summary": "Play Store Banner & Images",
"link": "https://t.me/FlixbusLennart", "link": "https://t.me/FlixbusLennart",
"profile_image": "https://i.imgur.com/Q5Nsx1R.jpg" "image": "https://i.imgur.com/Q5Nsx1R.jpg"
}, },
{ {
"name": "Daksh P. Jain", "name": "Daksh P. Jain",
"summary": "Support Representative & Moderator", "summary": "Support Representative & Moderator",
"link": "https://daksh.eu.org", "link": "https://daksh.eu.org",
"profile_image": "https://i.imgur.com/fnYpg65.jpg" "image": "https://i.imgur.com/fnYpg65.jpg"
}, },
{ {
"name": "Milind Goel", "name": "Milind Goel",
"summary": "Support Representative & Moderator", "summary": "Support Representative & Moderator",
"link": "https://t.me/MilindGoel15", "link": "https://t.me/MilindGoel15",
"profile_image": "https://i.imgur.com/Bz4De21_d.jpg" "image": "https://i.imgur.com/Bz4De21_d.jpg"
},
{
"name": "Haythem Gataa",
"summary": "App Logo Designer",
"link": "https://dribbble.com/haythemgataa",
"image": "https://i.imgur.com/g5RuIZq.jpg"
} }
] ]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before After
Before After

View file

@ -1,17 +1,16 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
package io.github.muntashirakon.music package io.github.muntashirakon.music
import androidx.multidex.MultiDexApplication import androidx.multidex.MultiDexApplication

View file

@ -1,17 +1,16 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
package io.github.muntashirakon.music package io.github.muntashirakon.music
import android.provider.BaseColumns import android.provider.BaseColumns
@ -46,9 +45,9 @@ object Constants {
MediaStore.Audio.AudioColumns.ALBUM_ID, // 7 MediaStore.Audio.AudioColumns.ALBUM_ID, // 7
MediaStore.Audio.AudioColumns.ALBUM, // 8 MediaStore.Audio.AudioColumns.ALBUM, // 8
MediaStore.Audio.AudioColumns.ARTIST_ID, // 9 MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
MediaStore.Audio.AudioColumns.ARTIST,// 10 MediaStore.Audio.AudioColumns.ARTIST, // 10
MediaStore.Audio.AudioColumns.COMPOSER,// 11 MediaStore.Audio.AudioColumns.COMPOSER, // 11
"album_artist"//12 "album_artist" // 12
) )
const val NUMBER_OF_TOP_TRACKS = 99 const val NUMBER_OF_TOP_TRACKS = 99
} }
@ -76,6 +75,8 @@ const val BLURRED_ALBUM_ART = "blurred_album_art"
const val NEW_BLUR_AMOUNT = "new_blur_amount" const val NEW_BLUR_AMOUNT = "new_blur_amount"
const val TOGGLE_HEADSET = "toggle_headset" const val TOGGLE_HEADSET = "toggle_headset"
const val GENERAL_THEME = "general_theme" const val GENERAL_THEME = "general_theme"
const val ACCENT_COLOR = "accent_color"
const val SHOULD_COLOR_APP_SHORTCUTS = "should_color_app_shortcuts"
const val CIRCULAR_ALBUM_ART = "circular_album_art" const val CIRCULAR_ALBUM_ART = "circular_album_art"
const val USER_NAME = "user_name" const val USER_NAME = "user_name"
const val TOGGLE_FULL_SCREEN = "toggle_full_screen" const val TOGGLE_FULL_SCREEN = "toggle_full_screen"
@ -87,6 +88,7 @@ const val BANNER_IMAGE_PATH = "banner_image_path"
const val ADAPTIVE_COLOR_APP = "adaptive_color_app" const val ADAPTIVE_COLOR_APP = "adaptive_color_app"
const val TOGGLE_SEPARATE_LINE = "toggle_separate_line" const val TOGGLE_SEPARATE_LINE = "toggle_separate_line"
const val HOME_ARTIST_GRID_STYLE = "home_artist_grid_style" const val HOME_ARTIST_GRID_STYLE = "home_artist_grid_style"
const val HOME_ALBUM_GRID_STYLE = "home_album_grid_style"
const val TOGGLE_ADD_CONTROLS = "toggle_add_controls" const val TOGGLE_ADD_CONTROLS = "toggle_add_controls"
const val ALBUM_COVER_STYLE = "album_cover_style_id" const val ALBUM_COVER_STYLE = "album_cover_style_id"
const val ALBUM_COVER_TRANSFORM = "album_cover_transform" const val ALBUM_COVER_TRANSFORM = "album_cover_transform"
@ -105,6 +107,7 @@ const val INITIALIZED_BLACKLIST = "initialized_blacklist"
const val ARTIST_SORT_ORDER = "artist_sort_order" const val ARTIST_SORT_ORDER = "artist_sort_order"
const val ARTIST_ALBUM_SORT_ORDER = "artist_album_sort_order" const val ARTIST_ALBUM_SORT_ORDER = "artist_album_sort_order"
const val ALBUM_SORT_ORDER = "album_sort_order" const val ALBUM_SORT_ORDER = "album_sort_order"
const val PLAYLIST_SORT_ORDER = "playlist_sort_order"
const val ALBUM_SONG_SORT_ORDER = "album_song_sort_order" const val ALBUM_SONG_SORT_ORDER = "album_song_sort_order"
const val ARTIST_SONG_SORT_ORDER = "artist_song_sort_order" const val ARTIST_SONG_SORT_ORDER = "artist_song_sort_order"
const val ALBUM_GRID_SIZE = "album_grid_size" const val ALBUM_GRID_SIZE = "album_grid_size"
@ -123,9 +126,11 @@ const val AUTO_DOWNLOAD_IMAGES_POLICY = "auto_download_images_policy"
const val START_DIRECTORY = "start_directory" const val START_DIRECTORY = "start_directory"
const val RECENTLY_PLAYED_CUTOFF = "recently_played_interval" const val RECENTLY_PLAYED_CUTOFF = "recently_played_interval"
const val LOCK_SCREEN = "lock_screen" const val LOCK_SCREEN = "lock_screen"
const val ALBUM_ARTISTS_ONLY = "album_artists_only"
const val ALBUM_DETAIL_SONG_SORT_ORDER = "album_detail_song_sort_order" const val ALBUM_DETAIL_SONG_SORT_ORDER = "album_detail_song_sort_order"
const val LYRICS_OPTIONS = "lyrics_tab_position" const val LYRICS_OPTIONS = "lyrics_tab_position"
const val CHOOSE_EQUALIZER = "choose_equalizer" const val CHOOSE_EQUALIZER = "choose_equalizer"
const val EQUALIZER = "equalizer"
const val TOGGLE_SHUFFLE = "toggle_shuffle" const val TOGGLE_SHUFFLE = "toggle_shuffle"
const val SONG_GRID_STYLE = "song_grid_style" const val SONG_GRID_STYLE = "song_grid_style"
const val PAUSE_ON_ZERO_VOLUME = "pause_on_zero_volume" const val PAUSE_ON_ZERO_VOLUME = "pause_on_zero_volume"

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music package io.github.muntashirakon.music
import androidx.annotation.IntDef import androidx.annotation.IntDef
@ -25,4 +39,4 @@ const val GENRES = 6
const val PLAYLISTS = 7 const val PLAYLISTS = 7
const val HISTORY_PLAYLIST = 8 const val HISTORY_PLAYLIST = 8
const val LAST_ADDED_PLAYLIST = 9 const val LAST_ADDED_PLAYLIST = 9
const val TOP_PLAYED_PLAYLIST = 10 const val TOP_PLAYED_PLAYLIST = 10

View file

@ -5,39 +5,37 @@ import android.content.ContextWrapper;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.LocaleList; import android.os.LocaleList;
import java.util.Locale;
import code.name.monkey.appthemehelper.util.VersionUtils; import code.name.monkey.appthemehelper.util.VersionUtils;
import java.util.Locale;
public class LanguageContextWrapper extends ContextWrapper { public class LanguageContextWrapper extends ContextWrapper {
public LanguageContextWrapper(Context base) { public LanguageContextWrapper(Context base) {
super(base); super(base);
}
public static LanguageContextWrapper wrap(Context context, Locale newLocale) {
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
if (VersionUtils.INSTANCE.hasNougatMR()) {
configuration.setLocale(newLocale);
LocaleList localeList = new LocaleList(newLocale);
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
context = context.createConfigurationContext(configuration);
} else if (VersionUtils.INSTANCE.hasLollipop()) {
configuration.setLocale(newLocale);
context = context.createConfigurationContext(configuration);
} else {
configuration.locale = newLocale;
res.updateConfiguration(configuration, res.getDisplayMetrics());
} }
public static LanguageContextWrapper wrap(Context context, Locale newLocale) { return new LanguageContextWrapper(context);
Resources res = context.getResources(); }
Configuration configuration = res.getConfiguration(); }
if (VersionUtils.INSTANCE.hasNougatMR()) {
configuration.setLocale(newLocale);
LocaleList localeList = new LocaleList(newLocale);
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
context = context.createConfigurationContext(configuration);
} else if (VersionUtils.INSTANCE.hasLollipop()) {
configuration.setLocale(newLocale);
context = context.createConfigurationContext(configuration);
} else {
configuration.locale = newLocale;
res.updateConfiguration(configuration, res.getDisplayMetrics());
}
return new LanguageContextWrapper(context);
}
}

View file

@ -12,9 +12,11 @@ import io.github.muntashirakon.music.fragments.albums.AlbumDetailsViewModel
import io.github.muntashirakon.music.fragments.artists.ArtistDetailsViewModel import io.github.muntashirakon.music.fragments.artists.ArtistDetailsViewModel
import io.github.muntashirakon.music.fragments.genres.GenreDetailsViewModel import io.github.muntashirakon.music.fragments.genres.GenreDetailsViewModel
import io.github.muntashirakon.music.fragments.playlists.PlaylistDetailsViewModel import io.github.muntashirakon.music.fragments.playlists.PlaylistDetailsViewModel
import io.github.muntashirakon.music.fragments.search.SearchViewModel
import io.github.muntashirakon.music.model.Genre import io.github.muntashirakon.music.model.Genre
import io.github.muntashirakon.music.network.* import io.github.muntashirakon.music.network.provideDefaultCache
import io.github.muntashirakon.music.network.provideLastFmRest
import io.github.muntashirakon.music.network.provideLastFmRetrofit
import io.github.muntashirakon.music.network.provideOkHttp
import io.github.muntashirakon.music.repository.* import io.github.muntashirakon.music.repository.*
import io.github.muntashirakon.music.util.FilePathUtil import io.github.muntashirakon.music.util.FilePathUtil
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
@ -36,15 +38,9 @@ val networkModule = module {
single { single {
provideLastFmRetrofit(get()) provideLastFmRetrofit(get())
} }
single {
provideDeezerRest(get())
}
single { single {
provideLastFmRest(get()) provideLastFmRest(get())
} }
single {
provideLyrics(get())
}
} }
private val roomModule = module { private val roomModule = module {
@ -93,7 +89,6 @@ private val mainModule = module {
single { single {
androidContext().contentResolver androidContext().contentResolver
} }
} }
private val dataModule = module { private val dataModule = module {
single { single {
@ -109,7 +104,7 @@ private val dataModule = module {
get(), get(),
get(), get(),
get(), get(),
get() get(),
) )
} bind Repository::class } bind Repository::class
@ -154,6 +149,9 @@ private val dataModule = module {
get() get()
) )
} }
single {
RealLocalDataRepository(get())
} bind LocalDataRepository::class
} }
private val viewModules = module { private val viewModules = module {
@ -189,10 +187,6 @@ private val viewModules = module {
genre genre
) )
} }
viewModel {
SearchViewModel(get())
}
} }
val appModules = listOf(mainModule, dataModule, viewModules, networkModule, roomModule) val appModules = listOf(mainModule, dataModule, viewModules, networkModule, roomModule)

View file

@ -4,36 +4,32 @@ import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetBehavior;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class RetroBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> { public class RetroBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {
private static final String TAG = "RetroBottomSheetBehavior"; private static final String TAG = "RetroBottomSheetBehavior";
private boolean allowDragging = true; private boolean allowDragging = true;
public RetroBottomSheetBehavior() { public RetroBottomSheetBehavior() {}
public RetroBottomSheetBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setAllowDragging(boolean allowDragging) {
this.allowDragging = allowDragging;
}
@Override
public boolean onInterceptTouchEvent(
@NotNull CoordinatorLayout parent, @NotNull V child, @NotNull MotionEvent event) {
if (!allowDragging) {
return false;
} }
return super.onInterceptTouchEvent(parent, child, event);
public RetroBottomSheetBehavior(Context context, AttributeSet attrs) { }
super(context, attrs); }
}
public void setAllowDragging(boolean allowDragging) {
this.allowDragging = allowDragging;
}
@Override
public boolean onInterceptTouchEvent(@NotNull CoordinatorLayout parent, @NotNull V child, @NotNull MotionEvent event) {
if (!allowDragging) {
return false;
}
return super.onInterceptTouchEvent(parent, child, event);
}
}

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2020 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.activities package io.github.muntashirakon.music.activities
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
@ -234,4 +234,4 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong()) songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong()) songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
} }
} }

View file

@ -18,82 +18,86 @@ import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.view.MenuItem; import android.view.MenuItem;
import android.webkit.WebView; import android.webkit.WebView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import code.name.monkey.appthemehelper.ThemeStore; import code.name.monkey.appthemehelper.ThemeStore;
import code.name.monkey.appthemehelper.util.ATHUtil; import code.name.monkey.appthemehelper.util.ATHUtil;
import code.name.monkey.appthemehelper.util.ColorUtil; import code.name.monkey.appthemehelper.util.ColorUtil;
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper;
import io.github.muntashirakon.music.R; import io.github.muntashirakon.music.R;
import io.github.muntashirakon.music.activities.base.AbsBaseActivity; import io.github.muntashirakon.music.activities.base.AbsBaseActivity;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import org.jetbrains.annotations.Nullable;
/** /** Created by hemanths on 2019-09-27. */
* Created by hemanths on 2019-09-27.
*/
public class LicenseActivity extends AbsBaseActivity { public class LicenseActivity extends AbsBaseActivity {
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
setDrawUnderStatusBar(); setDrawUnderStatusBar();
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_license); setContentView(R.layout.activity_license);
setStatusbarColorAuto(); setStatusbarColorAuto();
setNavigationbarColorAuto(); setNavigationbarColorAuto();
setLightNavigationBar(true); setLightNavigationBar(true);
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
ToolbarContentTintHelper.colorBackButton(toolbar); ToolbarContentTintHelper.colorBackButton(toolbar);
toolbar.setBackgroundColor(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface)); toolbar.setBackgroundColor(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface));
WebView webView = findViewById(R.id.license); WebView webView = findViewById(R.id.license);
try { try {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
InputStream json = getAssets().open("oldindex.html"); InputStream json = getAssets().open("oldindex.html");
BufferedReader in = new BufferedReader(new InputStreamReader(json, StandardCharsets.UTF_8)); BufferedReader in = new BufferedReader(new InputStreamReader(json, StandardCharsets.UTF_8));
String str; String str;
while ((str = in.readLine()) != null) { while ((str = in.readLine()) != null) {
buf.append(str); buf.append(str);
} }
in.close(); in.close();
// Inject color values for WebView body background and links // Inject color values for WebView body background and links
final boolean isDark = ATHUtil.INSTANCE.isWindowBackgroundDark(this); final boolean isDark = ATHUtil.INSTANCE.isWindowBackgroundDark(this);
final String backgroundColor = colorToCSS(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface, final String backgroundColor =
Color.parseColor(isDark ? "#424242" : "#ffffff"))); colorToCSS(
final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000")); ATHUtil.INSTANCE.resolveColor(
final String changeLog = buf.toString() this, R.attr.colorSurface, Color.parseColor(isDark ? "#424242" : "#ffffff")));
.replace("{style-placeholder}", final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000"));
String.format("body { background-color: %s; color: %s; }", backgroundColor, contentColor)) final String changeLog =
.replace("{link-color}", colorToCSS(ThemeStore.Companion.accentColor(this))) buf.toString()
.replace("{link-color-active}", .replace(
colorToCSS(ColorUtil.INSTANCE.lightenColor(ThemeStore.Companion.accentColor(this)))); "{style-placeholder}",
String.format(
webView.loadData(changeLog, "text/html", "UTF-8"); "body { background-color: %s; color: %s; }", backgroundColor, contentColor))
} catch (Throwable e) { .replace("{link-color}", colorToCSS(ThemeStore.Companion.accentColor(this)))
webView.loadData("<h1>Unable to load</h1><p>" + e.getLocalizedMessage() + "</p>", "text/html", "UTF-8"); .replace(
} "{link-color-active}",
colorToCSS(
ColorUtil.INSTANCE.lightenColor(ThemeStore.Companion.accentColor(this))));
webView.loadData(changeLog, "text/html", "UTF-8");
} catch (Throwable e) {
webView.loadData(
"<h1>Unable to load</h1><p>" + e.getLocalizedMessage() + "</p>", "text/html", "UTF-8");
} }
}
@Override @Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) { public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) { if (item.getItemId() == android.R.id.home) {
onBackPressed(); onBackPressed();
return true; return true;
}
return super.onOptionsItemSelected(item);
} }
return super.onOptionsItemSelected(item);
}
private String colorToCSS(int color) { private String colorToCSS(int color) {
return String.format("rgb(%d, %d, %d)", Color.red(color), Color.green(color), return String.format(
Color.blue(color)); // on API 29, WebView doesn't load with hex colors "rgb(%d, %d, %d)",
} Color.red(color),
Color.green(color),
Color.blue(color)); // on API 29, WebView doesn't load with hex colors
}
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities package io.github.muntashirakon.music.activities
import android.app.KeyguardManager import android.app.KeyguardManager
@ -9,7 +23,8 @@ import android.view.WindowManager
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.activities.base.AbsMusicServiceActivity import io.github.muntashirakon.music.activities.base.AbsMusicServiceActivity
import io.github.muntashirakon.music.fragments.player.lockscreen.LockScreenPlayerControlsFragment import io.github.muntashirakon.music.extensions.whichFragment
import io.github.muntashirakon.music.fragments.player.lockscreen.LockScreenControlsFragment
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import io.github.muntashirakon.music.glide.SongGlideRequest import io.github.muntashirakon.music.glide.SongGlideRequest
import io.github.muntashirakon.music.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
@ -22,21 +37,12 @@ import com.r0adkll.slidr.model.SlidrPosition
import kotlinx.android.synthetic.main.activity_lock_screen.* import kotlinx.android.synthetic.main.activity_lock_screen.*
class LockScreenActivity : AbsMusicServiceActivity() { class LockScreenActivity : AbsMusicServiceActivity() {
private var fragment: LockScreenPlayerControlsFragment? = null private var fragment: LockScreenControlsFragment? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar() setDrawUnderStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { lockScreenInit()
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
this.window.addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
)
}
setContentView(R.layout.activity_lock_screen) setContentView(R.layout.activity_lock_screen)
hideStatusBar() hideStatusBar()
setStatusbarColorAuto() setStatusbarColorAuto()
@ -67,8 +73,7 @@ class LockScreenActivity : AbsMusicServiceActivity() {
Slidr.attach(this, config) Slidr.attach(this, config)
fragment = fragment = whichFragment<LockScreenControlsFragment>(R.id.playback_controls_fragment)
supportFragmentManager.findFragmentById(R.id.playback_controls_fragment) as LockScreenPlayerControlsFragment?
findViewById<View>(R.id.slide).apply { findViewById<View>(R.id.slide).apply {
translationY = 100f translationY = 100f
@ -77,6 +82,19 @@ class LockScreenActivity : AbsMusicServiceActivity() {
} }
} }
private fun lockScreenInit() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true)
val keyguardManager: KeyguardManager = getSystemService(KeyguardManager::class.java)
keyguardManager.requestDismissKeyguard(this, null)
} else {
this.window.addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
)
}
}
override fun onPlayingMetaChanged() { override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged() super.onPlayingMetaChanged()
updateSongs() updateSongs()
@ -97,4 +115,4 @@ class LockScreenActivity : AbsMusicServiceActivity() {
} }
}) })
} }
} }

View file

@ -1,9 +1,25 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities package io.github.muntashirakon.music.activities
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.WindowManager import android.view.WindowManager
import androidx.core.view.ViewCompat
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
@ -15,6 +31,10 @@ import io.github.muntashirakon.music.lyrics.LrcView
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.LyricUtil import io.github.muntashirakon.music.util.LyricUtil
import io.github.muntashirakon.music.util.RetroUtil import io.github.muntashirakon.music.util.RetroUtil
import com.google.android.material.color.MaterialColors
import com.google.android.material.transition.platform.MaterialArcMotion
import com.google.android.material.transition.platform.MaterialContainerTransform
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
import kotlinx.android.synthetic.main.activity_lyrics.* import kotlinx.android.synthetic.main.activity_lyrics.*
class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.Callback { class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.Callback {
@ -31,9 +51,20 @@ class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.
return baseUrl return baseUrl
} }
private fun buildContainerTransform(): MaterialContainerTransform {
val transform = MaterialContainerTransform()
transform.setAllContainerColors(
MaterialColors.getColor(findViewById(R.id.container), R.attr.colorSurface)
)
transform.addTarget(R.id.container)
transform.duration = 300
return transform
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_lyrics) setContentView(R.layout.activity_lyrics)
ViewCompat.setTransitionName(container, "lyrics")
setStatusbarColorAuto() setStatusbarColorAuto()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setNavigationbarColorAuto() setNavigationbarColorAuto()
@ -122,4 +153,4 @@ class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities package io.github.muntashirakon.music.activities
import android.content.Intent import android.content.Intent
@ -8,17 +22,45 @@ import android.os.Bundle
import android.provider.MediaStore import android.provider.MediaStore
import android.view.View import android.view.View
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import io.github.muntashirakon.music.* import androidx.navigation.ui.NavigationUI
import io.github.muntashirakon.music.ADAPTIVE_COLOR_APP
import io.github.muntashirakon.music.ALBUM_COVER_STYLE
import io.github.muntashirakon.music.ALBUM_COVER_TRANSFORM
import io.github.muntashirakon.music.BANNER_IMAGE_PATH
import io.github.muntashirakon.music.BLACK_THEME
import io.github.muntashirakon.music.CAROUSEL_EFFECT
import io.github.muntashirakon.music.CIRCULAR_ALBUM_ART
import io.github.muntashirakon.music.DESATURATED_COLOR
import io.github.muntashirakon.music.EXTRA_SONG_INFO
import io.github.muntashirakon.music.GENERAL_THEME
import io.github.muntashirakon.music.HOME_ARTIST_GRID_STYLE
import io.github.muntashirakon.music.KEEP_SCREEN_ON
import io.github.muntashirakon.music.LANGUAGE_NAME
import io.github.muntashirakon.music.LIBRARY_CATEGORIES
import io.github.muntashirakon.music.NOW_PLAYING_SCREEN_ID
import io.github.muntashirakon.music.PROFILE_IMAGE_PATH
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.ROUND_CORNERS
import io.github.muntashirakon.music.TAB_TEXT_MODE
import io.github.muntashirakon.music.TOGGLE_ADD_CONTROLS
import io.github.muntashirakon.music.TOGGLE_FULL_SCREEN
import io.github.muntashirakon.music.TOGGLE_GENRE
import io.github.muntashirakon.music.TOGGLE_HOME_BANNER
import io.github.muntashirakon.music.TOGGLE_SEPARATE_LINE
import io.github.muntashirakon.music.TOGGLE_VOLUME
import io.github.muntashirakon.music.USER_NAME
import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
import io.github.muntashirakon.music.extensions.findNavController import io.github.muntashirakon.music.extensions.findNavController
import io.github.muntashirakon.music.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.helper.SearchQueryHelper.getSongs import io.github.muntashirakon.music.helper.SearchQueryHelper.getSongs
import io.github.muntashirakon.music.model.CategoryInfo
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.repository.PlaylistSongsLoader import io.github.muntashirakon.music.repository.PlaylistSongsLoader
import io.github.muntashirakon.music.service.MusicService import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.android.ext.android.get
class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener { class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener {
companion object { companion object {
@ -28,21 +70,43 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
} }
override fun createContentView(): View { override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_main_content) return wrapSlidingMusicPanel()
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar() setDrawUnderStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (!hasPermissions()) {
findNavController(R.id.fragment_container).navigate(R.id.permissionFragment)
}
setStatusbarColorAuto() setStatusbarColorAuto()
setNavigationbarColorAuto() setNavigationbarColorAuto()
setLightNavigationBar(true) setLightNavigationBar(true)
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
hideStatusBar() hideStatusBar()
updateTabs() updateTabs()
// NavigationUI.setupWithNavController(getBottomNavigationView(), findNavController(R.id.fragment_container))
setupNavigationController()
if (!hasPermissions()) {
findNavController(R.id.fragment_container).navigate(R.id.permissionFragment)
}
showPromotionalDialog()
}
private fun showPromotionalDialog() {
}
private fun setupNavigationController() {
val navController = findNavController(R.id.fragment_container)
val navInflater = navController.navInflater
val navGraph = navInflater.inflate(R.navigation.main_graph)
val categoryInfo: CategoryInfo = PreferenceUtil.libraryCategory.first { it.visible }
if (categoryInfo.visible) {
navGraph.startDestination = categoryInfo.category.id
}
navController.graph = navGraph
NavigationUI.setupWithNavController(getBottomNavigationView(), navController)
} }
override fun onSupportNavigateUp(): Boolean = override fun onSupportNavigateUp(): Boolean =
@ -98,8 +162,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
val id = parseLongFromIntent(intent, "playlistId", "playlist") val id = parseLongFromIntent(intent, "playlistId", "playlist")
if (id >= 0L) { if (id >= 0L) {
val position: Int = intent.getIntExtra("position", 0) val position: Int = intent.getIntExtra("position", 0)
val songs: List<Song> = val songs: List<Song> = PlaylistSongsLoader.getPlaylistSongList(get(), id)
PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id)
MusicPlayerRemote.openQueue(songs, position, true) MusicPlayerRemote.openQueue(songs, position, true)
handled = true handled = true
} }
@ -107,8 +170,9 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
val id = parseLongFromIntent(intent, "albumId", "album") val id = parseLongFromIntent(intent, "albumId", "album")
if (id >= 0L) { if (id >= 0L) {
val position: Int = intent.getIntExtra("position", 0) val position: Int = intent.getIntExtra("position", 0)
val songs = libraryViewModel.albumById(id).songs
MusicPlayerRemote.openQueue( MusicPlayerRemote.openQueue(
libraryViewModel.albumById(id).songs, songs,
position, position,
true true
) )
@ -118,8 +182,9 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
val id = parseLongFromIntent(intent, "artistId", "artist") val id = parseLongFromIntent(intent, "artistId", "artist")
if (id >= 0L) { if (id >= 0L) {
val position: Int = intent.getIntExtra("position", 0) val position: Int = intent.getIntExtra("position", 0)
val songs: List<Song> = libraryViewModel.artistById(id).songs
MusicPlayerRemote.openQueue( MusicPlayerRemote.openQueue(
libraryViewModel.artistById(id).songs, songs,
position, position,
true true
) )
@ -130,11 +195,11 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
setIntent(Intent()) setIntent(Intent())
} }
} }
} }
private fun parseLongFromIntent( private fun parseLongFromIntent(
intent: Intent, longKey: String, intent: Intent,
longKey: String,
stringKey: String stringKey: String
): Long { ): Long {
var id = intent.getLongExtra(longKey, -1) var id = intent.getLongExtra(longKey, -1)
@ -150,4 +215,4 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
} }
return id return id
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities package io.github.muntashirakon.music.activities
import android.content.Intent import android.content.Intent
@ -13,7 +27,6 @@ import io.github.muntashirakon.music.extensions.show
import io.github.muntashirakon.music.util.RingtoneManager import io.github.muntashirakon.music.util.RingtoneManager
import kotlinx.android.synthetic.main.activity_permission.* import kotlinx.android.synthetic.main.activity_permission.*
class PermissionActivity : AbsMusicServiceActivity() { class PermissionActivity : AbsMusicServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -37,7 +50,7 @@ class PermissionActivity : AbsMusicServiceActivity() {
} }
finish.accentBackgroundColor() finish.accentBackgroundColor()
finish.setOnClickListener { finish.setOnClickListener {
if (hasPermissions() && !RingtoneManager.requiresDialog(this)) { if (hasPermissions()) {
startActivity( startActivity(
Intent(this, MainActivity::class.java).addFlags( Intent(this, MainActivity::class.java).addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_NEW_TASK or
@ -56,4 +69,4 @@ class PermissionActivity : AbsMusicServiceActivity() {
) )
appNameText.text = appName appNameText.text = appName
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities package io.github.muntashirakon.music.activities
import android.content.res.ColorStateList import android.content.res.ColorStateList

View file

@ -1,8 +1,23 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities package io.github.muntashirakon.music.activities
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavDestination
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import com.afollestad.materialdialogs.color.ColorChooserDialog import com.afollestad.materialdialogs.color.ColorChooserDialog
@ -29,10 +44,26 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
applyToolbar(toolbar) applyToolbar(toolbar)
val navController: NavController = findNavController(R.id.contentFrame) val navController: NavController = findNavController(R.id.contentFrame)
navController.addOnDestinationChangedListener { _, _, _ -> navController.addOnDestinationChangedListener { _, _, _ ->
toolbar.title = navController.currentDestination?.label toolbar.title = navController.currentDestination?.let { getStringFromDestination(it) }
} }
} }
private fun getStringFromDestination(currentDestination: NavDestination): String {
val idRes = when (currentDestination.id) {
R.id.mainSettingsFragment -> R.string.action_settings
R.id.audioSettings -> R.string.pref_header_audio
R.id.imageSettingFragment -> R.string.pref_header_images
R.id.notificationSettingsFragment -> R.string.notification
R.id.nowPlayingSettingsFragment -> R.string.now_playing
R.id.otherSettingsFragment -> R.string.others
R.id.personalizeSettingsFragment -> R.string.personalize
R.id.themeSettingsFragment -> R.string.general_settings_title
R.id.aboutActivity -> R.string.action_about
else -> R.id.action_settings
}
return getString(idRes)
}
override fun onSupportNavigateUp(): Boolean { override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.contentFrame).navigateUp() || super.onSupportNavigateUp() return findNavController(R.id.contentFrame).navigateUp() || super.onSupportNavigateUp()
} }
@ -49,7 +80,6 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
} }
override fun onColorChooserDismissed(dialog: ColorChooserDialog) { override fun onColorChooserDismissed(dialog: ColorChooserDialog) {
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -58,4 +88,4 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
} }

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2020 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.activities package io.github.muntashirakon.music.activities
import android.content.res.ColorStateList import android.content.res.ColorStateList

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities package io.github.muntashirakon.music.activities
import android.app.Activity import android.app.Activity
@ -11,12 +25,6 @@ import android.view.MenuItem
import android.widget.Toast import android.widget.Toast
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.MaterialValueHelper
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.github.dhaval2404.imagepicker.ImagePicker
import com.github.dhaval2404.imagepicker.constant.ImageProvider
import io.github.muntashirakon.music.Constants.USER_BANNER import io.github.muntashirakon.music.Constants.USER_BANNER
import io.github.muntashirakon.music.Constants.USER_PROFILE import io.github.muntashirakon.music.Constants.USER_PROFILE
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
@ -27,15 +35,21 @@ import io.github.muntashirakon.music.glide.ProfileBannerGlideRequest
import io.github.muntashirakon.music.glide.UserProfileGlideRequest import io.github.muntashirakon.music.glide.UserProfileGlideRequest
import io.github.muntashirakon.music.util.ImageUtil import io.github.muntashirakon.music.util.ImageUtil
import io.github.muntashirakon.music.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.github.dhaval2404.imagepicker.ImagePicker
import com.github.dhaval2404.imagepicker.constant.ImageProvider
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import kotlinx.android.synthetic.main.activity_user_info.* import kotlinx.android.synthetic.main.activity_user_info.*
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
class UserInfoActivity : AbsBaseActivity() { class UserInfoActivity : AbsBaseActivity() {
@ -55,7 +69,7 @@ class UserInfoActivity : AbsBaseActivity() {
pickNewPhoto() pickNewPhoto()
} }
bannerSelect.setOnClickListener { bannerImage.setOnClickListener {
selectBannerImage() selectBannerImage()
} }
@ -114,7 +128,6 @@ class UserInfoActivity : AbsBaseActivity() {
.start(PICK_IMAGE_REQUEST) .start(PICK_IMAGE_REQUEST)
} }
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == PICK_IMAGE_REQUEST) { if (resultCode == Activity.RESULT_OK && requestCode == PICK_IMAGE_REQUEST) {
@ -209,9 +222,8 @@ class UserInfoActivity : AbsBaseActivity() {
.into(userImage) .into(userImage)
} }
companion object { companion object {
private const val PICK_IMAGE_REQUEST = 9002 private const val PICK_IMAGE_REQUEST = 9002
private const val PICK_BANNER_REQUEST = 9004 private const val PICK_BANNER_REQUEST = 9004
} }
} }

View file

@ -1,23 +1,14 @@
package io.github.muntashirakon.music.activities; package io.github.muntashirakon.music.activities;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Color; import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.webkit.WebView; import android.webkit.WebView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import code.name.monkey.appthemehelper.ThemeStore; import code.name.monkey.appthemehelper.ThemeStore;
import code.name.monkey.appthemehelper.util.ATHUtil; import code.name.monkey.appthemehelper.util.ATHUtil;
import code.name.monkey.appthemehelper.util.ColorUtil; import code.name.monkey.appthemehelper.util.ColorUtil;
@ -26,65 +17,95 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper;
import io.github.muntashirakon.music.R; import io.github.muntashirakon.music.R;
import io.github.muntashirakon.music.activities.base.AbsBaseActivity; import io.github.muntashirakon.music.activities.base.AbsBaseActivity;
import io.github.muntashirakon.music.util.PreferenceUtil; import io.github.muntashirakon.music.util.PreferenceUtil;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
public class WhatsNewActivity extends AbsBaseActivity { public class WhatsNewActivity extends AbsBaseActivity {
private static String colorToCSS(int color) { private static String colorToCSS(int color) {
return String.format(Locale.getDefault(), "rgba(%d, %d, %d, %d)", Color.red(color), Color.green(color), return String.format(
Color.blue(color), Color.alpha(color)); // on API 29, WebView doesn't load with hex colors Locale.getDefault(),
"rgba(%d, %d, %d, %d)",
Color.red(color),
Color.green(color),
Color.blue(color),
Color.alpha(color)); // on API 29, WebView doesn't load with hex colors
}
private static void setChangelogRead(@NonNull Context context) {
try {
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
int currentVersion = pInfo.versionCode;
PreferenceUtil.INSTANCE.setLastVersion(currentVersion);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} }
}
private static void setChangelogRead(@NonNull Context context) { @Override
try { protected void onCreate(@Nullable Bundle savedInstanceState) {
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); setDrawUnderStatusBar();
int currentVersion = pInfo.versionCode; super.onCreate(savedInstanceState);
PreferenceUtil.INSTANCE.setLastVersion(currentVersion); setContentView(R.layout.activity_whats_new);
} catch (PackageManager.NameNotFoundException e) { setStatusbarColorAuto();
e.printStackTrace(); setNavigationbarColorAuto();
} setTaskDescriptionColorAuto();
WebView webView = findViewById(R.id.webView);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setBackgroundColor(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface));
toolbar.setNavigationOnClickListener(v -> onBackPressed());
ToolbarContentTintHelper.colorBackButton(toolbar);
try {
StringBuilder buf = new StringBuilder();
InputStream json = getAssets().open("retro-changelog.html");
BufferedReader in = new BufferedReader(new InputStreamReader(json, StandardCharsets.UTF_8));
String str;
while ((str = in.readLine()) != null) {
buf.append(str);
}
in.close();
// Inject color values for WebView body background and links
final boolean isDark = ATHUtil.INSTANCE.isWindowBackgroundDark(this);
final int accentColor = ThemeStore.Companion.accentColor(this);
final String backgroundColor =
colorToCSS(
ATHUtil.INSTANCE.resolveColor(
this, R.attr.colorSurface, Color.parseColor(isDark ? "#424242" : "#ffffff")));
final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000"));
final String textColor = colorToCSS(Color.parseColor(isDark ? "#60FFFFFF" : "#80000000"));
final String accentColorString = colorToCSS(ThemeStore.Companion.accentColor(this));
final String accentTextColor =
colorToCSS(
MaterialValueHelper.getPrimaryTextColor(
this, ColorUtil.INSTANCE.isColorLight(accentColor)));
final String changeLog =
buf.toString()
.replace(
"{style-placeholder}",
String.format(
"body { background-color: %s; color: %s; } li {color: %s;} .colorHeader {background-color: %s; color: %s;} .tag {color: %s;}",
backgroundColor,
contentColor,
textColor,
accentColorString,
accentTextColor,
accentColorString))
.replace("{link-color}", colorToCSS(ThemeStore.Companion.accentColor(this)))
.replace(
"{link-color-active}",
colorToCSS(
ColorUtil.INSTANCE.lightenColor(ThemeStore.Companion.accentColor(this))));
webView.loadData(changeLog, "text/html", "UTF-8");
} catch (Throwable e) {
webView.loadData(
"<h1>Unable to load</h1><p>" + e.getLocalizedMessage() + "</p>", "text/html", "UTF-8");
} }
setChangelogRead(this);
@Override }
protected void onCreate(@Nullable Bundle savedInstanceState) { }
setDrawUnderStatusBar();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_whats_new);
setStatusbarColorAuto();
setNavigationbarColorAuto();
setTaskDescriptionColorAuto();
WebView webView = findViewById(R.id.webView);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setBackgroundColor(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface));
toolbar.setNavigationOnClickListener(v -> onBackPressed());
ToolbarContentTintHelper.colorBackButton(toolbar);
try {
StringBuilder buf = new StringBuilder();
InputStream json = getAssets().open("retro-changelog.html");
BufferedReader in = new BufferedReader(new InputStreamReader(json, StandardCharsets.UTF_8));
String str;
while ((str = in.readLine()) != null) {
buf.append(str);
}
in.close();
// Inject color values for WebView body background and links
final boolean isDark = ATHUtil.INSTANCE.isWindowBackgroundDark(this);
final int accentColor = ThemeStore.Companion.accentColor(this);
final String backgroundColor = colorToCSS(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface, Color.parseColor(isDark ? "#424242" : "#ffffff")));
final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000"));
final String textColor = colorToCSS(Color.parseColor(isDark ? "#60FFFFFF" : "#80000000"));
final String accentColorString = colorToCSS(ThemeStore.Companion.accentColor(this));
final String accentTextColor = colorToCSS(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.INSTANCE.isColorLight(accentColor)));
final String changeLog = buf.toString()
.replace("{style-placeholder}", String.format("body { background-color: %s; color: %s; } li {color: %s;} .colorHeader {background-color: %s; color: %s;} .tag {color: %s;}", backgroundColor, contentColor, textColor, accentColorString, accentTextColor, accentColorString))
.replace("{link-color}", colorToCSS(ThemeStore.Companion.accentColor(this)))
.replace("{link-color-active}", colorToCSS(ColorUtil.INSTANCE.lightenColor(ThemeStore.Companion.accentColor(this))));
webView.loadData(changeLog, "text/html", "UTF-8");
} catch (Throwable e) {
webView.loadData("<h1>Unable to load</h1><p>" + e.getLocalizedMessage() + "</p>", "text/html", "UTF-8");
}
setChangelogRead(this);
}
}

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities.base package io.github.muntashirakon.music.activities.base
import android.Manifest import android.Manifest
@ -12,8 +26,8 @@ import android.view.KeyEvent
import android.view.View import android.view.View
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import com.google.android.material.snackbar.Snackbar
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import com.google.android.material.snackbar.Snackbar
abstract class AbsBaseActivity : AbsThemeActivity() { abstract class AbsBaseActivity : AbsThemeActivity() {
private var hadPermissions: Boolean = false private var hadPermissions: Boolean = false
@ -46,7 +60,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
override fun onPostCreate(savedInstanceState: Bundle?) { override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState) super.onPostCreate(savedInstanceState)
if (!hasPermissions()) { if (!hasPermissions()) {
//requestPermissions() // requestPermissions()
} }
} }
@ -107,7 +121,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
this@AbsBaseActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE this@AbsBaseActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE
) )
) { ) {
//User has deny from permission dialog // User has deny from permission dialog
Snackbar.make( Snackbar.make(
snackBarContainer, snackBarContainer,
permissionDeniedMessage!!, permissionDeniedMessage!!,

View file

@ -1,25 +1,44 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities.base package io.github.muntashirakon.music.activities.base
import android.Manifest import android.Manifest
import android.content.* import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.db.toPlayCount import io.github.muntashirakon.music.db.toPlayCount
import io.github.muntashirakon.music.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener import io.github.muntashirakon.music.interfaces.IMusicServiceEventListener
import io.github.muntashirakon.music.repository.RealRepository import io.github.muntashirakon.music.repository.RealRepository
import io.github.muntashirakon.music.service.MusicService.* import io.github.muntashirakon.music.service.MusicService.*
import java.lang.ref.WeakReference
import java.util.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import java.lang.ref.WeakReference
import java.util.*
abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener { abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventListener {
private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>() private val mMusicServiceEventListeners = ArrayList<IMusicServiceEventListener>()
private val repository: RealRepository by inject() private val repository: RealRepository by inject()
private var serviceToken: MusicPlayerRemote.ServiceToken? = null private var serviceToken: MusicPlayerRemote.ServiceToken? = null
private var musicStateReceiver: MusicStateReceiver? = null private var musicStateReceiver: MusicStateReceiver? = null
@ -49,15 +68,15 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
} }
} }
fun addMusicServiceEventListener(listener: MusicServiceEventListener?) { fun addMusicServiceEventListener(listenerI: IMusicServiceEventListener?) {
if (listener != null) { if (listenerI != null) {
mMusicServiceEventListeners.add(listener) mMusicServiceEventListeners.add(listenerI)
} }
} }
fun removeMusicServiceEventListener(listener: MusicServiceEventListener?) { fun removeMusicServiceEventListener(listenerI: IMusicServiceEventListener?) {
if (listener != null) { if (listenerI != null) {
mMusicServiceEventListeners.remove(listener) mMusicServiceEventListeners.remove(listenerI)
} }
} }

View file

@ -1,30 +1,63 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities.base package io.github.muntashirakon.music.activities.base
import android.annotation.SuppressLint
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.annotation.LayoutRes
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Observer import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.ColorUtil
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.RetroBottomSheetBehavior import io.github.muntashirakon.music.RetroBottomSheetBehavior
import io.github.muntashirakon.music.extensions.hide import io.github.muntashirakon.music.extensions.*
import io.github.muntashirakon.music.extensions.whichFragment
import io.github.muntashirakon.music.fragments.LibraryViewModel import io.github.muntashirakon.music.fragments.LibraryViewModel
import io.github.muntashirakon.music.fragments.MiniPlayerFragment import io.github.muntashirakon.music.fragments.MiniPlayerFragment
import io.github.muntashirakon.music.fragments.NowPlayingScreen import io.github.muntashirakon.music.fragments.NowPlayingScreen
import io.github.muntashirakon.music.fragments.NowPlayingScreen.* import io.github.muntashirakon.music.fragments.NowPlayingScreen.*
import io.github.muntashirakon.music.fragments.base.AbsPlayerFragment
import io.github.muntashirakon.music.fragments.player.adaptive.AdaptiveFragment
import io.github.muntashirakon.music.fragments.player.blur.BlurPlayerFragment
import io.github.muntashirakon.music.fragments.player.card.CardFragment
import io.github.muntashirakon.music.fragments.player.cardblur.CardBlurFragment
import io.github.muntashirakon.music.fragments.player.circle.CirclePlayerFragment
import io.github.muntashirakon.music.fragments.player.classic.ClassicPlayerFragment
import io.github.muntashirakon.music.fragments.player.color.ColorFragment
import io.github.muntashirakon.music.fragments.player.fit.FitFragment
import io.github.muntashirakon.music.fragments.player.flat.FlatPlayerFragment
import io.github.muntashirakon.music.fragments.player.full.FullPlayerFragment
import io.github.muntashirakon.music.fragments.player.gradient.GradientPlayerFragment
import io.github.muntashirakon.music.fragments.player.material.MaterialFragment
import io.github.muntashirakon.music.fragments.player.normal.PlayerFragment
import io.github.muntashirakon.music.fragments.player.peak.PeakPlayerFragment
import io.github.muntashirakon.music.fragments.player.plain.PlainPlayerFragment
import io.github.muntashirakon.music.fragments.player.simple.SimplePlayerFragment
import io.github.muntashirakon.music.fragments.player.tiny.TinyPlayerFragment
import io.github.muntashirakon.music.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.model.CategoryInfo import io.github.muntashirakon.music.model.CategoryInfo
import io.github.muntashirakon.music.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.views.BottomNavigationBarTinted import io.github.muntashirakon.music.views.BottomNavigationBarTinted
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
import kotlinx.android.synthetic.main.sliding_music_panel_layout.* import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
@ -34,9 +67,10 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
} }
protected val libraryViewModel by viewModel<LibraryViewModel>() protected val libraryViewModel by viewModel<LibraryViewModel>()
private lateinit var behavior: RetroBottomSheetBehavior<FrameLayout> private lateinit var bottomSheetBehavior: RetroBottomSheetBehavior<FrameLayout>
private var playerFragment: AbsPlayerFragment? = null
private var miniPlayerFragment: MiniPlayerFragment? = null private var miniPlayerFragment: MiniPlayerFragment? = null
private var cps: NowPlayingScreen? = null private var nowPlayingScreen: NowPlayingScreen? = null
private var navigationBarColor: Int = 0 private var navigationBarColor: Int = 0
private var taskColor: Int = 0 private var taskColor: Int = 0
private var lightStatusBar: Boolean = false private var lightStatusBar: Boolean = false
@ -44,88 +78,90 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
private var paletteColor: Int = Color.WHITE private var paletteColor: Int = Color.WHITE
protected abstract fun createContentView(): View protected abstract fun createContentView(): View
private val panelState: Int private val panelState: Int
get() = behavior.state get() = bottomSheetBehavior.state
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() { private val bottomSheetCallbackList = object : BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) { override fun onSlide(bottomSheet: View, slideOffset: Float) {
setMiniPlayerAlphaProgress(slideOffset) setMiniPlayerAlphaProgress(slideOffset)
dimBackground.show()
dimBackground.alpha = slideOffset
} }
override fun onStateChanged(bottomSheet: View, newState: Int) { override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) { when (newState) {
BottomSheetBehavior.STATE_EXPANDED -> { STATE_EXPANDED -> {
onPanelExpanded() onPanelExpanded()
} }
BottomSheetBehavior.STATE_COLLAPSED -> { STATE_COLLAPSED -> {
onPanelCollapsed() onPanelCollapsed()
dimBackground.hide()
} }
else -> { else -> {
println("Do something")
} }
} }
} }
} }
fun getBottomSheetBehavior() = bottomSheetBehavior
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(createContentView()) setContentView(createContentView())
chooseFragmentForTheme() chooseFragmentForTheme()
setupSlidingUpPanel() setupSlidingUpPanel()
setupBottomSheet() setupBottomSheet()
updateColor()
libraryViewModel.paletteColorLiveData.observe(this, Observer { val themeColor = ATHUtil.resolveColor(this, android.R.attr.windowBackground, Color.GRAY)
this.paletteColor = it dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
onPaletteColorChanged() dimBackground.setOnClickListener {
}) println("dimBackground")
}
} }
fun getBottomSheetBehavior() = behavior
private fun setupBottomSheet() { private fun setupBottomSheet() {
behavior = BottomSheetBehavior.from(slidingPanel) as RetroBottomSheetBehavior bottomSheetBehavior = from(slidingPanel) as RetroBottomSheetBehavior
behavior.addBottomSheetCallback(bottomSheetCallbackList) bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
if (behavior.state == BottomSheetBehavior.STATE_EXPANDED) {
setMiniPlayerAlphaProgress(1f)
}
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if (cps != PreferenceUtil.nowPlayingScreen) { if (nowPlayingScreen != PreferenceUtil.nowPlayingScreen) {
postRecreate() postRecreate()
} }
if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) {
setMiniPlayerAlphaProgress(1f)
}
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
behavior.removeBottomSheetCallback(bottomSheetCallbackList) bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList)
} }
protected fun wrapSlidingMusicPanel(@LayoutRes resId: Int): View { @SuppressLint("InflateParams")
protected fun wrapSlidingMusicPanel(): View {
val slidingMusicPanelLayout = val slidingMusicPanelLayout =
layoutInflater.inflate(R.layout.sliding_music_panel_layout, null) layoutInflater.inflate(R.layout.sliding_music_panel_layout, null)
val contentContainer: ViewGroup = val contentContainer: ViewGroup =
slidingMusicPanelLayout.findViewById(R.id.mainContentFrame) slidingMusicPanelLayout.findViewById(R.id.mainContentFrame)
layoutInflater.inflate(resId, contentContainer) layoutInflater.inflate(R.layout.activity_main_content, contentContainer)
return slidingMusicPanelLayout return slidingMusicPanelLayout
} }
fun collapsePanel() { fun collapsePanel() {
behavior.state = BottomSheetBehavior.STATE_COLLAPSED bottomSheetBehavior.state = STATE_COLLAPSED
setMiniPlayerAlphaProgress(0f)
} }
fun expandPanel() { fun expandPanel() {
behavior.state = BottomSheetBehavior.STATE_EXPANDED bottomSheetBehavior.state = STATE_EXPANDED
setMiniPlayerAlphaProgress(1f) setMiniPlayerAlphaProgress(1f)
} }
private fun setMiniPlayerAlphaProgress(progress: Float) { private fun setMiniPlayerAlphaProgress(progress: Float) {
if (miniPlayerFragment?.view == null) return
val alpha = 1 - progress val alpha = 1 - progress
miniPlayerFragment?.view?.alpha = alpha miniPlayerFragment?.view?.alpha = alpha
miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE
@ -150,11 +186,16 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
ViewTreeObserver.OnGlobalLayoutListener { ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() { override fun onGlobalLayout() {
slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this) slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
if (nowPlayingScreen != Peak) {
val params = slidingPanel.layoutParams as ViewGroup.LayoutParams
params.height = ViewGroup.LayoutParams.MATCH_PARENT
slidingPanel.layoutParams = params
}
when (panelState) { when (panelState) {
BottomSheetBehavior.STATE_EXPANDED -> onPanelExpanded() STATE_EXPANDED -> onPanelExpanded()
BottomSheetBehavior.STATE_COLLAPSED -> onPanelCollapsed() STATE_COLLAPSED -> onPanelCollapsed()
else -> { else -> {
//playerFragment!!.onHide() // playerFragment!!.onHide()
} }
} }
} }
@ -165,35 +206,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
return bottomNavigationView return bottomNavigationView
} }
fun hideBottomBarVisibility(visible: Boolean) {
bottomNavigationView.isVisible = visible
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
}
private fun hideBottomBar(hide: Boolean) {
val heightOfBar = bottomNavigationView.height
val isBottomBarVisible = bottomNavigationView.isVisible
if (hide) {
behavior.isHideable = true
behavior.peekHeight = 0
collapsePanel()
ViewCompat.setElevation(slidingPanel, 0f)
ViewCompat.setElevation(bottomNavigationView, 10f)
} else {
ViewCompat.setElevation(bottomNavigationView, 10f)
ViewCompat.setElevation(slidingPanel, 10f)
behavior.isHideable = false
behavior.peekHeight = (if (isBottomBarVisible) heightOfBar * 2 else heightOfBar) - 24
}
}
private fun chooseFragmentForTheme() {
cps = PreferenceUtil.nowPlayingScreen
miniPlayerFragment = whichFragment<MiniPlayerFragment>(R.id.miniPlayerFragment)
miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
}
override fun onServiceConnected() { override fun onServiceConnected() {
super.onServiceConnected() super.onServiceConnected()
if (MusicPlayerRemote.playingQueue.isNotEmpty()) { if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
@ -216,36 +228,38 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
if (!handleBackPress()) super.onBackPressed() if (!handleBackPress()) super.onBackPressed()
} }
open fun handleBackPress(): Boolean { private fun handleBackPress(): Boolean {
if (panelState == BottomSheetBehavior.STATE_EXPANDED) { if (bottomSheetBehavior.peekHeight != 0 && playerFragment!!.onBackPressed()) return true
if (panelState == STATE_EXPANDED) {
collapsePanel() collapsePanel()
return true return true
} }
return false return false
} }
private fun onPaletteColorChanged() { private fun onPaletteColorChanged() {
if (panelState == BottomSheetBehavior.STATE_EXPANDED) { if (panelState == STATE_EXPANDED) {
super.setTaskDescriptionColor(paletteColor) super.setTaskDescriptionColor(paletteColor)
val isColorLight = ColorUtil.isColorLight(paletteColor) val isColorLight = ColorUtil.isColorLight(paletteColor)
if (PreferenceUtil.isAdaptiveColor && (cps == Normal || cps == Flat)) { if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat)) {
super.setLightNavigationBar(true) super.setLightNavigationBar(true)
super.setLightStatusbar(isColorLight) super.setLightStatusbar(isColorLight)
} else if (cps == Card || cps == Blur || cps == BlurCard) { } else if (nowPlayingScreen == Card || nowPlayingScreen == Blur || nowPlayingScreen == BlurCard) {
super.setLightStatusbar(false) super.setLightStatusbar(false)
super.setLightNavigationBar(true) super.setLightNavigationBar(true)
super.setNavigationbarColor(Color.BLACK) super.setNavigationbarColor(Color.BLACK)
} else if (cps == Color || cps == Tiny || cps == Gradient) { } else if (nowPlayingScreen == Color || nowPlayingScreen == Tiny || nowPlayingScreen == Gradient) {
super.setNavigationbarColor(paletteColor) super.setNavigationbarColor(paletteColor)
super.setLightNavigationBar(isColorLight) super.setLightNavigationBar(isColorLight)
super.setLightStatusbar(isColorLight) super.setLightStatusbar(isColorLight)
} else if (cps == Full) { } else if (nowPlayingScreen == Full) {
super.setNavigationbarColor(paletteColor) super.setNavigationbarColor(paletteColor)
super.setLightNavigationBar(isColorLight) super.setLightNavigationBar(isColorLight)
super.setLightStatusbar(false) super.setLightStatusbar(false)
} else if (cps == Classic) { } else if (nowPlayingScreen == Classic) {
super.setLightStatusbar(false) super.setLightStatusbar(false)
} else if (cps == Fit) { } else if (nowPlayingScreen == Fit) {
super.setLightStatusbar(false) super.setLightStatusbar(false)
} else { } else {
super.setLightStatusbar( super.setLightStatusbar(
@ -263,38 +277,32 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
override fun setLightStatusbar(enabled: Boolean) { override fun setLightStatusbar(enabled: Boolean) {
lightStatusBar = enabled lightStatusBar = enabled
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) { if (panelState == STATE_COLLAPSED) {
super.setLightStatusbar(enabled) super.setLightStatusbar(enabled)
} }
} }
override fun setLightNavigationBar(enabled: Boolean) { override fun setLightNavigationBar(enabled: Boolean) {
lightNavigationBar = enabled lightNavigationBar = enabled
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) { if (panelState == STATE_COLLAPSED) {
super.setLightNavigationBar(enabled) super.setLightNavigationBar(enabled)
} }
} }
override fun setNavigationbarColor(color: Int) { override fun setNavigationbarColor(color: Int) {
navigationBarColor = color navigationBarColor = color
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) { if (panelState == STATE_COLLAPSED) {
super.setNavigationbarColor(color) super.setNavigationbarColor(color)
} }
} }
override fun setTaskDescriptionColor(color: Int) { override fun setTaskDescriptionColor(color: Int) {
taskColor = color taskColor = color
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) { if (panelState == STATE_COLLAPSED) {
super.setTaskDescriptionColor(color) super.setTaskDescriptionColor(color)
} }
} }
fun hideBottomNavigation() {
behavior.isHideable = true
behavior.peekHeight = 0
hideBottomBarVisibility(false)
}
fun updateTabs() { fun updateTabs() {
bottomNavigationView.menu.clear() bottomNavigationView.menu.clear()
val currentTabs: List<CategoryInfo> = PreferenceUtil.libraryCategory val currentTabs: List<CategoryInfo> = PreferenceUtil.libraryCategory
@ -308,4 +316,74 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
bottomNavigationView.hide() bottomNavigationView.hide()
} }
} }
}
private fun updateColor() {
libraryViewModel.paletteColor.observe(this, { color ->
this.paletteColor = color
onPaletteColorChanged()
})
}
fun setBottomBarVisibility(visible: Int) {
bottomNavigationView.visibility = visible
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
}
private fun hideBottomBar(hide: Boolean) {
val heightOfBar = dip(R.dimen.mini_player_height)
val heightOfBarWithTabs = dip(R.dimen.mini_player_height_expanded)
val isVisible = bottomNavigationView.isVisible
if (hide) {
bottomSheetBehavior.isHideable = true
bottomSheetBehavior.peekHeight = 0
ViewCompat.setElevation(slidingPanel, 0f)
ViewCompat.setElevation(bottomNavigationView, 10f)
collapsePanel()
} else {
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
bottomSheetBehavior.isHideable = false
ViewCompat.setElevation(slidingPanel, 10f)
ViewCompat.setElevation(bottomNavigationView, 10f)
if (isVisible) {
bottomSheetBehavior.peekHeight = heightOfBarWithTabs
bottomNavigationView.translateYAnimate(0f)
} else {
bottomNavigationView.translateYAnimate(150f)
bottomSheetBehavior.peekHeight = heightOfBar
}
}
}
}
private fun chooseFragmentForTheme() {
nowPlayingScreen = PreferenceUtil.nowPlayingScreen
val fragment: Fragment = when (nowPlayingScreen) {
Blur -> BlurPlayerFragment()
Adaptive -> AdaptiveFragment()
Normal -> PlayerFragment()
Card -> CardFragment()
BlurCard -> CardBlurFragment()
Fit -> FitFragment()
Flat -> FlatPlayerFragment()
Full -> FullPlayerFragment()
Plain -> PlainPlayerFragment()
Simple -> SimplePlayerFragment()
Material -> MaterialFragment()
Color -> ColorFragment()
Gradient -> GradientPlayerFragment()
Tiny -> TinyPlayerFragment()
Peak -> PeakPlayerFragment()
Circle -> CirclePlayerFragment()
Classic -> ClassicPlayerFragment()
else -> PlayerFragment()
} // must implement AbsPlayerFragment
supportFragmentManager.commit {
replace(R.id.playerFragmentContainer, fragment)
}
supportFragmentManager.executePendingTransactions()
playerFragment = whichFragment<AbsPlayerFragment>(R.id.playerFragmentContainer)
miniPlayerFragment = whichFragment<MiniPlayerFragment>(R.id.miniPlayerFragment)
miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
}
}

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities.base package io.github.muntashirakon.music.activities.base
import android.content.Context import android.content.Context
@ -37,7 +51,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
MaterialDialogsUtil.updateMaterialDialogsThemeSingleton(this) MaterialDialogsUtil.updateMaterialDialogsThemeSingleton(this)
} }
private fun updateTheme() { private fun updateTheme() {
setTheme(ThemeManager.getThemeResValue(this)) setTheme(ThemeManager.getThemeResValue(this))
setDefaultNightMode(ThemeManager.getNightMode(this)) setDefaultNightMode(ThemeManager.getNightMode(this))
@ -204,4 +217,4 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
super.attachBaseContext(LanguageContextWrapper.wrap(newBase, Locale(code))) super.attachBaseContext(LanguageContextWrapper.wrap(newBase, Locale(code)))
} else super.attachBaseContext(newBase) } else super.attachBaseContext(newBase)
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities.bugreport package io.github.muntashirakon.music.activities.bugreport
import android.app.Activity import android.app.Activity
@ -31,6 +45,7 @@ import io.github.muntashirakon.music.misc.DialogAsyncTask
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import java.io.IOException
import kotlinx.android.synthetic.main.activity_bug_report.* import kotlinx.android.synthetic.main.activity_bug_report.*
import kotlinx.android.synthetic.main.bug_report_card_device_info.* import kotlinx.android.synthetic.main.bug_report_card_device_info.*
import kotlinx.android.synthetic.main.bug_report_card_report.* import kotlinx.android.synthetic.main.bug_report_card_report.*
@ -38,7 +53,6 @@ import org.eclipse.egit.github.core.Issue
import org.eclipse.egit.github.core.client.GitHubClient import org.eclipse.egit.github.core.client.GitHubClient
import org.eclipse.egit.github.core.client.RequestException import org.eclipse.egit.github.core.client.RequestException
import org.eclipse.egit.github.core.service.IssueService import org.eclipse.egit.github.core.service.IssueService
import java.io.IOException
private const val RESULT_SUCCESS = "RESULT_OK" private const val RESULT_SUCCESS = "RESULT_OK"
private const val RESULT_BAD_CREDENTIALS = "RESULT_BAD_CREDENTIALS" private const val RESULT_BAD_CREDENTIALS = "RESULT_BAD_CREDENTIALS"
@ -306,7 +320,6 @@ open class BugReportActivity : AbsThemeActivity() {
} }
} }
companion object { companion object {
fun report( fun report(

View file

@ -5,129 +5,197 @@ import android.content.Context;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
import code.name.monkey.retromusic.util.PreferenceUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import io.github.muntashirakon.music.util.PreferenceUtil;
public class DeviceInfo { public class DeviceInfo {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private final String[] abis = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? private final String[] abis =
Build.SUPPORTED_ABIS : new String[]{Build.CPU_ABI, Build.CPU_ABI2}; Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
? Build.SUPPORTED_ABIS
: new String[] {Build.CPU_ABI, Build.CPU_ABI2};
@SuppressLint("NewApi") @SuppressLint("NewApi")
private final String[] abis32Bits = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? private final String[] abis32Bits =
Build.SUPPORTED_32_BIT_ABIS : null; Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? Build.SUPPORTED_32_BIT_ABIS : null;
@SuppressLint("NewApi") @SuppressLint("NewApi")
private final String[] abis64Bits = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? private final String[] abis64Bits =
Build.SUPPORTED_64_BIT_ABIS : null; Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? Build.SUPPORTED_64_BIT_ABIS : null;
private final String baseTheme; private final String baseTheme;
private final String brand = Build.BRAND; private final String brand = Build.BRAND;
private final String buildID = Build.DISPLAY; private final String buildID = Build.DISPLAY;
private final String buildVersion = Build.VERSION.INCREMENTAL; private final String buildVersion = Build.VERSION.INCREMENTAL;
private final String device = Build.DEVICE; private final String device = Build.DEVICE;
private final String hardware = Build.HARDWARE; private final String hardware = Build.HARDWARE;
private final boolean isAdaptive; private final boolean isAdaptive;
private final String manufacturer = Build.MANUFACTURER; private final String manufacturer = Build.MANUFACTURER;
private final String model = Build.MODEL; private final String model = Build.MODEL;
private final String nowPlayingTheme; private final String nowPlayingTheme;
private final String product = Build.PRODUCT; private final String product = Build.PRODUCT;
private final String releaseVersion = Build.VERSION.RELEASE; private final String releaseVersion = Build.VERSION.RELEASE;
@IntRange(from = 0) @IntRange(from = 0)
private final int sdkVersion = Build.VERSION.SDK_INT; private final int sdkVersion = Build.VERSION.SDK_INT;
private final int versionCode; private final int versionCode;
private final String versionName; private final String versionName;
private final String selectedLang; private final String selectedLang;
public DeviceInfo(Context context) { public DeviceInfo(Context context) {
PackageInfo packageInfo; PackageInfo packageInfo;
try { try {
packageInfo = context.getPackageManager() packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
.getPackageInfo(context.getPackageName(), 0); } catch (PackageManager.NameNotFoundException e) {
} catch (PackageManager.NameNotFoundException e) { packageInfo = null;
packageInfo = null;
}
if (packageInfo != null) {
versionCode = packageInfo.versionCode;
versionName = packageInfo.versionName;
} else {
versionCode = -1;
versionName = null;
}
baseTheme = PreferenceUtil.INSTANCE.getBaseTheme();
nowPlayingTheme = context.getString(PreferenceUtil.INSTANCE.getNowPlayingScreen().getTitleRes());
isAdaptive = PreferenceUtil.INSTANCE.isAdaptiveColor();
selectedLang = PreferenceUtil.INSTANCE.getLanguageCode();
} }
if (packageInfo != null) {
public String toMarkdown() { versionCode = packageInfo.versionCode;
return "Device info:\n" versionName = packageInfo.versionName;
+ "---\n" } else {
+ "<table>\n" versionCode = -1;
+ "<tr><td><b>App version</b></td><td>" + versionName + "</td></tr>\n" versionName = null;
+ "<tr><td>App version code</td><td>" + versionCode + "</td></tr>\n"
+ "<tr><td>Android build version</td><td>" + buildVersion + "</td></tr>\n"
+ "<tr><td>Android release version</td><td>" + releaseVersion + "</td></tr>\n"
+ "<tr><td>Android SDK version</td><td>" + sdkVersion + "</td></tr>\n"
+ "<tr><td>Android build ID</td><td>" + buildID + "</td></tr>\n"
+ "<tr><td>Device brand</td><td>" + brand + "</td></tr>\n"
+ "<tr><td>Device manufacturer</td><td>" + manufacturer + "</td></tr>\n"
+ "<tr><td>Device name</td><td>" + device + "</td></tr>\n"
+ "<tr><td>Device model</td><td>" + model + "</td></tr>\n"
+ "<tr><td>Device product name</td><td>" + product + "</td></tr>\n"
+ "<tr><td>Device hardware name</td><td>" + hardware + "</td></tr>\n"
+ "<tr><td>ABIs</td><td>" + Arrays.toString(abis) + "</td></tr>\n"
+ "<tr><td>ABIs (32bit)</td><td>" + Arrays.toString(abis32Bits) + "</td></tr>\n"
+ "<tr><td>ABIs (64bit)</td><td>" + Arrays.toString(abis64Bits) + "</td></tr>\n"
+ "<tr><td>Language</td><td>" + selectedLang + "</td></tr>\n"
+ "</table>\n";
} }
baseTheme = PreferenceUtil.INSTANCE.getBaseTheme();
nowPlayingTheme =
context.getString(PreferenceUtil.INSTANCE.getNowPlayingScreen().getTitleRes());
isAdaptive = PreferenceUtil.INSTANCE.isAdaptiveColor();
selectedLang = PreferenceUtil.INSTANCE.getLanguageCode();
}
@NotNull public String toMarkdown() {
return "Device info:\n"
+ "---\n"
+ "<table>\n"
+ "<tr><td><b>App version</b></td><td>"
+ versionName
+ "</td></tr>\n"
+ "<tr><td>App version code</td><td>"
+ versionCode
+ "</td></tr>\n"
+ "<tr><td>Android build version</td><td>"
+ buildVersion
+ "</td></tr>\n"
+ "<tr><td>Android release version</td><td>"
+ releaseVersion
+ "</td></tr>\n"
+ "<tr><td>Android SDK version</td><td>"
+ sdkVersion
+ "</td></tr>\n"
+ "<tr><td>Android build ID</td><td>"
+ buildID
+ "</td></tr>\n"
+ "<tr><td>Device brand</td><td>"
+ brand
+ "</td></tr>\n"
+ "<tr><td>Device manufacturer</td><td>"
+ manufacturer
+ "</td></tr>\n"
+ "<tr><td>Device name</td><td>"
+ device
+ "</td></tr>\n"
+ "<tr><td>Device model</td><td>"
+ model
+ "</td></tr>\n"
+ "<tr><td>Device product name</td><td>"
+ product
+ "</td></tr>\n"
+ "<tr><td>Device hardware name</td><td>"
+ hardware
+ "</td></tr>\n"
+ "<tr><td>ABIs</td><td>"
+ Arrays.toString(abis)
+ "</td></tr>\n"
+ "<tr><td>ABIs (32bit)</td><td>"
+ Arrays.toString(abis32Bits)
+ "</td></tr>\n"
+ "<tr><td>ABIs (64bit)</td><td>"
+ Arrays.toString(abis64Bits)
+ "</td></tr>\n"
+ "<tr><td>Language</td><td>"
+ selectedLang
+ "</td></tr>\n"
+ "</table>\n";
}
@NotNull
@Override @Override
public String toString() { public String toString() {
return "App version: " + versionName + "\n" return "App version: "
+ "App version code: " + versionCode + "\n" + versionName
+ "Android build version: " + buildVersion + "\n" + "\n"
+ "Android release version: " + releaseVersion + "\n" + "App version code: "
+ "Android SDK version: " + sdkVersion + "\n" + versionCode
+ "Android build ID: " + buildID + "\n" + "\n"
+ "Device brand: " + brand + "\n" + "Android build version: "
+ "Device manufacturer: " + manufacturer + "\n" + buildVersion
+ "Device name: " + device + "\n" + "\n"
+ "Device model: " + model + "\n" + "Android release version: "
+ "Device product name: " + product + "\n" + releaseVersion
+ "Device hardware name: " + hardware + "\n" + "\n"
+ "ABIs: " + Arrays.toString(abis) + "\n" + "Android SDK version: "
+ "ABIs (32bit): " + Arrays.toString(abis32Bits) + "\n" + sdkVersion
+ "ABIs (64bit): " + Arrays.toString(abis64Bits) + "\n" + "\n"
+ "Base theme: " + baseTheme + "\n" + "Android build ID: "
+ "Now playing theme: " + nowPlayingTheme + "\n" + buildID
+ "Adaptive: " + isAdaptive + "\n" + "\n"
+ "System language: " + Locale.getDefault().toLanguageTag() + "\n" + "Device brand: "
+ "In-App Language: " + selectedLang; + brand
} + "\n"
+ "Device manufacturer: "
+ manufacturer
+ "\n"
+ "Device name: "
+ device
+ "\n"
+ "Device model: "
+ model
+ "\n"
+ "Device product name: "
+ product
+ "\n"
+ "Device hardware name: "
+ hardware
+ "\n"
+ "ABIs: "
+ Arrays.toString(abis)
+ "\n"
+ "ABIs (32bit): "
+ Arrays.toString(abis32Bits)
+ "\n"
+ "ABIs (64bit): "
+ Arrays.toString(abis64Bits)
+ "\n"
+ "Base theme: "
+ baseTheme
+ "\n"
+ "Now playing theme: "
+ nowPlayingTheme
+ "\n"
+ "Adaptive: "
+ isAdaptive
+ "\n"
+ "System language: "
+ Locale.getDefault().toLanguageTag()
+ "\n"
+ "In-App Language: "
+ selectedLang;
}
} }

View file

@ -1,33 +1,34 @@
package io.github.muntashirakon.music.activities.bugreport.model; package io.github.muntashirakon.music.activities.bugreport.model;
import io.github.muntashirakon.music.activities.bugreport.model.github.ExtraInfo; import io.github.muntashirakon.music.activities.bugreport.model.github.ExtraInfo;
public class Report { public class Report {
private final String description; private final String description;
private final DeviceInfo deviceInfo; private final DeviceInfo deviceInfo;
private final ExtraInfo extraInfo; private final ExtraInfo extraInfo;
private final String title; private final String title;
public Report(String title, String description, DeviceInfo deviceInfo, ExtraInfo extraInfo) { public Report(String title, String description, DeviceInfo deviceInfo, ExtraInfo extraInfo) {
this.title = title; this.title = title;
this.description = description; this.description = description;
this.deviceInfo = deviceInfo; this.deviceInfo = deviceInfo;
this.extraInfo = extraInfo; this.extraInfo = extraInfo;
} }
public String getDescription() { public String getDescription() {
return description + "\n\n" return description
+ "-\n\n" + "\n\n"
+ deviceInfo.toMarkdown() + "\n\n" + "-\n\n"
+ extraInfo.toMarkdown(); + deviceInfo.toMarkdown()
} + "\n\n"
+ extraInfo.toMarkdown();
}
public String getTitle() { public String getTitle() {
return title; return title;
} }
} }

View file

@ -5,58 +5,57 @@ import java.util.Map;
public class ExtraInfo { public class ExtraInfo {
private final Map<String, String> extraInfo = new LinkedHashMap<>(); private final Map<String, String> extraInfo = new LinkedHashMap<>();
public void put(String key, String value) { public void put(String key, String value) {
extraInfo.put(key, value); extraInfo.put(key, value);
}
public void put(String key, boolean value) {
extraInfo.put(key, Boolean.toString(value));
}
public void put(String key, double value) {
extraInfo.put(key, Double.toString(value));
}
public void put(String key, float value) {
extraInfo.put(key, Float.toString(value));
}
public void put(String key, long value) {
extraInfo.put(key, Long.toString(value));
}
public void put(String key, int value) {
extraInfo.put(key, Integer.toString(value));
}
public void put(String key, Object value) {
extraInfo.put(key, String.valueOf(value));
}
public void remove(String key) {
extraInfo.remove(key);
}
public String toMarkdown() {
if (extraInfo.isEmpty()) {
return "";
} }
public void put(String key, boolean value) { StringBuilder output = new StringBuilder();
extraInfo.put(key, Boolean.toString(value)); output.append("Extra info:\n" + "---\n" + "<table>\n");
for (String key : extraInfo.keySet()) {
output
.append("<tr><td>")
.append(key)
.append("</td><td>")
.append(extraInfo.get(key))
.append("</td></tr>\n");
} }
output.append("</table>\n");
public void put(String key, double value) { return output.toString();
extraInfo.put(key, Double.toString(value)); }
}
public void put(String key, float value) {
extraInfo.put(key, Float.toString(value));
}
public void put(String key, long value) {
extraInfo.put(key, Long.toString(value));
}
public void put(String key, int value) {
extraInfo.put(key, Integer.toString(value));
}
public void put(String key, Object value) {
extraInfo.put(key, String.valueOf(value));
}
public void remove(String key) {
extraInfo.remove(key);
}
public String toMarkdown() {
if (extraInfo.isEmpty()) {
return "";
}
StringBuilder output = new StringBuilder();
output.append("Extra info:\n"
+ "---\n"
+ "<table>\n");
for (String key : extraInfo.keySet()) {
output.append("<tr><td>")
.append(key)
.append("</td><td>")
.append(extraInfo.get(key))
.append("</td></tr>\n");
}
output.append("</table>\n");
return output.toString();
}
} }

View file

@ -4,38 +4,37 @@ import android.text.TextUtils;
public class GithubLogin { public class GithubLogin {
private final String apiToken; private final String apiToken;
private final String password; private final String password;
private final String username; private final String username;
public GithubLogin(String username, String password) { public GithubLogin(String username, String password) {
this.username = username; this.username = username;
this.password = password; this.password = password;
this.apiToken = null; this.apiToken = null;
} }
public GithubLogin(String apiToken) { public GithubLogin(String apiToken) {
this.username = null; this.username = null;
this.password = null; this.password = null;
this.apiToken = apiToken; this.apiToken = apiToken;
} }
public String getApiToken() { public String getApiToken() {
return apiToken; return apiToken;
} }
public String getPassword() { public String getPassword() {
return password; return password;
} }
public String getUsername() { public String getUsername() {
return username; return username;
} }
public boolean shouldUseApiToken() {
return TextUtils.isEmpty(username) || TextUtils.isEmpty(password);
}
public boolean shouldUseApiToken() {
return TextUtils.isEmpty(username) || TextUtils.isEmpty(password);
}
} }

View file

@ -2,20 +2,20 @@ package io.github.muntashirakon.music.activities.bugreport.model.github;
public class GithubTarget { public class GithubTarget {
private final String repository; private final String repository;
private final String username; private final String username;
public GithubTarget(String username, String repository) { public GithubTarget(String username, String repository) {
this.username = username; this.username = username;
this.repository = repository; this.repository = repository;
} }
public String getRepository() { public String getRepository() {
return repository; return repository;
} }
public String getUsername() { public String getUsername() {
return username; return username;
} }
} }

View file

@ -16,57 +16,58 @@ package io.github.muntashirakon.music.activities.saf;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import io.github.muntashirakon.music.R;
import com.heinrichreimersoftware.materialintro.app.IntroActivity; import com.heinrichreimersoftware.materialintro.app.IntroActivity;
import com.heinrichreimersoftware.materialintro.slide.SimpleSlide; import com.heinrichreimersoftware.materialintro.slide.SimpleSlide;
import io.github.muntashirakon.music.R; /** Created by hemanths on 2019-07-31. */
/**
* Created by hemanths on 2019-07-31.
*/
public class SAFGuideActivity extends IntroActivity { public class SAFGuideActivity extends IntroActivity {
public static final int REQUEST_CODE_SAF_GUIDE = 98; public static final int REQUEST_CODE_SAF_GUIDE = 98;
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setButtonCtaVisible(false); setButtonCtaVisible(false);
setButtonNextVisible(false); setButtonNextVisible(false);
setButtonBackVisible(false); setButtonBackVisible(false);
setButtonCtaTintMode(BUTTON_CTA_TINT_MODE_TEXT); setButtonCtaTintMode(BUTTON_CTA_TINT_MODE_TEXT);
String title = String.format(getString(R.string.saf_guide_slide1_title), getString(R.string.app_name)); String title =
String.format(getString(R.string.saf_guide_slide1_title), getString(R.string.app_name));
addSlide(new SimpleSlide.Builder() addSlide(
.title(title) new SimpleSlide.Builder()
.description(Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1 .title(title)
? R.string.saf_guide_slide1_description_before_o : R.string.saf_guide_slide1_description) .description(
.image(R.drawable.saf_guide_1) Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
.background(R.color.md_deep_purple_300) ? R.string.saf_guide_slide1_description_before_o
.backgroundDark(R.color.md_deep_purple_400) : R.string.saf_guide_slide1_description)
.layout(R.layout.fragment_simple_slide_large_image) .image(R.drawable.saf_guide_1)
.build()); .background(R.color.md_deep_purple_300)
addSlide(new SimpleSlide.Builder() .backgroundDark(R.color.md_deep_purple_400)
.title(R.string.saf_guide_slide2_title) .layout(R.layout.fragment_simple_slide_large_image)
.description(R.string.saf_guide_slide2_description) .build());
.image(R.drawable.saf_guide_2) addSlide(
.background(R.color.md_deep_purple_500) new SimpleSlide.Builder()
.backgroundDark(R.color.md_deep_purple_600) .title(R.string.saf_guide_slide2_title)
.layout(R.layout.fragment_simple_slide_large_image) .description(R.string.saf_guide_slide2_description)
.build()); .image(R.drawable.saf_guide_2)
addSlide(new SimpleSlide.Builder() .background(R.color.md_deep_purple_500)
.title(R.string.saf_guide_slide3_title) .backgroundDark(R.color.md_deep_purple_600)
.description(R.string.saf_guide_slide3_description) .layout(R.layout.fragment_simple_slide_large_image)
.image(R.drawable.saf_guide_3) .build());
.background(R.color.md_deep_purple_700) addSlide(
.backgroundDark(R.color.md_deep_purple_800) new SimpleSlide.Builder()
.layout(R.layout.fragment_simple_slide_large_image) .title(R.string.saf_guide_slide3_title)
.build()); .description(R.string.saf_guide_slide3_description)
} .image(R.drawable.saf_guide_3)
.background(R.color.md_deep_purple_700)
.backgroundDark(R.color.md_deep_purple_800)
.layout(R.layout.fragment_simple_slide_large_image)
.build());
}
} }

View file

@ -1,13 +1,25 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities.tageditor package io.github.muntashirakon.music.activities.tageditor
import android.app.Activity import android.app.Activity
import android.app.SearchManager import android.app.SearchManager
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.MenuItem import android.view.MenuItem
@ -16,18 +28,19 @@ import android.view.animation.OvershootInterpolator
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.R.drawable import io.github.muntashirakon.music.R.drawable
import io.github.muntashirakon.music.activities.base.AbsBaseActivity import io.github.muntashirakon.music.activities.base.AbsBaseActivity
import io.github.muntashirakon.music.activities.saf.SAFGuideActivity import io.github.muntashirakon.music.activities.saf.SAFGuideActivity
import io.github.muntashirakon.music.extensions.accentColor
import io.github.muntashirakon.music.model.ArtworkInfo
import io.github.muntashirakon.music.model.LoadingInfo
import io.github.muntashirakon.music.repository.Repository import io.github.muntashirakon.music.repository.Repository
import io.github.muntashirakon.music.util.RetroUtil import io.github.muntashirakon.music.util.RetroUtil
import io.github.muntashirakon.music.util.SAFUtil import io.github.muntashirakon.music.util.SAFUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.android.synthetic.main.activity_album_tag_editor.* import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.audio.AudioFile import org.jaudiotagger.audio.AudioFile
import org.jaudiotagger.audio.AudioFileIO import org.jaudiotagger.audio.AudioFileIO
@ -49,6 +62,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private val currentSongPath: String? = null private val currentSongPath: String? = null
private var savedTags: Map<FieldKey, String>? = null private var savedTags: Map<FieldKey, String>? = null
private var savedArtworkInfo: ArtworkInfo? = null private var savedArtworkInfo: ArtworkInfo? = null
protected abstract val contentViewLayout: Int
protected abstract fun loadImageFromFile(selectedFile: Uri?)
protected val show: AlertDialog protected val show: AlertDialog
get() = get() =
@ -62,7 +77,6 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
} }
} }
.show() .show()
protected abstract val contentViewLayout: Int
internal val albumArtist: String? internal val albumArtist: String?
get() { get() {
@ -182,6 +196,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
getIntentExtras() getIntentExtras()
songPaths = getSongPaths() songPaths = getSongPaths()
println(songPaths?.size)
if (songPaths!!.isEmpty()) { if (songPaths!!.isEmpty()) {
finish() finish()
} }
@ -198,9 +213,9 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private fun setUpImageView() { private fun setUpImageView() {
loadCurrentImage() loadCurrentImage()
items = listOf( items = listOf(
getString(io.github.muntashirakon.music.R.string.pick_from_local_storage), getString(R.string.pick_from_local_storage),
getString(io.github.muntashirakon.music.R.string.web_search), getString(R.string.web_search),
getString(io.github.muntashirakon.music.R.string.remove_cover) getString(R.string.remove_cover)
) )
editorImage?.setOnClickListener { show } editorImage?.setOnClickListener { show }
} }
@ -211,7 +226,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
startActivityForResult( startActivityForResult(
Intent.createChooser( Intent.createChooser(
intent, intent,
getString(io.github.muntashirakon.music.R.string.pick_from_local_storage) getString(R.string.pick_from_local_storage)
), REQUEST_CODE_SELECT_IMAGE ), REQUEST_CODE_SELECT_IMAGE
) )
} }
@ -223,20 +238,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
protected abstract fun deleteImage() protected abstract fun deleteImage()
private fun setUpFab() { private fun setUpFab() {
saveFab.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this)) saveFab.accentColor()
ColorStateList.valueOf(
MaterialValueHelper.getPrimaryTextColor(
this,
ColorUtil.isColorLight(
ThemeStore.accentColor(
this
)
)
)
).apply {
saveFab.setTextColor(this)
saveFab.iconTint = this
}
saveFab.apply { saveFab.apply {
scaleX = 0f scaleX = 0f
scaleY = 0f scaleY = 0f
@ -324,35 +326,25 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
} }
protected fun writeValuesToFiles( protected fun writeValuesToFiles(
fieldKeyValueMap: Map<FieldKey, String>, artworkInfo: ArtworkInfo? fieldKeyValueMap: Map<FieldKey, String>,
artworkInfo: ArtworkInfo?
) { ) {
RetroUtil.hideSoftKeyboard(this) RetroUtil.hideSoftKeyboard(this)
hideFab() hideFab()
println(fieldKeyValueMap)
savedSongPaths = songPaths WriteTagsAsyncTask(this).execute(
savedTags = fieldKeyValueMap LoadingInfo(
savedArtworkInfo = artworkInfo songPaths,
fieldKeyValueMap,
if (!SAFUtil.isSAFRequired(savedSongPaths)) { artworkInfo
writeTags(savedSongPaths) )
} else { )
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (SAFUtil.isSDCardAccessGranted(this)) {
writeTags(savedSongPaths)
} else {
startActivityForResult(
Intent(this, SAFGuideActivity::class.java),
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE
)
}
}
}
} }
private fun writeTags(paths: List<String>?) { private fun writeTags(paths: List<String>?) {
WriteTagsAsyncTask(this).execute( WriteTagsAsyncTask(this).execute(
WriteTagsAsyncTask.LoadingInfo( LoadingInfo(
paths, paths,
savedTags, savedTags,
savedArtworkInfo savedArtworkInfo
@ -360,6 +352,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
) )
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent) super.onActivityResult(requestCode, resultCode, intent)
when (requestCode) { when (requestCode) {
@ -385,7 +378,6 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
} }
} }
protected abstract fun loadImageFromFile(selectedFile: Uri?)
private fun getAudioFile(path: String): AudioFile { private fun getAudioFile(path: String): AudioFile {
return try { return try {
@ -396,7 +388,6 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
} }
} }
class ArtworkInfo constructor(val albumId: Long, val artwork: Bitmap?)
companion object { companion object {
@ -405,5 +396,4 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private val TAG = AbsTagEditorActivity::class.java.simpleName private val TAG = AbsTagEditorActivity::class.java.simpleName
private const val REQUEST_CODE_SELECT_IMAGE = 1000 private const val REQUEST_CODE_SELECT_IMAGE = 1000
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities.tageditor package io.github.muntashirakon.music.activities.tageditor
import android.app.Activity import android.app.Activity
@ -18,6 +32,7 @@ import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.extensions.appHandleColor import io.github.muntashirakon.music.extensions.appHandleColor
import io.github.muntashirakon.music.glide.palette.BitmapPaletteTranscoder import io.github.muntashirakon.music.glide.palette.BitmapPaletteTranscoder
import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import io.github.muntashirakon.music.model.ArtworkInfo
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.ImageUtil import io.github.muntashirakon.music.util.ImageUtil
import io.github.muntashirakon.music.util.RetroColorUtil.generatePalette import io.github.muntashirakon.music.util.RetroColorUtil.generatePalette
@ -26,9 +41,9 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.animation.GlideAnimation import com.bumptech.glide.request.animation.GlideAnimation
import com.bumptech.glide.request.target.SimpleTarget import com.bumptech.glide.request.target.SimpleTarget
import java.util.*
import kotlinx.android.synthetic.main.activity_album_tag_editor.* import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.tag.FieldKey import org.jaudiotagger.tag.FieldKey
import java.util.*
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher { class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
@ -155,7 +170,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
override fun save() { override fun save() {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java) val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString() fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
//android seems not to recognize album_artist field so we additionally write the normal artist field // android seems not to recognize album_artist field so we additionally write the normal artist field
fieldKeyValueMap[FieldKey.ARTIST] = albumArtistText.text.toString() fieldKeyValueMap[FieldKey.ARTIST] = albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString() fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.GENRE] = genreTitle.text.toString() fieldKeyValueMap[FieldKey.GENRE] = genreTitle.text.toString()
@ -163,8 +178,11 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
writeValuesToFiles( writeValuesToFiles(
fieldKeyValueMap, fieldKeyValueMap,
if (deleteAlbumArt) ArtworkInfo(id, null) when {
else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!) deleteAlbumArt -> ArtworkInfo(id, null)
albumArtBitmap == null -> null
else -> ArtworkInfo(id, albumArtBitmap!!)
}
) )
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities.tageditor package io.github.muntashirakon.music.activities.tageditor
import android.net.Uri import android.net.Uri
@ -88,11 +102,7 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
writeValuesToFiles(fieldKeyValueMap, null) writeValuesToFiles(fieldKeyValueMap, null)
} }
override fun getSongPaths(): List<String> { override fun getSongPaths(): List<String> = listOf(songRepository.song(id).data)
val paths = ArrayList<String>(1)
paths.add(songRepository.song(id).data)
return paths
}
override fun loadImageFromFile(selectedFile: Uri?) { override fun loadImageFromFile(selectedFile: Uri?) {
} }
@ -111,5 +121,3 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
val TAG: String = SongTagEditorActivity::class.java.simpleName val TAG: String = SongTagEditorActivity::class.java.simpleName
} }
} }

View file

@ -5,67 +5,54 @@ import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.media.MediaScannerConnection; import android.media.MediaScannerConnection;
import android.net.Uri; import android.util.Log;
import android.os.Build; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.afollestad.materialdialogs.MaterialDialog;
import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.CannotWriteException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.images.Artwork; import org.jaudiotagger.tag.images.Artwork;
import org.jaudiotagger.tag.images.ArtworkFactory; import org.jaudiotagger.tag.images.ArtworkFactory;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference; import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import io.github.muntashirakon.music.R; import io.github.muntashirakon.music.R;
import io.github.muntashirakon.music.misc.DialogAsyncTask; import io.github.muntashirakon.music.misc.DialogAsyncTask;
import io.github.muntashirakon.music.misc.UpdateToastMediaScannerCompletionListener; import io.github.muntashirakon.music.misc.UpdateToastMediaScannerCompletionListener;
import io.github.muntashirakon.music.model.LoadingInfo;
import io.github.muntashirakon.music.util.MusicUtil; import io.github.muntashirakon.music.util.MusicUtil;
import io.github.muntashirakon.music.util.SAFUtil;
public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.LoadingInfo, Integer, String[]> { public class WriteTagsAsyncTask extends DialogAsyncTask<LoadingInfo, Integer, List<String>> {
private WeakReference<Activity> activity; public WriteTagsAsyncTask(Context context) {
super(context);
public WriteTagsAsyncTask(@NonNull Activity activity) {
super(activity);
this.activity = new WeakReference<>(activity);
}
@NonNull
@Override
protected Dialog createDialog(@NonNull Context context) {
return new MaterialAlertDialogBuilder(context)
.setTitle(R.string.saving_changes)
.setCancelable(false)
.setView(R.layout.loading)
.create();
} }
@Override @Override
protected String[] doInBackground(LoadingInfo... params) { protected List<String> doInBackground(LoadingInfo... params) {
try { try {
LoadingInfo info = params[0]; LoadingInfo info = params[0];
Artwork artwork = null; Artwork artwork = null;
File albumArtFile = null; File albumArtFile = null;
if (info.artworkInfo != null && info.artworkInfo.getArtwork() != null) { if (info.getArtworkInfo() != null && info.getArtworkInfo().getArtwork() != null) {
try { try {
albumArtFile = MusicUtil.INSTANCE.createAlbumArtFile().getCanonicalFile(); albumArtFile = MusicUtil.INSTANCE.createAlbumArtFile().getCanonicalFile();
info.artworkInfo.getArtwork() info.getArtworkInfo().getArtwork().compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(albumArtFile));
.compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(albumArtFile));
artwork = ArtworkFactory.createArtworkFromFile(albumArtFile); artwork = ArtworkFactory.createArtworkFromFile(albumArtFile);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -75,21 +62,14 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
int counter = 0; int counter = 0;
boolean wroteArtwork = false; boolean wroteArtwork = false;
boolean deletedArtwork = false; boolean deletedArtwork = false;
for (String filePath : info.filePaths) { for (String filePath : info.getFilePaths()) {
publishProgress(++counter, info.filePaths.size()); publishProgress(++counter, info.getFilePaths().size());
try { try {
Uri safUri = null;
if (filePath.contains(SAFUtil.SEPARATOR)) {
String[] fragments = filePath.split(SAFUtil.SEPARATOR);
filePath = fragments[0];
safUri = Uri.parse(fragments[1]);
}
AudioFile audioFile = AudioFileIO.read(new File(filePath)); AudioFile audioFile = AudioFileIO.read(new File(filePath));
Tag tag = audioFile.getTagOrCreateAndSetDefault(); Tag tag = audioFile.getTagOrCreateAndSetDefault();
if (info.fieldKeyValueMap != null) { if (info.getFieldKeyValueMap() != null) {
for (Map.Entry<FieldKey, String> entry : info.fieldKeyValueMap.entrySet()) { for (Map.Entry<FieldKey, String> entry : info.getFieldKeyValueMap().entrySet()) {
try { try {
tag.setField(entry.getKey(), entry.getValue()); tag.setField(entry.getKey(), entry.getValue());
} catch (Exception e) { } catch (Exception e) {
@ -98,8 +78,8 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
} }
} }
if (info.artworkInfo != null) { if (info.getArtworkInfo() != null) {
if (info.artworkInfo.getArtwork() == null) { if (info.getArtworkInfo().getArtwork() == null) {
tag.deleteArtworkField(); tag.deleteArtworkField();
deletedArtwork = true; deletedArtwork = true;
} else if (artwork != null) { } else if (artwork != null) {
@ -109,10 +89,8 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
} }
} }
Activity activity = this.activity.get(); audioFile.commit();
SAFUtil.write(activity, audioFile, safUri); } catch (@NonNull CannotReadException | IOException | CannotWriteException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
} catch (@NonNull Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -120,24 +98,13 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
Context context = getContext(); Context context = getContext();
if (context != null) { if (context != null) {
if (wroteArtwork) { if (wroteArtwork) {
MusicUtil.INSTANCE.insertAlbumArt(context, info.artworkInfo.getAlbumId(), albumArtFile.getPath()); MusicUtil.INSTANCE.insertAlbumArt(context, info.getArtworkInfo().getAlbumId(), albumArtFile.getPath());
} else if (deletedArtwork) { } else if (deletedArtwork) {
MusicUtil.INSTANCE.deleteAlbumArt(context, info.artworkInfo.getAlbumId()); MusicUtil.INSTANCE.deleteAlbumArt(context, info.getArtworkInfo().getAlbumId());
} }
} }
Collection<String> paths = info.filePaths; return info.getFilePaths();
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
paths = new ArrayList<>(info.filePaths.size());
for (String path : info.filePaths) {
if (path.contains(SAFUtil.SEPARATOR)) {
path = path.split(SAFUtil.SEPARATOR)[0];
}
paths.add(path);
}
}
return paths.toArray(new String[paths.size()]);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
@ -145,48 +112,40 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
} }
@Override @Override
protected void onCancelled(String[] toBeScanned) { protected void onPostExecute(List<String> toBeScanned) {
super.onCancelled(toBeScanned);
scan(toBeScanned);
}
@Override
protected void onPostExecute(String[] toBeScanned) {
super.onPostExecute(toBeScanned); super.onPostExecute(toBeScanned);
scan(toBeScanned); scan(toBeScanned);
} }
@Override
protected void onCancelled(List<String> toBeScanned) {
super.onCancelled(toBeScanned);
scan(toBeScanned);
}
private void scan(List<String> toBeScanned) {
Context context = getContext();
if (toBeScanned == null || toBeScanned.isEmpty()) {
Log.i("scan", "scan: Empty");
Toast.makeText(context, "Scan file from folder", Toast.LENGTH_SHORT).show();
return;
}
MediaScannerConnection.scanFile(context, toBeScanned.toArray(new String[0]), null, context instanceof Activity ? new UpdateToastMediaScannerCompletionListener((Activity) context, toBeScanned) : null);
}
@Override
protected Dialog createDialog(@NonNull Context context) {
return new MaterialDialog.Builder(context)
.title(R.string.saving_changes)
.cancelable(false)
.progress(false, 0)
.build();
}
@Override @Override
protected void onProgressUpdate(@NonNull Dialog dialog, Integer... values) { protected void onProgressUpdate(@NonNull Dialog dialog, Integer... values) {
super.onProgressUpdate(dialog, values); super.onProgressUpdate(dialog, values);
//((MaterialDialog) dialog).setMaxProgress(values[1]); ((MaterialDialog) dialog).setMaxProgress(values[1]);
//((MaterialDialog) dialog).setProgress(values[0]); ((MaterialDialog) dialog).setProgress(values[0]);
} }
}
private void scan(String[] toBeScanned) {
Activity activity = this.activity.get();
if (activity != null) {
MediaScannerConnection.scanFile(activity, toBeScanned, null,
new UpdateToastMediaScannerCompletionListener(activity, toBeScanned));
}
}
public static class LoadingInfo {
@Nullable
final Map<FieldKey, String> fieldKeyValueMap;
final Collection<String> filePaths;
@Nullable
private AbsTagEditorActivity.ArtworkInfo artworkInfo;
public LoadingInfo(Collection<String> filePaths,
@Nullable Map<FieldKey, String> fieldKeyValueMap,
@Nullable AbsTagEditorActivity.ArtworkInfo artworkInfo) {
this.filePaths = filePaths;
this.fieldKeyValueMap = fieldKeyValueMap;
this.artworkInfo = artworkInfo;
}
}
}

View file

@ -22,116 +22,119 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.checkbox.MaterialCheckBox;
import java.util.List;
import code.name.monkey.appthemehelper.ThemeStore; import code.name.monkey.appthemehelper.ThemeStore;
import io.github.muntashirakon.music.R; import io.github.muntashirakon.music.R;
import io.github.muntashirakon.music.model.CategoryInfo; import io.github.muntashirakon.music.model.CategoryInfo;
import io.github.muntashirakon.music.util.SwipeAndDragHelper; import io.github.muntashirakon.music.util.SwipeAndDragHelper;
import com.google.android.material.checkbox.MaterialCheckBox;
import java.util.List;
public class CategoryInfoAdapter extends RecyclerView.Adapter<CategoryInfoAdapter.ViewHolder> public class CategoryInfoAdapter extends RecyclerView.Adapter<CategoryInfoAdapter.ViewHolder>
implements SwipeAndDragHelper.ActionCompletionContract { implements SwipeAndDragHelper.ActionCompletionContract {
private List<CategoryInfo> categoryInfos; private List<CategoryInfo> categoryInfos;
private ItemTouchHelper touchHelper; private ItemTouchHelper touchHelper;
public CategoryInfoAdapter() { public CategoryInfoAdapter() {
SwipeAndDragHelper swipeAndDragHelper = new SwipeAndDragHelper(this); SwipeAndDragHelper swipeAndDragHelper = new SwipeAndDragHelper(this);
touchHelper = new ItemTouchHelper(swipeAndDragHelper); touchHelper = new ItemTouchHelper(swipeAndDragHelper);
} }
public void attachToRecyclerView(RecyclerView recyclerView) { public void attachToRecyclerView(RecyclerView recyclerView) {
touchHelper.attachToRecyclerView(recyclerView); touchHelper.attachToRecyclerView(recyclerView);
} }
@NonNull @NonNull
public List<CategoryInfo> getCategoryInfos() { public List<CategoryInfo> getCategoryInfos() {
return categoryInfos; return categoryInfos;
} }
public void setCategoryInfos(@NonNull List<CategoryInfo> categoryInfos) { public void setCategoryInfos(@NonNull List<CategoryInfo> categoryInfos) {
this.categoryInfos = categoryInfos; this.categoryInfos = categoryInfos;
notifyDataSetChanged(); notifyDataSetChanged();
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return categoryInfos.size(); return categoryInfos.size();
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@Override @Override
public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
CategoryInfo categoryInfo = categoryInfos.get(position); CategoryInfo categoryInfo = categoryInfos.get(position);
holder.checkBox.setChecked(categoryInfo.isVisible()); holder.checkBox.setChecked(categoryInfo.isVisible());
holder.title.setText(holder.title.getResources().getString(categoryInfo.getCategory().getStringRes())); holder.title.setText(
holder.title.getResources().getString(categoryInfo.getCategory().getStringRes()));
holder.itemView.setOnClickListener(v -> { holder.itemView.setOnClickListener(
if (!(categoryInfo.isVisible() && isLastCheckedCategory(categoryInfo))) { v -> {
categoryInfo.setVisible(!categoryInfo.isVisible()); if (!(categoryInfo.isVisible() && isLastCheckedCategory(categoryInfo))) {
holder.checkBox.setChecked(categoryInfo.isVisible()); categoryInfo.setVisible(!categoryInfo.isVisible());
} else { holder.checkBox.setChecked(categoryInfo.isVisible());
Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category, } else {
Toast.LENGTH_SHORT).show(); Toast.makeText(
} holder.itemView.getContext(),
R.string.you_have_to_select_at_least_one_category,
Toast.LENGTH_SHORT)
.show();
}
}); });
holder.dragView.setOnTouchListener((view, event) -> { holder.dragView.setOnTouchListener(
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { (view, event) -> {
touchHelper.startDrag(holder); if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
} touchHelper.startDrag(holder);
return false; }
} return false;
); });
} }
@Override @Override
@NonNull @NonNull
public CategoryInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public CategoryInfoAdapter.ViewHolder onCreateViewHolder(
View view = LayoutInflater.from(parent.getContext()) @NonNull ViewGroup parent, int viewType) {
.inflate(R.layout.preference_dialog_library_categories_listitem, parent, false); View view =
return new ViewHolder(view); LayoutInflater.from(parent.getContext())
} .inflate(R.layout.preference_dialog_library_categories_listitem, parent, false);
return new ViewHolder(view);
}
@Override @Override
public void onViewMoved(int oldPosition, int newPosition) { public void onViewMoved(int oldPosition, int newPosition) {
CategoryInfo categoryInfo = categoryInfos.get(oldPosition); CategoryInfo categoryInfo = categoryInfos.get(oldPosition);
categoryInfos.remove(oldPosition); categoryInfos.remove(oldPosition);
categoryInfos.add(newPosition, categoryInfo); categoryInfos.add(newPosition, categoryInfo);
notifyItemMoved(oldPosition, newPosition); notifyItemMoved(oldPosition, newPosition);
} }
private boolean isLastCheckedCategory(CategoryInfo categoryInfo) { private boolean isLastCheckedCategory(CategoryInfo categoryInfo) {
if (categoryInfo.isVisible()) { if (categoryInfo.isVisible()) {
for (CategoryInfo c : categoryInfos) { for (CategoryInfo c : categoryInfos) {
if (c != categoryInfo && c.isVisible()) { if (c != categoryInfo && c.isVisible()) {
return false; return false;
}
}
} }
return true; }
} }
return true;
}
static class ViewHolder extends RecyclerView.ViewHolder { static class ViewHolder extends RecyclerView.ViewHolder {
private MaterialCheckBox checkBox; private MaterialCheckBox checkBox;
private View dragView; private View dragView;
private TextView title; private TextView title;
ViewHolder(View view) { ViewHolder(View view) {
super(view); super(view);
checkBox = view.findViewById(R.id.checkbox); checkBox = view.findViewById(R.id.checkbox);
checkBox.setButtonTintList( checkBox.setButtonTintList(
ColorStateList.valueOf(ThemeStore.Companion.accentColor(checkBox.getContext()))); ColorStateList.valueOf(ThemeStore.Companion.accentColor(checkBox.getContext())));
title = view.findViewById(R.id.title); title = view.findViewById(R.id.title);
dragView = view.findViewById(R.id.drag_view); dragView = view.findViewById(R.id.drag_view);
}
} }
} }
}

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter package io.github.muntashirakon.music.adapter
import android.app.Activity import android.app.Activity
@ -59,6 +73,11 @@ class ContributorAdapter(
return contributors.size return contributors.size
} }
fun swapData(it: List<Contributor>) {
contributors = it
notifyDataSetChanged()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.findViewById(R.id.title) val title: TextView = itemView.findViewById(R.id.title)
val text: TextView = itemView.findViewById(R.id.text) val text: TextView = itemView.findViewById(R.id.text)
@ -68,7 +87,7 @@ class ContributorAdapter(
title.text = contributor.name title.text = contributor.name
text.text = contributor.summary text.text = contributor.summary
Glide.with(image.context) Glide.with(image.context)
.load(contributor.profileImage) .load(contributor.image)
.error(R.drawable.ic_account) .error(R.drawable.ic_account)
.placeholder(R.drawable.ic_account) .placeholder(R.drawable.ic_account)
.dontAnimate() .dontAnimate()

View file

@ -1,6 +1,19 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter package io.github.muntashirakon.music.adapter
import android.graphics.Color
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -23,14 +36,12 @@ class GenreAdapter(
var dataSet: List<Genre>, var dataSet: List<Genre>,
private val mItemLayoutRes: Int private val mItemLayoutRes: Int
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() { ) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
val colors = listOf<Int>(Color.RED, Color.BLUE)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false)) return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val genre = dataSet[position] val genre = dataSet[position]
holder.title?.text = genre.name holder.title?.text = genre.name
holder.text?.text = String.format( holder.text?.text = String.format(
Locale.getDefault(), Locale.getDefault(),

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter package io.github.muntashirakon.music.adapter
import android.view.LayoutInflater import android.view.LayoutInflater
@ -15,23 +29,23 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.ColorUtil
import com.bumptech.glide.Glide
import com.google.android.material.card.MaterialCardView
import io.github.muntashirakon.music.* import io.github.muntashirakon.music.*
import io.github.muntashirakon.music.adapter.album.AlbumAdapter import io.github.muntashirakon.music.adapter.album.AlbumAdapter
import io.github.muntashirakon.music.adapter.artist.ArtistAdapter import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
import io.github.muntashirakon.music.adapter.song.SongAdapter import io.github.muntashirakon.music.adapter.song.SongAdapter
import io.github.muntashirakon.music.extensions.hide import io.github.muntashirakon.music.extensions.hide
import io.github.muntashirakon.music.fragments.albums.AlbumClickListener
import io.github.muntashirakon.music.fragments.artists.ArtistClickListener
import io.github.muntashirakon.music.glide.SongGlideRequest import io.github.muntashirakon.music.glide.SongGlideRequest
import io.github.muntashirakon.music.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.IAlbumClickListener
import io.github.muntashirakon.music.interfaces.IArtistClickListener
import io.github.muntashirakon.music.model.* import io.github.muntashirakon.music.model.*
import io.github.muntashirakon.music.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
import com.bumptech.glide.Glide
import com.google.android.material.card.MaterialCardView
class HomeAdapter( class HomeAdapter(
private val activity: AppCompatActivity private val activity: AppCompatActivity
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), ArtistClickListener, AlbumClickListener { ) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener {
private var list = listOf<Home>() private var list = listOf<Home>()
@ -121,7 +135,6 @@ class HomeAdapter(
viewHolder.bind(home) viewHolder.bind(home)
} }
PLAYLISTS -> { PLAYLISTS -> {
} }
} }
} }
@ -181,7 +194,6 @@ class HomeAdapter(
.asBitmap() .asBitmap()
.build() .build()
.into(itemView.findViewById(id)) .into(itemView.findViewById(id))
} }
} }
} }
@ -225,21 +237,22 @@ class HomeAdapter(
} }
fun artistsAdapter(artists: List<Artist>) = fun artistsAdapter(artists: List<Artist>) =
ArtistAdapter(activity, artists, PreferenceUtil.homeGridStyle, null, this) ArtistAdapter(activity, artists, PreferenceUtil.homeArtistGridStyle, null, this)
fun albumAdapter(albums: List<Album>) = fun albumAdapter(albums: List<Album>) =
AlbumAdapter(activity, albums, R.layout.item_image, null, this) AlbumAdapter(activity, albums, PreferenceUtil.homeAlbumGridStyle, null, this)
fun gridLayoutManager() = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false) fun gridLayoutManager() = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
fun linearLayoutManager() = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false) fun linearLayoutManager() = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
override fun onArtist(artistId: Long, imageView: ImageView) { override fun onArtist(artistId: Long, view: View) {
activity.findNavController(R.id.fragment_container).navigate( activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment, R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to artistId), bundleOf(EXTRA_ARTIST_ID to artistId),
null, null,
FragmentNavigatorExtras( FragmentNavigatorExtras(
imageView to activity.getString(R.string.transition_album_art) view to "artist"
) )
) )
} }
@ -250,7 +263,7 @@ class HomeAdapter(
bundleOf(EXTRA_ALBUM_ID to albumId), bundleOf(EXTRA_ALBUM_ID to albumId),
null, null,
FragmentNavigatorExtras( FragmentNavigatorExtras(
view to activity.getString(R.string.transition_album_art) view to "album"
) )
) )
} }

View file

@ -1,16 +1,32 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter package io.github.muntashirakon.music.adapter
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import com.bumptech.glide.Glide
import io.github.muntashirakon.music.* import io.github.muntashirakon.music.*
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import io.github.muntashirakon.music.db.PlaylistWithSongs
import io.github.muntashirakon.music.glide.AlbumGlideRequest import io.github.muntashirakon.music.glide.AlbumGlideRequest
import io.github.muntashirakon.music.glide.ArtistGlideRequest import io.github.muntashirakon.music.glide.ArtistGlideRequest
import io.github.muntashirakon.music.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
@ -19,13 +35,15 @@ import io.github.muntashirakon.music.model.*
import io.github.muntashirakon.music.model.smartplaylist.AbsSmartPlaylist import io.github.muntashirakon.music.model.smartplaylist.AbsSmartPlaylist
import io.github.muntashirakon.music.repository.PlaylistSongsLoader import io.github.muntashirakon.music.repository.PlaylistSongsLoader
import io.github.muntashirakon.music.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import com.bumptech.glide.Glide
import java.util.*
class SearchAdapter( class SearchAdapter(
private val activity: FragmentActivity, private val activity: FragmentActivity,
private var dataSet: List<Any> private var dataSet: List<Any>
) : RecyclerView.Adapter<SearchAdapter.ViewHolder>() { ) : RecyclerView.Adapter<SearchAdapter.ViewHolder>() {
fun swapDataSet(dataSet: MutableList<Any>) { fun swapDataSet(dataSet: List<Any>) {
this.dataSet = dataSet this.dataSet = dataSet
notifyDataSetChanged() notifyDataSetChanged()
} }
@ -34,7 +52,7 @@ class SearchAdapter(
if (dataSet[position] is Album) return ALBUM if (dataSet[position] is Album) return ALBUM
if (dataSet[position] is Artist) return ARTIST if (dataSet[position] is Artist) return ARTIST
if (dataSet[position] is Genre) return GENRE if (dataSet[position] is Genre) return GENRE
if (dataSet[position] is Playlist) return PLAYLIST if (dataSet[position] is PlaylistWithSongs) return PLAYLIST
return if (dataSet[position] is Song) SONG else HEADER return if (dataSet[position] is Song) SONG else HEADER
} }
@ -56,42 +74,52 @@ class SearchAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (getItemViewType(position)) { when (getItemViewType(position)) {
ALBUM -> { ALBUM -> {
val album = dataSet.get(position) as Album holder.imageTextContainer?.isVisible = true
val album = dataSet[position] as Album
holder.title?.text = album.title holder.title?.text = album.title
holder.text?.text = album.artistName holder.text?.text = album.artistName
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore().build().into(holder.image) .checkIgnoreMediaStore().build().into(holder.image)
} }
ARTIST -> { ARTIST -> {
val artist = dataSet.get(position) as Artist holder.imageTextContainer?.isVisible = true
val artist = dataSet[position] as Artist
holder.title?.text = artist.name holder.title?.text = artist.name
holder.text?.text = MusicUtil.getArtistInfoString(activity, artist) holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
ArtistGlideRequest.Builder.from(Glide.with(activity), artist).build() ArtistGlideRequest.Builder.from(Glide.with(activity), artist).build()
.into(holder.image) .into(holder.image)
} }
SONG -> { SONG -> {
val song = dataSet.get(position) as Song val song = dataSet[position] as Song
holder.title?.text = song.title holder.title?.text = song.title
holder.text?.text = song.albumName holder.text?.text = song.albumName
} }
GENRE -> { GENRE -> {
val genre = dataSet.get(position) as Genre val genre = dataSet[position] as Genre
holder.title?.text = genre.name holder.title?.text = genre.name
holder.text?.text = String.format(
Locale.getDefault(),
"%d %s",
genre.songCount,
if (genre.songCount > 1) activity.getString(R.string.songs) else activity.getString(
R.string.song
)
)
} }
PLAYLIST -> { PLAYLIST -> {
val playlist = dataSet.get(position) as Playlist val playlist = dataSet[position] as PlaylistWithSongs
holder.title?.text = playlist.name holder.title?.text = playlist.playlistEntity.playlistName
holder.text?.text = MusicUtil.getPlaylistInfoString(activity, getSongs(playlist)) holder.text?.text = MusicUtil.playlistInfoString(activity, playlist.songs)
} }
else -> { else -> {
holder.title?.text = dataSet.get(position).toString() holder.title?.text = dataSet[position].toString()
holder.title?.setTextColor(ThemeStore.accentColor(activity)) holder.title?.setTextColor(ThemeStore.accentColor(activity))
} }
} }
} }
private fun getSongs(playlist: Playlist): java.util.ArrayList<Song> { private fun getSongs(playlist: Playlist): List<Song> {
val songs = java.util.ArrayList<Song>() val songs = mutableListOf<Song>()
if (playlist is AbsSmartPlaylist) { if (playlist is AbsSmartPlaylist) {
songs.addAll(playlist.getSongs()) songs.addAll(playlist.getSongs())
} else { } else {
@ -107,7 +135,7 @@ class SearchAdapter(
inner class ViewHolder(itemView: View, itemViewType: Int) : MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View, itemViewType: Int) : MediaEntryViewHolder(itemView) {
init { init {
itemView.setOnLongClickListener(null) itemView.setOnLongClickListener(null)
imageTextContainer?.isInvisible = true
if (itemViewType == SONG) { if (itemViewType == SONG) {
menu?.visibility = View.VISIBLE menu?.visibility = View.VISIBLE
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) { menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
@ -151,12 +179,12 @@ class SearchAdapter(
} }
PLAYLIST -> { PLAYLIST -> {
activity.findNavController(R.id.fragment_container).navigate( activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment, R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to (item as Playlist)) bundleOf(EXTRA_PLAYLIST to (item as PlaylistWithSongs))
) )
} }
SONG -> { SONG -> {
val playList = ArrayList<Song>() val playList = mutableListOf<Song>()
playList.add(item as Song) playList.add(item as Song)
MusicPlayerRemote.openQueue(playList, 0, true) MusicPlayerRemote.openQueue(playList, 0, true)
} }

View file

@ -1,17 +1,16 @@
/* /*
* Copyright 2019 Google LLC * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the GNU General Public License v3
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ */
package io.github.muntashirakon.music.adapter package io.github.muntashirakon.music.adapter
@ -22,31 +21,31 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ATHUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.MediaStoreSignature
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import io.github.muntashirakon.music.glide.audiocover.AudioFileCover import io.github.muntashirakon.music.glide.audiocover.AudioFileCover
import io.github.muntashirakon.music.interfaces.CabHolder import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.interfaces.Callbacks import io.github.muntashirakon.music.interfaces.ICallbacks
import io.github.muntashirakon.music.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.RetroUtil import io.github.muntashirakon.music.util.RetroUtil
import me.zhanghai.android.fastscroll.PopupTextProvider import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.MediaStoreSignature
import java.io.File import java.io.File
import java.text.DecimalFormat import java.text.DecimalFormat
import kotlin.math.log10 import kotlin.math.log10
import kotlin.math.pow import kotlin.math.pow
import me.zhanghai.android.fastscroll.PopupTextProvider
class SongFileAdapter( class SongFileAdapter(
private val activity: AppCompatActivity, private val activity: AppCompatActivity,
private var dataSet: List<File>, private var dataSet: List<File>,
private val itemLayoutRes: Int, private val itemLayoutRes: Int,
private val callbacks: Callbacks?, private val ICallbacks: ICallbacks?,
cabHolder: CabHolder? ICabHolder: ICabHolder?
) : AbsMultiSelectAdapter<SongFileAdapter.ViewHolder, File>( ) : AbsMultiSelectAdapter<SongFileAdapter.ViewHolder, File>(
activity, cabHolder, R.menu.menu_media_selection activity, ICabHolder, R.menu.menu_media_selection
), PopupTextProvider { ), PopupTextProvider {
init { init {
@ -136,8 +135,8 @@ class SongFileAdapter(
} }
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<File>) { override fun onMultipleItemAction(menuItem: MenuItem, selection: List<File>) {
if (callbacks == null) return if (ICallbacks == null) return
callbacks.onMultipleItemAction(menuItem, selection as ArrayList<File>) ICallbacks.onMultipleItemAction(menuItem, selection as ArrayList<File>)
} }
override fun getPopupText(position: Int): String { override fun getPopupText(position: Int): String {
@ -148,15 +147,14 @@ class SongFileAdapter(
return MusicUtil.getSectionName(dataSet[position].name) return MusicUtil.getSectionName(dataSet[position].name)
} }
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init { init {
if (menu != null && callbacks != null) { if (menu != null && ICallbacks != null) {
menu?.setOnClickListener { v -> menu?.setOnClickListener { v ->
val position = layoutPosition val position = layoutPosition
if (isPositionInRange(position)) { if (isPositionInRange(position)) {
callbacks.onFileMenuClicked(dataSet[position], v) ICallbacks.onFileMenuClicked(dataSet[position], v)
} }
} }
} }
@ -171,7 +169,7 @@ class SongFileAdapter(
if (isInQuickSelectMode) { if (isInQuickSelectMode) {
toggleChecked(position) toggleChecked(position)
} else { } else {
callbacks?.onFileSelected(dataSet[position]) ICallbacks?.onFileSelected(dataSet[position])
} }
} }
} }
@ -198,4 +196,4 @@ class SongFileAdapter(
return DecimalFormat("#,##0.##").format(size / 1024.0.pow(digitGroups.toDouble())) + " " + units[digitGroups] return DecimalFormat("#,##0.##").format(size / 1024.0.pow(digitGroups.toDouble())) + " " + units[digitGroups]
} }
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter package io.github.muntashirakon.music.adapter
import android.app.Activity import android.app.Activity
@ -49,4 +63,4 @@ class TranslatorsAdapter(
image.hide() image.hide()
} }
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.album package io.github.muntashirakon.music.adapter.album
import android.content.res.ColorStateList import android.content.res.ColorStateList
@ -6,7 +20,23 @@ import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import io.github.muntashirakon.music.glide.AlbumGlideRequest
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.helper.SortOrder
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
import io.github.muntashirakon.music.interfaces.IAlbumClickListener
import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Album
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
@ -29,11 +59,11 @@ open class AlbumAdapter(
protected val activity: FragmentActivity, protected val activity: FragmentActivity,
var dataSet: List<Album>, var dataSet: List<Album>,
protected var itemLayoutRes: Int, protected var itemLayoutRes: Int,
cabHolder: CabHolder?, ICabHolder: ICabHolder?,
private val albumClickListener: AlbumClickListener? private val albumClickListener: IAlbumClickListener?
) : AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album>( ) : AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album>(
activity, activity,
cabHolder, ICabHolder,
R.menu.menu_media_selection R.menu.menu_media_selection
), PopupTextProvider { ), PopupTextProvider {
@ -75,7 +105,7 @@ open class AlbumAdapter(
holder.title?.text = getAlbumTitle(album) holder.title?.text = getAlbumTitle(album)
holder.text?.text = getAlbumText(album) holder.text?.text = getAlbumText(album)
holder.playSongs?.setOnClickListener { holder.playSongs?.setOnClickListener {
album.songs?.let { songs -> album.songs.let { songs ->
MusicPlayerRemote.openQueue( MusicPlayerRemote.openQueue(
songs, songs,
0, 0,
@ -116,7 +146,7 @@ open class AlbumAdapter(
} }
override fun getItemId(position: Int): Long { override fun getItemId(position: Int): Long {
return dataSet[position].id.toLong() return dataSet[position].id
} }
override fun getIdentifier(position: Int): Album? { override fun getIdentifier(position: Int): Album? {
@ -128,7 +158,8 @@ open class AlbumAdapter(
} }
override fun onMultipleItemAction( override fun onMultipleItemAction(
menuItem: MenuItem, selection: List<Album> menuItem: MenuItem,
selection: List<Album>
) { ) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId) SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
} }
@ -161,7 +192,7 @@ open class AlbumAdapter(
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init { init {
setImageTransitionName(activity.getString(R.string.transition_album_art)) setImageTransitionName("Album")
menu?.visibility = View.GONE menu?.visibility = View.GONE
} }
@ -170,6 +201,7 @@ open class AlbumAdapter(
if (isInQuickSelectMode) { if (isInQuickSelectMode) {
toggleChecked(layoutPosition) toggleChecked(layoutPosition)
} else { } else {
ViewCompat.setTransitionName(itemView, "album")
albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, itemView) albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, itemView)
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.album package io.github.muntashirakon.music.adapter.album
import android.os.Bundle import android.os.Bundle
@ -5,6 +19,7 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@ -88,9 +103,9 @@ class AlbumCoverPagerAdapter(
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false) val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
ViewCompat.setTransitionName(view, "lyrics")
albumCover = view.findViewById(R.id.player_image) albumCover = view.findViewById(R.id.player_image)
albumCover.setOnClickListener { view.setOnClickListener {
//LyricsDialog().show(childFragmentManager, "LyricsDialog")
showLyricsDialog() showLyricsDialog()
} }
return view return view
@ -98,14 +113,14 @@ class AlbumCoverPagerAdapter(
private fun showLyricsDialog() { private fun showLyricsDialog() {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val data: String = MusicUtil.getLyrics(song) ?: "No lyrics found" val data: String? = MusicUtil.getLyrics(song)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
MaterialAlertDialogBuilder( MaterialAlertDialogBuilder(
requireContext(), requireContext(),
R.style.ThemeOverlay_MaterialComponents_Dialog_Alert R.style.ThemeOverlay_MaterialComponents_Dialog_Alert
).apply { ).apply {
setTitle(song.title) setTitle(song.title)
setMessage(data) setMessage(if (data.isNullOrEmpty()) "No lyrics found" else data)
setNegativeButton(R.string.synced_lyrics) { _, _ -> setNegativeButton(R.string.synced_lyrics) { _, _ ->
NavigationUtil.goToLyrics(requireActivity()) NavigationUtil.goToLyrics(requireActivity())
} }
@ -197,4 +212,3 @@ class AlbumCoverPagerAdapter(
val TAG: String = AlbumCoverPagerAdapter::class.java.simpleName val TAG: String = AlbumCoverPagerAdapter::class.java.simpleName
} }
} }

View file

@ -1,13 +1,27 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.album package io.github.muntashirakon.music.adapter.album
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import io.github.muntashirakon.music.fragments.albums.AlbumClickListener
import io.github.muntashirakon.music.glide.AlbumGlideRequest import io.github.muntashirakon.music.glide.AlbumGlideRequest
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import io.github.muntashirakon.music.helper.HorizontalAdapterHelper import io.github.muntashirakon.music.helper.HorizontalAdapterHelper
import io.github.muntashirakon.music.interfaces.CabHolder import io.github.muntashirakon.music.interfaces.IAlbumClickListener
import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Album import io.github.muntashirakon.music.model.Album
import io.github.muntashirakon.music.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
@ -16,10 +30,10 @@ import com.bumptech.glide.Glide
class HorizontalAlbumAdapter( class HorizontalAlbumAdapter(
activity: FragmentActivity, activity: FragmentActivity,
dataSet: List<Album>, dataSet: List<Album>,
cabHolder: CabHolder?, ICabHolder: ICabHolder?,
albumClickListener: AlbumClickListener albumClickListener: IAlbumClickListener
) : AlbumAdapter( ) : AlbumAdapter(
activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, cabHolder, albumClickListener activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, ICabHolder, albumClickListener
) { ) {
override fun createViewHolder(view: View, viewType: Int): ViewHolder { override fun createViewHolder(view: View, viewType: Int): ViewHolder {
@ -29,8 +43,8 @@ class HorizontalAlbumAdapter(
} }
override fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) { override fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) {
//holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary)) // holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
//holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary)) // holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
} }
override fun loadAlbumCover(album: Album, holder: ViewHolder) { override fun loadAlbumCover(album: Album, holder: ViewHolder) {
@ -51,7 +65,7 @@ class HorizontalAlbumAdapter(
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return HorizontalAdapterHelper.getItemViewtype(position, itemCount) return HorizontalAdapterHelper.getItemViewType(position, itemCount)
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.artist package io.github.muntashirakon.music.adapter.artist
import android.content.res.ColorStateList import android.content.res.ColorStateList
@ -8,31 +22,31 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import com.bumptech.glide.Glide
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import io.github.muntashirakon.music.extensions.hide import io.github.muntashirakon.music.extensions.hide
import io.github.muntashirakon.music.fragments.artists.ArtistClickListener
import io.github.muntashirakon.music.glide.ArtistGlideRequest import io.github.muntashirakon.music.glide.ArtistGlideRequest
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
import io.github.muntashirakon.music.interfaces.CabHolder import io.github.muntashirakon.music.interfaces.IArtistClickListener
import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Artist import io.github.muntashirakon.music.model.Artist
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
import me.zhanghai.android.fastscroll.PopupTextProvider import com.bumptech.glide.Glide
import java.util.* import java.util.*
import me.zhanghai.android.fastscroll.PopupTextProvider
class ArtistAdapter( class ArtistAdapter(
val activity: FragmentActivity, val activity: FragmentActivity,
var dataSet: List<Artist>, var dataSet: List<Artist>,
var itemLayoutRes: Int, var itemLayoutRes: Int,
cabHolder: CabHolder?, val ICabHolder: ICabHolder?,
private val artistClickListener: ArtistClickListener val IArtistClickListener: IArtistClickListener
) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>( ) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>(
activity, cabHolder, R.menu.menu_media_selection activity, ICabHolder, R.menu.menu_media_selection
), PopupTextProvider { ), PopupTextProvider {
init { init {
@ -45,7 +59,7 @@ class ArtistAdapter(
} }
override fun getItemId(position: Int): Long { override fun getItemId(position: Int): Long {
return dataSet[position].id.toLong() return dataSet[position].id
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -107,7 +121,8 @@ class ArtistAdapter(
} }
override fun onMultipleItemAction( override fun onMultipleItemAction(
menuItem: MenuItem, selection: List<Artist> menuItem: MenuItem,
selection: List<Artist>
) { ) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId) SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
} }
@ -140,11 +155,8 @@ class ArtistAdapter(
toggleChecked(layoutPosition) toggleChecked(layoutPosition)
} else { } else {
image?.let { image?.let {
ViewCompat.setTransitionName( ViewCompat.setTransitionName(itemView, "album")
it, IArtistClickListener.onArtist(dataSet[layoutPosition].id, itemView)
activity.getString(R.string.transition_artist_image)
)
artistClickListener.onArtist(dataSet[layoutPosition].id, it)
} }
} }
} }

View file

@ -3,132 +3,127 @@ package io.github.muntashirakon.music.adapter.base;
import android.content.Context; import android.content.Context;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import androidx.annotation.MenuRes; import androidx.annotation.MenuRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import io.github.muntashirakon.music.R;
import io.github.muntashirakon.music.interfaces.ICabHolder;
import com.afollestad.materialcab.MaterialCab; import com.afollestad.materialcab.MaterialCab;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import io.github.muntashirakon.music.R; public abstract class AbsMultiSelectAdapter<V extends RecyclerView.ViewHolder, I>
import io.github.muntashirakon.music.interfaces.CabHolder; extends RecyclerView.Adapter<V> implements MaterialCab.Callback {
@Nullable private final ICabHolder ICabHolder;
private final Context context;
private MaterialCab cab;
private List<I> checked;
private int menuRes;
public abstract class AbsMultiSelectAdapter<V extends RecyclerView.ViewHolder, I> extends RecyclerView.Adapter<V> public AbsMultiSelectAdapter(
implements MaterialCab.Callback { @NonNull Context context, @Nullable ICabHolder ICabHolder, @MenuRes int menuRes) {
this.ICabHolder = ICabHolder;
checked = new ArrayList<>();
this.menuRes = menuRes;
this.context = context;
}
@Nullable @Override
private final CabHolder cabHolder; public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
private final Context context; return true;
private MaterialCab cab; }
private List<I> checked;
private int menuRes;
public AbsMultiSelectAdapter(@NonNull Context context, @Nullable CabHolder cabHolder, @MenuRes int menuRes) { @Override
this.cabHolder = cabHolder; public boolean onCabFinished(MaterialCab materialCab) {
checked = new ArrayList<>(); clearChecked();
this.menuRes = menuRes; return true;
this.context = context; }
@Override
public boolean onCabItemClicked(MenuItem menuItem) {
if (menuItem.getItemId() == R.id.action_multi_select_adapter_check_all) {
checkAll();
} else {
onMultipleItemAction(menuItem, new ArrayList<>(checked));
cab.finish();
clearChecked();
} }
return true;
}
@Override protected void checkAll() {
public boolean onCabCreated(MaterialCab materialCab, Menu menu) { if (ICabHolder != null) {
return true; checked.clear();
} for (int i = 0; i < getItemCount(); i++) {
I identifier = getIdentifier(i);
@Override if (identifier != null) {
public boolean onCabFinished(MaterialCab materialCab) { checked.add(identifier);
clearChecked();
return true;
}
@Override
public boolean onCabItemClicked(MenuItem menuItem) {
if (menuItem.getItemId() == R.id.action_multi_select_adapter_check_all) {
checkAll();
} else {
onMultipleItemAction(menuItem, new ArrayList<>(checked));
cab.finish();
clearChecked();
} }
return true; }
notifyDataSetChanged();
updateCab();
} }
}
protected void checkAll() { @Nullable
if (cabHolder != null) { protected abstract I getIdentifier(int position);
checked.clear();
for (int i = 0; i < getItemCount(); i++) {
I identifier = getIdentifier(i);
if (identifier != null) {
checked.add(identifier);
}
}
notifyDataSetChanged();
updateCab();
}
}
@Nullable protected String getName(I object) {
protected abstract I getIdentifier(int position); return object.toString();
}
protected String getName(I object) { protected boolean isChecked(I identifier) {
return object.toString(); return checked.contains(identifier);
} }
protected boolean isChecked(I identifier) { protected boolean isInQuickSelectMode() {
return checked.contains(identifier); return cab != null && cab.isActive();
} }
protected boolean isInQuickSelectMode() { protected abstract void onMultipleItemAction(MenuItem menuItem, List<I> selection);
return cab != null && cab.isActive();
}
protected abstract void onMultipleItemAction(MenuItem menuItem, List<I> selection); protected void setMultiSelectMenuRes(@MenuRes int menuRes) {
this.menuRes = menuRes;
}
protected void setMultiSelectMenuRes(@MenuRes int menuRes) { protected boolean toggleChecked(final int position) {
this.menuRes = menuRes; if (ICabHolder != null) {
} I identifier = getIdentifier(position);
if (identifier == null) {
protected boolean toggleChecked(final int position) {
if (cabHolder != null) {
I identifier = getIdentifier(position);
if (identifier == null) {
return false;
}
if (!checked.remove(identifier)) {
checked.add(identifier);
}
notifyItemChanged(position);
updateCab();
return true;
}
return false; return false;
} }
private void clearChecked() { if (!checked.remove(identifier)) {
checked.clear(); checked.add(identifier);
notifyDataSetChanged(); }
}
private void updateCab() { notifyItemChanged(position);
if (cabHolder != null) { updateCab();
if (cab == null || !cab.isActive()) { return true;
cab = cabHolder.openCab(menuRes, this);
}
final int size = checked.size();
if (size <= 0) {
cab.finish();
} else if (size == 1) {
cab.setTitle(getName(checked.get(0)));
} else {
cab.setTitle(context.getString(R.string.x_selected, size));
}
}
} }
return false;
}
private void clearChecked() {
checked.clear();
notifyDataSetChanged();
}
private void updateCab() {
if (ICabHolder != null) {
if (cab == null || !cab.isActive()) {
cab = ICabHolder.openCab(menuRes, this);
}
final int size = checked.size();
if (size <= 0) {
cab.finish();
} else if (size == 1) {
cab.setTitle(getName(checked.get(0)));
} else {
cab.setTitle(context.getString(R.string.x_selected, size));
}
}
}
} }

View file

@ -16,126 +16,104 @@ package io.github.muntashirakon.music.adapter.base;
import android.graphics.Color; import android.graphics.Color;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import io.github.muntashirakon.music.R;
import com.google.android.material.card.MaterialCardView; import com.google.android.material.card.MaterialCardView;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableSwipeableItemViewHolder; import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableSwipeableItemViewHolder;
import io.github.muntashirakon.music.R;
public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHolder public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHolder
implements View.OnLongClickListener, View.OnClickListener { implements View.OnLongClickListener, View.OnClickListener {
@Nullable @Nullable public View dragView;
public View dragView;
@Nullable @Nullable public View dummyContainer;
public View dummyContainer;
@Nullable @Nullable public ImageView image;
public ImageView image;
@Nullable
public ImageView artistImage;
@Nullable @Nullable public ImageView artistImage;
public ImageView playerImage;
@Nullable @Nullable public ImageView playerImage;
public ViewGroup imageContainer;
@Nullable @Nullable public MaterialCardView imageContainerCard;
public MaterialCardView imageContainerCard;
@Nullable @Nullable public TextView imageText;
public TextView imageText;
@Nullable @Nullable public MaterialCardView imageTextContainer;
public MaterialCardView imageTextContainer;
@Nullable @Nullable public View mask;
public View mask;
@Nullable @Nullable public View menu;
public View menu;
@Nullable @Nullable public View paletteColorContainer;
public View paletteColorContainer;
@Nullable @Nullable public ImageButton playSongs;
public ImageButton playSongs;
@Nullable @Nullable public RecyclerView recyclerView;
public RecyclerView recyclerView;
@Nullable @Nullable public TextView text;
public TextView text;
@Nullable @Nullable public TextView text2;
public TextView time;
@Nullable @Nullable public TextView time;
public TextView title;
public MediaEntryViewHolder(@NonNull View itemView) { @Nullable public TextView title;
super(itemView);
title = itemView.findViewById(R.id.title);
text = itemView.findViewById(R.id.text);
image = itemView.findViewById(R.id.image); public MediaEntryViewHolder(@NonNull View itemView) {
artistImage = itemView.findViewById(R.id.artistImage); super(itemView);
playerImage = itemView.findViewById(R.id.player_image); title = itemView.findViewById(R.id.title);
time = itemView.findViewById(R.id.time); text = itemView.findViewById(R.id.text);
text2 = itemView.findViewById(R.id.text2);
imageText = itemView.findViewById(R.id.imageText); image = itemView.findViewById(R.id.image);
imageContainer = itemView.findViewById(R.id.imageContainer); artistImage = itemView.findViewById(R.id.artistImage);
imageTextContainer = itemView.findViewById(R.id.imageTextContainer); playerImage = itemView.findViewById(R.id.player_image);
imageContainerCard = itemView.findViewById(R.id.imageContainerCard); time = itemView.findViewById(R.id.time);
menu = itemView.findViewById(R.id.menu); imageText = itemView.findViewById(R.id.imageText);
dragView = itemView.findViewById(R.id.drag_view); imageTextContainer = itemView.findViewById(R.id.imageTextContainer);
paletteColorContainer = itemView.findViewById(R.id.paletteColorContainer); imageContainerCard = itemView.findViewById(R.id.imageContainerCard);
recyclerView = itemView.findViewById(R.id.recycler_view);
mask = itemView.findViewById(R.id.mask);
playSongs = itemView.findViewById(R.id.playSongs);
dummyContainer = itemView.findViewById(R.id.dummy_view);
if (imageContainerCard != null) { menu = itemView.findViewById(R.id.menu);
imageContainerCard.setCardBackgroundColor(Color.TRANSPARENT); dragView = itemView.findViewById(R.id.drag_view);
} paletteColorContainer = itemView.findViewById(R.id.paletteColorContainer);
itemView.setOnClickListener(this); recyclerView = itemView.findViewById(R.id.recycler_view);
itemView.setOnLongClickListener(this); mask = itemView.findViewById(R.id.mask);
playSongs = itemView.findViewById(R.id.playSongs);
dummyContainer = itemView.findViewById(R.id.dummy_view);
if (imageContainerCard != null) {
imageContainerCard.setCardBackgroundColor(Color.TRANSPARENT);
} }
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
@Nullable @Nullable
@Override @Override
public View getSwipeableContainerView() { public View getSwipeableContainerView() {
return null; return null;
} }
@Override @Override
public void onClick(View v) { public void onClick(View v) {}
} @Override
public boolean onLongClick(View v) {
@Override return false;
public boolean onLongClick(View v) { }
return false;
} public void setImageTransitionName(@NonNull String transitionName) {
itemView.setTransitionName(transitionName);
public void setImageTransitionName(@NonNull String transitionName) { /* if (imageContainerCard != null) {
itemView.setTransitionName(transitionName); imageContainerCard.setTransitionName(transitionName);
/* if (imageContainerCard != null) {
imageContainerCard.setTransitionName(transitionName);
}
if (image != null) {
image.setTransitionName(transitionName);
}*/
} }
if (image != null) {
image.setTransitionName(transitionName);
}*/
}
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.playlist package io.github.muntashirakon.music.adapter.playlist
import android.view.LayoutInflater import android.view.LayoutInflater
@ -49,4 +63,4 @@ class LegacyPlaylistAdapter(
interface PlaylistClickListener { interface PlaylistClickListener {
fun onPlaylistClick(playlist: Playlist) fun onPlaylistClick(playlist: Playlist)
} }
} }

View file

@ -1,21 +1,32 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.playlist package io.github.muntashirakon.music.adapter.playlist
import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.AsyncTask
import android.text.TextUtils import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.os.bundleOf import androidx.core.view.ViewCompat
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController import androidx.lifecycle.lifecycleScope
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
import io.github.muntashirakon.music.EXTRA_PLAYLIST
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
@ -27,22 +38,25 @@ import io.github.muntashirakon.music.extensions.hide
import io.github.muntashirakon.music.extensions.show import io.github.muntashirakon.music.extensions.show
import io.github.muntashirakon.music.helper.menu.PlaylistMenuHelper import io.github.muntashirakon.music.helper.menu.PlaylistMenuHelper
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
import io.github.muntashirakon.music.interfaces.CabHolder import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Playlist import io.github.muntashirakon.music.interfaces.IPlaylistClickListener
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.repository.PlaylistSongsLoader
import io.github.muntashirakon.music.util.AutoGeneratedPlaylistBitmap import io.github.muntashirakon.music.util.AutoGeneratedPlaylistBitmap
import io.github.muntashirakon.music.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.RetroColorUtil import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class PlaylistAdapter( class PlaylistAdapter(
private val activity: FragmentActivity, private val activity: FragmentActivity,
var dataSet: List<PlaylistWithSongs>, private var dataSet: List<PlaylistWithSongs>,
private var itemLayoutRes: Int, private var itemLayoutRes: Int,
cabHolder: CabHolder? ICabHolder: ICabHolder?,
private val listener: IPlaylistClickListener
) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, PlaylistWithSongs>( ) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, PlaylistWithSongs>(
activity, activity,
cabHolder, ICabHolder,
R.menu.menu_playlists_selection R.menu.menu_playlists_selection
) { ) {
@ -56,7 +70,7 @@ class PlaylistAdapter(
} }
override fun getItemId(position: Int): Long { override fun getItemId(position: Int): Long {
return dataSet[position].playlistEntity.playListId.toLong() return dataSet[position].playlistEntity.playListId
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -88,7 +102,7 @@ class PlaylistAdapter(
} else { } else {
holder.menu?.show() holder.menu?.show()
} }
//PlaylistBitmapLoader(this, holder, playlist).execute() //playlistBitmapLoader(activity, holder, playlist)
} }
private fun getIconRes(): Drawable = TintHelper.createTintedDrawable( private fun getIconRes(): Drawable = TintHelper.createTintedDrawable(
@ -158,10 +172,8 @@ class PlaylistAdapter(
if (isInQuickSelectMode) { if (isInQuickSelectMode) {
toggleChecked(layoutPosition) toggleChecked(layoutPosition)
} else { } else {
activity.findNavController(R.id.fragment_container).navigate( ViewCompat.setTransitionName(itemView, "playlist")
R.id.playlistDetailsFragment, listener.onPlaylistClick(dataSet[layoutPosition], itemView)
bundleOf(EXTRA_PLAYLIST to dataSet[layoutPosition])
)
} }
} }
@ -171,28 +183,35 @@ class PlaylistAdapter(
} }
} }
class PlaylistBitmapLoader( private fun playlistBitmapLoader(
private var adapter: PlaylistAdapter, activity: FragmentActivity,
private var viewHolder: ViewHolder, viewHolder: ViewHolder,
private var playlist: Playlist playlist: PlaylistWithSongs
) : AsyncTask<Void, Void, Bitmap>() { ) {
override fun doInBackground(vararg params: Void?): Bitmap { activity.lifecycleScope.launch(IO) {
val songs = PlaylistSongsLoader.getPlaylistSongList(adapter.activity, playlist) val songs = playlist.songs.toSongs()
return AutoGeneratedPlaylistBitmap.getBitmap(adapter.activity, songs, false, false) val bitmap = AutoGeneratedPlaylistBitmap.getBitmap(activity, songs, false, false)
withContext(Main) { viewHolder.image?.setImageBitmap(bitmap) }
} }
override fun onPostExecute(result: Bitmap?) { /*
super.onPostExecute(result) override fun doInBackground(vararg params: Void?): Bitmap {
viewHolder.image?.setImageBitmap(result) val songs = playlist.songs.toSongs()
val color = RetroColorUtil.getColor( return AutoGeneratedPlaylistBitmap.getBitmap(activity, songs, false, false)
RetroColorUtil.generatePalette( }
result
), override fun onPostExecute(result: Bitmap?) {
ATHUtil.resolveColor(adapter.activity, R.attr.colorSurface) super.onPostExecute(result)
) viewHolder.image?.setImageBitmap(result)
viewHolder.paletteColorContainer?.setBackgroundColor(color) val color = RetroColorUtil.getColor(
} RetroColorUtil.generatePalette(
result
),
ATHUtil.resolveColor(activity, R.attr.colorSurface)
)
viewHolder.paletteColorContainer?.setBackgroundColor(color)
}*/
} }
companion object { companion object {

View file

@ -1,21 +1,35 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.song package io.github.muntashirakon.music.adapter.song
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.FragmentActivity
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.CabHolder import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
abstract class AbsOffsetSongAdapter( abstract class AbsOffsetSongAdapter(
activity: AppCompatActivity, activity: FragmentActivity,
dataSet: MutableList<Song>, dataSet: MutableList<Song>,
@LayoutRes itemLayoutRes: Int, @LayoutRes itemLayoutRes: Int,
cabHolder: CabHolder? ICabHolder: ICabHolder?
) : SongAdapter(activity, dataSet, itemLayoutRes, cabHolder) { ) : SongAdapter(activity, dataSet, itemLayoutRes, ICabHolder) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder {
if (viewType == OFFSET_ITEM) { if (viewType == OFFSET_ITEM) {
@ -76,4 +90,4 @@ abstract class AbsOffsetSongAdapter(
const val OFFSET_ITEM = 0 const val OFFSET_ITEM = 0
const val SONG = 1 const val SONG = 1
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.song package io.github.muntashirakon.music.adapter.song
import android.view.MenuItem import android.view.MenuItem
@ -9,7 +23,7 @@ import io.github.muntashirakon.music.db.PlaylistEntity
import io.github.muntashirakon.music.db.toSongEntity import io.github.muntashirakon.music.db.toSongEntity
import io.github.muntashirakon.music.db.toSongs import io.github.muntashirakon.music.db.toSongs
import io.github.muntashirakon.music.dialogs.RemoveSongFromPlaylistDialog import io.github.muntashirakon.music.dialogs.RemoveSongFromPlaylistDialog
import io.github.muntashirakon.music.interfaces.CabHolder import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.PlaylistSong import io.github.muntashirakon.music.model.PlaylistSong
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.ViewUtil import io.github.muntashirakon.music.util.ViewUtil
@ -23,13 +37,13 @@ class OrderablePlaylistSongAdapter(
activity: FragmentActivity, activity: FragmentActivity,
dataSet: ArrayList<Song>, dataSet: ArrayList<Song>,
itemLayoutRes: Int, itemLayoutRes: Int,
cabHolder: CabHolder?, ICabHolder: ICabHolder?,
private val onMoveItemListener: OnMoveItemListener? private val onMoveItemListener: OnMoveItemListener?
) : SongAdapter( ) : SongAdapter(
activity, activity,
dataSet, dataSet,
itemLayoutRes, itemLayoutRes,
cabHolder ICabHolder
), DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> { ), DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
init { init {

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.song package io.github.muntashirakon.music.adapter.song
import android.view.MenuItem import android.view.MenuItem
@ -5,6 +19,8 @@ import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import io.github.muntashirakon.music.glide.SongGlideRequest
import io.github.muntashirakon.music.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.helper.MusicPlayerRemote.isPlaying import io.github.muntashirakon.music.helper.MusicPlayerRemote.isPlaying
import io.github.muntashirakon.music.helper.MusicPlayerRemote.playNextSong import io.github.muntashirakon.music.helper.MusicPlayerRemote.playNextSong
@ -12,6 +28,8 @@ import io.github.muntashirakon.music.helper.MusicPlayerRemote.removeFromQueue
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.ViewUtil import io.github.muntashirakon.music.util.ViewUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
@ -41,8 +59,8 @@ class PlayingQueueAdapter(
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) { override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
super.onBindViewHolder(holder, position) super.onBindViewHolder(holder, position)
holder.imageText?.text = (position - current).toString() val song = dataSet[position]
holder.time?.text = MusicUtil.getReadableDurationString(dataSet[position].duration) holder.time?.text = MusicUtil.getReadableDurationString(song.duration)
if (holder.itemViewType == HISTORY || holder.itemViewType == CURRENT) { if (holder.itemViewType == HISTORY || holder.itemViewType == CURRENT) {
setAlpha(holder, 0.5f) setAlpha(holder, 0.5f)
} }
@ -58,7 +76,17 @@ class PlayingQueueAdapter(
} }
override fun loadAlbumCover(song: Song, holder: SongAdapter.ViewHolder) { override fun loadAlbumCover(song: Song, holder: SongAdapter.ViewHolder) {
// We don't want to load it in this adapter if (holder.image == null) {
return
}
SongGlideRequest.Builder.from(Glide.with(activity), song)
.checkIgnoreMediaStore(activity)
.generatePalette(activity).build()
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onColorReady(colors: MediaNotificationProcessor) {
//setColors(colors, holder)
}
})
} }
fun swapDataSet(dataSet: List<Song>, position: Int) { fun swapDataSet(dataSet: List<Song>, position: Int) {
@ -76,7 +104,6 @@ class PlayingQueueAdapter(
holder.image?.alpha = alpha holder.image?.alpha = alpha
holder.title?.alpha = alpha holder.title?.alpha = alpha
holder.text?.alpha = alpha holder.text?.alpha = alpha
holder.imageText?.alpha = alpha
holder.paletteColorContainer?.alpha = alpha holder.paletteColorContainer?.alpha = alpha
holder.dragView?.alpha = alpha holder.dragView?.alpha = alpha
holder.menu?.alpha = alpha holder.menu?.alpha = alpha
@ -129,7 +156,6 @@ class PlayingQueueAdapter(
} }
init { init {
imageText?.visibility = View.VISIBLE
dragView?.visibility = View.VISIBLE dragView?.visibility = View.VISIBLE
} }
@ -173,7 +199,7 @@ class PlayingQueueAdapter(
} }
override fun onGetSwipeReactionType(holder: ViewHolder, position: Int, x: Int, y: Int): Int { override fun onGetSwipeReactionType(holder: ViewHolder, position: Int, x: Int, y: Int): Int {
return if (onCheckCanStartDrag(holder!!, position, x, y)) { return if (onCheckCanStartDrag(holder, position, x, y)) {
SwipeableItemConstants.REACTION_CAN_NOT_SWIPE_BOTH_H SwipeableItemConstants.REACTION_CAN_NOT_SWIPE_BOTH_H
} else { } else {
SwipeableItemConstants.REACTION_CAN_SWIPE_BOTH_H SwipeableItemConstants.REACTION_CAN_SWIPE_BOTH_H
@ -196,17 +222,17 @@ class PlayingQueueAdapter(
private val isPlaying: Boolean = MusicPlayerRemote.isPlaying private val isPlaying: Boolean = MusicPlayerRemote.isPlaying
private val songProgressMillis = 0 private val songProgressMillis = 0
override fun onPerformAction() { override fun onPerformAction() {
//currentlyShownSnackbar = null // currentlyShownSnackbar = null
} }
override fun onSlideAnimationEnd() { override fun onSlideAnimationEnd() {
//initializeSnackBar(adapter, position, activity, isPlaying) // initializeSnackBar(adapter, position, activity, isPlaying)
songToRemove = adapter.dataSet[position] songToRemove = adapter.dataSet[position]
//If song removed was the playing song, then play the next song // If song removed was the playing song, then play the next song
if (isPlaying(songToRemove!!)) { if (isPlaying(songToRemove!!)) {
playNextSong() playNextSong()
} }
//Swipe animation is much smoother when we do the heavy lifting after it's completed // Swipe animation is much smoother when we do the heavy lifting after it's completed
adapter.setSongToRemove(songToRemove!!) adapter.setSongToRemove(songToRemove!!)
removeFromQueue(songToRemove!!) removeFromQueue(songToRemove!!)
} }

View file

@ -1,23 +1,37 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.song package io.github.muntashirakon.music.adapter.song
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.FragmentActivity
import androidx.core.os.bundleOf
import androidx.navigation.findNavController
import com.google.android.material.button.MaterialButton
import io.github.muntashirakon.music.EXTRA_ALBUM_ID
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.helper.MusicPlayerRemote import com.google.android.material.button.MaterialButton
import io.github.muntashirakon.music.interfaces.CabHolder import io.github.muntashirakon.music.db.PlaylistEntity
import io.github.muntashirakon.music.db.toSongEntity
import io.github.muntashirakon.music.dialogs.RemoveSongFromPlaylistDialog
import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
open class PlaylistSongAdapter( open class PlaylistSongAdapter(
activity: AppCompatActivity, private val playlist: PlaylistEntity,
activity: FragmentActivity,
dataSet: MutableList<Song>, dataSet: MutableList<Song>,
itemLayoutRes: Int, itemLayoutRes: Int,
cabHolder: CabHolder? ICabHolder: ICabHolder?
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) { ) : SongAdapter(activity, dataSet, itemLayoutRes, ICabHolder) {
init { init {
this.setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection) this.setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection)
@ -27,45 +41,23 @@ open class PlaylistSongAdapter(
return ViewHolder(view) return ViewHolder(view)
} }
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) { open inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) {
if (holder.itemViewType == OFFSET_ITEM) {
val viewHolder = holder as ViewHolder
viewHolder.playAction?.let {
it.setOnClickListener {
MusicPlayerRemote.openQueue(dataSet, 0, true)
}
}
viewHolder.shuffleAction?.let {
it.setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
}
}
} else {
super.onBindViewHolder(holder, position - 1)
}
}
open inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) {
val playAction: MaterialButton? = itemView.findViewById(R.id.playAction)
val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction)
override var songMenuRes: Int override var songMenuRes: Int
get() = R.menu.menu_item_cannot_delete_single_songs_playlist_song get() = R.menu.menu_item_playlist_song
set(value) { set(value) {
super.songMenuRes = value super.songMenuRes = value
} }
override fun onSongMenuItemClick(item: MenuItem): Boolean { override fun onSongMenuItemClick(item: MenuItem): Boolean {
if (item.itemId == R.id.action_go_to_album) { when (item.itemId) {
activity.findNavController(R.id.fragment_container) R.id.action_remove_from_playlist -> {
.navigate( RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlist.playListId))
R.id.albumDetailsFragment, .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
bundleOf(EXTRA_ALBUM_ID to song.albumId) return true
) }
return true
} }
return super.onSongMenuItemClick(item) return super.onSongMenuItemClick(item)
} }
} }
} }

View file

@ -1,10 +1,24 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.song package io.github.muntashirakon.music.adapter.song
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.CabHolder import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
@ -12,8 +26,8 @@ class ShuffleButtonSongAdapter(
activity: AppCompatActivity, activity: AppCompatActivity,
dataSet: MutableList<Song>, dataSet: MutableList<Song>,
itemLayoutRes: Int, itemLayoutRes: Int,
cabHolder: CabHolder? ICabHolder: ICabHolder?
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) { ) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, ICabHolder) {
override fun createViewHolder(view: View): SongAdapter.ViewHolder { override fun createViewHolder(view: View): SongAdapter.ViewHolder {
return ViewHolder(view) return ViewHolder(view)
@ -49,4 +63,4 @@ class ShuffleButtonSongAdapter(
super.onClick(v) super.onClick(v)
} }
} }
} }

View file

@ -1,9 +1,23 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.song package io.github.muntashirakon.music.adapter.song
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import io.github.muntashirakon.music.interfaces.CabHolder import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import java.util.* import java.util.*
@ -12,8 +26,8 @@ class SimpleSongAdapter(
context: FragmentActivity, context: FragmentActivity,
songs: ArrayList<Song>, songs: ArrayList<Song>,
layoutRes: Int, layoutRes: Int,
cabHolder: CabHolder? ICabHolder: ICabHolder?
) : SongAdapter(context, songs, layoutRes, cabHolder) { ) : SongAdapter(context, songs, layoutRes, ICabHolder) {
override fun swapDataSet(dataSet: List<Song>) { override fun swapDataSet(dataSet: List<Song>) {
this.dataSet = dataSet.toMutableList() this.dataSet = dataSet.toMutableList()

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.adapter.song package io.github.muntashirakon.music.adapter.song
import android.content.res.ColorStateList import android.content.res.ColorStateList
@ -7,10 +21,9 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController import androidx.navigation.findNavController
import com.afollestad.materialcab.MaterialCab
import com.bumptech.glide.Glide
import io.github.muntashirakon.music.EXTRA_ALBUM_ID import io.github.muntashirakon.music.EXTRA_ALBUM_ID
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
@ -23,11 +36,13 @@ import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.helper.SortOrder import io.github.muntashirakon.music.helper.SortOrder
import io.github.muntashirakon.music.helper.menu.SongMenuHelper import io.github.muntashirakon.music.helper.menu.SongMenuHelper
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
import io.github.muntashirakon.music.interfaces.CabHolder import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
import com.afollestad.materialcab.MaterialCab
import com.bumptech.glide.Glide
import me.zhanghai.android.fastscroll.PopupTextProvider import me.zhanghai.android.fastscroll.PopupTextProvider
/** /**
@ -38,11 +53,11 @@ open class SongAdapter(
protected val activity: FragmentActivity, protected val activity: FragmentActivity,
var dataSet: MutableList<Song>, var dataSet: MutableList<Song>,
protected var itemLayoutRes: Int, protected var itemLayoutRes: Int,
cabHolder: CabHolder?, ICabHolder: ICabHolder?,
showSectionName: Boolean = true showSectionName: Boolean = true
) : AbsMultiSelectAdapter<SongAdapter.ViewHolder, Song>( ) : AbsMultiSelectAdapter<SongAdapter.ViewHolder, Song>(
activity, activity,
cabHolder, ICabHolder,
R.menu.menu_media_selection R.menu.menu_media_selection
), MaterialCab.Callback, PopupTextProvider { ), MaterialCab.Callback, PopupTextProvider {
@ -59,7 +74,7 @@ open class SongAdapter(
} }
override fun getItemId(position: Int): Long { override fun getItemId(position: Int): Long {
return dataSet[position].id.toLong() return dataSet[position].id
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -87,6 +102,7 @@ open class SongAdapter(
} }
holder.title?.text = getSongTitle(song) holder.title?.text = getSongTitle(song)
holder.text?.text = getSongText(song) holder.text?.text = getSongText(song)
holder.text2?.text = getSongText(song)
loadAlbumCover(song, holder) loadAlbumCover(song, holder)
} }
@ -121,6 +137,10 @@ open class SongAdapter(
return song.artistName return song.artistName
} }
private fun getSongText2(song: Song): String? {
return song.albumName
}
override fun getItemCount(): Int { override fun getItemCount(): Int {
return dataSet.size return dataSet.size
} }
@ -157,7 +177,6 @@ open class SongAdapter(
get() = dataSet[layoutPosition] get() = dataSet[layoutPosition]
init { init {
setImageTransitionName(activity.getString(R.string.transition_album_art))
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) { menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
override val song: Song override val song: Song
get() = this@ViewHolder.song get() = this@ViewHolder.song
@ -172,7 +191,7 @@ open class SongAdapter(
} }
protected open fun onSongMenuItemClick(item: MenuItem): Boolean { protected open fun onSongMenuItemClick(item: MenuItem): Boolean {
if (image != null && image!!.visibility == View.VISIBLE) { if (image != null && image!!.isVisible) {
when (item.itemId) { when (item.itemId) {
R.id.action_go_to_album -> { R.id.action_go_to_album -> {
activity.findNavController(R.id.fragment_container) activity.findNavController(R.id.fragment_container)

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appshortcuts package io.github.muntashirakon.music.appshortcuts
import android.content.Context import android.content.Context
@ -60,7 +60,10 @@ object AppShortcutIconGenerator {
} }
private fun generateThemedIcon( private fun generateThemedIcon(
context: Context, iconId: Int, foregroundColor: Int, backgroundColor: Int context: Context,
iconId: Int,
foregroundColor: Int,
backgroundColor: Int
): Icon { ): Icon {
// Get and tint foreground and background drawables // Get and tint foreground and background drawables
val vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor) val vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor)

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appshortcuts package io.github.muntashirakon.music.appshortcuts
import android.app.Activity import android.app.Activity
@ -20,6 +20,7 @@ import android.os.Bundle
import io.github.muntashirakon.music.appshortcuts.shortcuttype.LastAddedShortcutType import io.github.muntashirakon.music.appshortcuts.shortcuttype.LastAddedShortcutType
import io.github.muntashirakon.music.appshortcuts.shortcuttype.ShuffleAllShortcutType import io.github.muntashirakon.music.appshortcuts.shortcuttype.ShuffleAllShortcutType
import io.github.muntashirakon.music.appshortcuts.shortcuttype.TopTracksShortcutType import io.github.muntashirakon.music.appshortcuts.shortcuttype.TopTracksShortcutType
import io.github.muntashirakon.music.extensions.extraNotNull
import io.github.muntashirakon.music.model.Playlist import io.github.muntashirakon.music.model.Playlist
import io.github.muntashirakon.music.model.smartplaylist.LastAddedPlaylist import io.github.muntashirakon.music.model.smartplaylist.LastAddedPlaylist
import io.github.muntashirakon.music.model.smartplaylist.ShuffleAllPlaylist import io.github.muntashirakon.music.model.smartplaylist.ShuffleAllPlaylist
@ -31,16 +32,7 @@ class AppShortcutLauncherActivity : Activity() {
public override fun onCreate(savedInstanceState: Bundle?) { public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
when (extraNotNull(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE).value) {
var shortcutType = SHORTCUT_TYPE_NONE
// Set shortcutType from the intent extras
val extras = intent.extras
if (extras != null) {
shortcutType = extras.getInt(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE)
}
when (shortcutType) {
SHORTCUT_TYPE_SHUFFLE_ALL -> { SHORTCUT_TYPE_SHUFFLE_ALL -> {
startServiceWithPlaylist( startServiceWithPlaylist(
SHUFFLE_MODE_SHUFFLE, ShuffleAllPlaylist() SHUFFLE_MODE_SHUFFLE, ShuffleAllPlaylist()
@ -78,9 +70,9 @@ class AppShortcutLauncherActivity : Activity() {
companion object { companion object {
const val KEY_SHORTCUT_TYPE = "io.github.muntashirakon.Music.appshortcuts.ShortcutType" const val KEY_SHORTCUT_TYPE = "io.github.muntashirakon.Music.appshortcuts.ShortcutType"
const val SHORTCUT_TYPE_SHUFFLE_ALL = 0 const val SHORTCUT_TYPE_SHUFFLE_ALL = 0L
const val SHORTCUT_TYPE_TOP_TRACKS = 1 const val SHORTCUT_TYPE_TOP_TRACKS = 1L
const val SHORTCUT_TYPE_LAST_ADDED = 2 const val SHORTCUT_TYPE_LAST_ADDED = 2L
const val SHORTCUT_TYPE_NONE = 4 const val SHORTCUT_TYPE_NONE = 4L
} }
} }

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appshortcuts package io.github.muntashirakon.music.appshortcuts
import android.annotation.TargetApi import android.annotation.TargetApi
@ -32,16 +32,16 @@ class DynamicShortcutManager(private val context: Context) {
this.context.getSystemService(ShortcutManager::class.java) this.context.getSystemService(ShortcutManager::class.java)
private val defaultShortcuts: List<ShortcutInfo> private val defaultShortcuts: List<ShortcutInfo>
get() = Arrays.asList( get() = listOf(
ShuffleAllShortcutType(context).shortcutInfo, ShuffleAllShortcutType(context).shortcutInfo,
TopTracksShortcutType(context).shortcutInfo, TopTracksShortcutType(context).shortcutInfo,
LastAddedShortcutType(context).shortcutInfo LastAddedShortcutType(context).shortcutInfo
) )
fun initDynamicShortcuts() { fun initDynamicShortcuts() {
//if (shortcutManager.dynamicShortcuts.size == 0) { // if (shortcutManager.dynamicShortcuts.size == 0) {
shortcutManager.dynamicShortcuts = defaultShortcuts shortcutManager.dynamicShortcuts = defaultShortcuts
//} // }
} }
fun updateDynamicShortcuts() { fun updateDynamicShortcuts() {
@ -58,8 +58,12 @@ class DynamicShortcutManager(private val context: Context) {
icon: Icon, icon: Icon,
intent: Intent intent: Intent
): ShortcutInfo { ): ShortcutInfo {
return ShortcutInfo.Builder(context, id).setShortLabel(shortLabel) return ShortcutInfo.Builder(context, id)
.setLongLabel(longLabel).setIcon(icon).setIntent(intent).build() .setShortLabel(shortLabel)
.setLongLabel(longLabel)
.setIcon(icon)
.setIntent(intent)
.build()
} }
fun reportShortcutUsed(context: Context, shortcutId: String) { fun reportShortcutUsed(context: Context, shortcutId: String) {

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appshortcuts.shortcuttype package io.github.muntashirakon.music.appshortcuts.shortcuttype
import android.annotation.TargetApi import android.annotation.TargetApi
@ -33,11 +33,11 @@ abstract class BaseShortcutType(internal var context: Context) {
* @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.) * @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.)
* @return * @return
*/ */
internal fun getPlaySongsIntent(shortcutType: Int): Intent { internal fun getPlaySongsIntent(shortcutType: Long): Intent {
val intent = Intent(context, AppShortcutLauncherActivity::class.java) val intent = Intent(context, AppShortcutLauncherActivity::class.java)
intent.action = Intent.ACTION_VIEW intent.action = Intent.ACTION_VIEW
val b = Bundle() val b = Bundle()
b.putInt(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType) b.putLong(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType)
intent.putExtras(b) intent.putExtras(b)
return intent return intent
} }

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appshortcuts.shortcuttype package io.github.muntashirakon.music.appshortcuts.shortcuttype
import android.annotation.TargetApi import android.annotation.TargetApi

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appshortcuts.shortcuttype package io.github.muntashirakon.music.appshortcuts.shortcuttype
import android.annotation.TargetApi import android.annotation.TargetApi
@ -26,20 +26,16 @@ import io.github.muntashirakon.music.appshortcuts.AppShortcutLauncherActivity
class ShuffleAllShortcutType(context: Context) : BaseShortcutType(context) { class ShuffleAllShortcutType(context: Context) : BaseShortcutType(context) {
override val shortcutInfo: ShortcutInfo override val shortcutInfo: ShortcutInfo
get() = ShortcutInfo.Builder( get() = ShortcutInfo.Builder(context, id)
context, id .setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short))
).setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short)).setLongLabel( .setLongLabel(context.getString(R.string.app_shortcut_shuffle_all_long))
context.getString(R.string.app_shortcut_shuffle_all_long) .setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_shuffle_all))
).setIcon( .setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL))
AppShortcutIconGenerator.generateThemedIcon(
context, R.drawable.ic_app_shortcut_shuffle_all
)
).setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL))
.build() .build()
companion object { companion object {
val id: String val id: String
get() = BaseShortcutType.ID_PREFIX + "shuffle_all" get() = ID_PREFIX + "shuffle_all"
} }
} }

View file

@ -1,17 +1,16 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
package io.github.muntashirakon.music.appshortcuts.shortcuttype package io.github.muntashirakon.music.appshortcuts.shortcuttype
import android.annotation.TargetApi import android.annotation.TargetApi

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
@ -30,6 +30,7 @@ import io.github.muntashirakon.music.appwidgets.base.BaseAppWidget
import io.github.muntashirakon.music.glide.SongGlideRequest import io.github.muntashirakon.music.glide.SongGlideRequest
import io.github.muntashirakon.music.service.MusicService import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.service.MusicService.* import io.github.muntashirakon.music.service.MusicService.*
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil import io.github.muntashirakon.music.util.RetroUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.animation.GlideAnimation import com.bumptech.glide.request.animation.GlideAnimation
@ -193,8 +194,11 @@ class AppWidgetBig : BaseAppWidget() {
* Link up various button actions using [PendingIntent]. * Link up various button actions using [PendingIntent].
*/ */
private fun linkButtons(context: Context, views: RemoteViews) { private fun linkButtons(context: Context, views: RemoteViews) {
val action = val action = Intent(context, MainActivity::class.java)
Intent(context, MainActivity::class.java).putExtra(MainActivity.EXPAND_PANEL, true) .putExtra(
MainActivity.EXPAND_PANEL,
PreferenceUtil.isExpandPanel
)
var pendingIntent: PendingIntent var pendingIntent: PendingIntent
val serviceName = ComponentName(context, MusicService::class.java) val serviceName = ComponentName(context, MusicService::class.java)
@ -229,6 +233,5 @@ class AppWidgetBig : BaseAppWidget() {
} }
return mInstance!! return mInstance!!
} }
} }
} }

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
@ -32,6 +32,7 @@ import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import io.github.muntashirakon.music.service.MusicService import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.service.MusicService.* import io.github.muntashirakon.music.service.MusicService.*
import io.github.muntashirakon.music.util.ImageUtil import io.github.muntashirakon.music.util.ImageUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil import io.github.muntashirakon.music.util.RetroUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.animation.GlideAnimation import com.bumptech.glide.request.animation.GlideAnimation
@ -217,7 +218,11 @@ class AppWidgetCard : BaseAppWidget() {
* Link up various button actions using [PendingIntent]. * Link up various button actions using [PendingIntent].
*/ */
private fun linkButtons(context: Context, views: RemoteViews) { private fun linkButtons(context: Context, views: RemoteViews) {
val action: Intent = Intent(context, MainActivity::class.java).putExtra("expand", true) val action = Intent(context, MainActivity::class.java)
.putExtra(
MainActivity.EXPAND_PANEL,
PreferenceUtil.isExpandPanel
)
var pendingIntent: PendingIntent var pendingIntent: PendingIntent
val serviceName = ComponentName(context, MusicService::class.java) val serviceName = ComponentName(context, MusicService::class.java)

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
@ -33,6 +33,7 @@ import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import io.github.muntashirakon.music.service.MusicService import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.service.MusicService.* import io.github.muntashirakon.music.service.MusicService.*
import io.github.muntashirakon.music.util.ImageUtil import io.github.muntashirakon.music.util.ImageUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil import io.github.muntashirakon.music.util.RetroUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.animation.GlideAnimation import com.bumptech.glide.request.animation.GlideAnimation
@ -49,7 +50,6 @@ class AppWidgetClassic : BaseAppWidget() {
override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) { override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) {
val appWidgetView = RemoteViews(context.packageName, R.layout.app_widget_classic) val appWidgetView = RemoteViews(context.packageName, R.layout.app_widget_classic)
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE) appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE)
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_audio_art) appWidgetView.setImageViewResource(R.id.image, R.drawable.default_audio_art)
appWidgetView.setImageViewBitmap( appWidgetView.setImageViewBitmap(
@ -208,7 +208,11 @@ class AppWidgetClassic : BaseAppWidget() {
* Link up various button actions using [PendingIntent]. * Link up various button actions using [PendingIntent].
*/ */
private fun linkButtons(context: Context, views: RemoteViews) { private fun linkButtons(context: Context, views: RemoteViews) {
val action = Intent(context, MainActivity::class.java).putExtra("expand", true) val action = Intent(context, MainActivity::class.java)
.putExtra(
MainActivity.EXPAND_PANEL,
PreferenceUtil.isExpandPanel
)
var pendingIntent: PendingIntent var pendingIntent: PendingIntent
val serviceName = ComponentName(context, MusicService::class.java) val serviceName = ComponentName(context, MusicService::class.java)

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
@ -31,6 +31,7 @@ import io.github.muntashirakon.music.glide.SongGlideRequest
import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import io.github.muntashirakon.music.service.MusicService import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.service.MusicService.* import io.github.muntashirakon.music.service.MusicService.*
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil import io.github.muntashirakon.music.util.RetroUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.animation.GlideAnimation import com.bumptech.glide.request.animation.GlideAnimation
@ -192,7 +193,11 @@ class AppWidgetSmall : BaseAppWidget() {
* Link up various button actions using [PendingIntent]. * Link up various button actions using [PendingIntent].
*/ */
private fun linkButtons(context: Context, views: RemoteViews) { private fun linkButtons(context: Context, views: RemoteViews) {
val action = Intent(context, MainActivity::class.java).putExtra("expand", true) val action = Intent(context, MainActivity::class.java)
.putExtra(
MainActivity.EXPAND_PANEL,
PreferenceUtil.isExpandPanel
)
var pendingIntent: PendingIntent var pendingIntent: PendingIntent
val serviceName = ComponentName(context, MusicService::class.java) val serviceName = ComponentName(context, MusicService::class.java)

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
@ -28,6 +28,7 @@ import io.github.muntashirakon.music.activities.MainActivity
import io.github.muntashirakon.music.appwidgets.base.BaseAppWidget import io.github.muntashirakon.music.appwidgets.base.BaseAppWidget
import io.github.muntashirakon.music.service.MusicService import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.service.MusicService.* import io.github.muntashirakon.music.service.MusicService.*
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil import io.github.muntashirakon.music.util.RetroUtil
class AppWidgetText : BaseAppWidget() { class AppWidgetText : BaseAppWidget() {
@ -77,7 +78,11 @@ class AppWidgetText : BaseAppWidget() {
* Link up various button actions using [PendingIntent]. * Link up various button actions using [PendingIntent].
*/ */
private fun linkButtons(context: Context, views: RemoteViews) { private fun linkButtons(context: Context, views: RemoteViews) {
val action = Intent(context, MainActivity::class.java).putExtra("expand", true) val action = Intent(context, MainActivity::class.java)
.putExtra(
MainActivity.EXPAND_PANEL,
PreferenceUtil.isExpandPanel
)
var pendingIntent: PendingIntent var pendingIntent: PendingIntent
val serviceName = ComponentName(context, MusicService::class.java) val serviceName = ComponentName(context, MusicService::class.java)
@ -153,10 +158,7 @@ class AppWidgetText : BaseAppWidget() {
) )
) )
pushUpdate(service.applicationContext, appWidgetIds, appWidgetView) pushUpdate(service.applicationContext, appWidgetIds, appWidgetView)
} }
companion object { companion object {

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appwidgets package io.github.muntashirakon.music.appwidgets
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.appwidgets.base package io.github.muntashirakon.music.appwidgets.base
import android.app.PendingIntent import android.app.PendingIntent
@ -40,7 +40,9 @@ abstract class BaseAppWidget : AppWidgetProvider() {
* {@inheritDoc} * {@inheritDoc}
*/ */
override fun onUpdate( override fun onUpdate(
context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) { ) {
defaultAppWidget(context, appWidgetIds) defaultAppWidget(context, appWidgetIds)
val updateIntent = Intent(APP_WIDGET_UPDATE) val updateIntent = Intent(APP_WIDGET_UPDATE)
@ -62,7 +64,9 @@ abstract class BaseAppWidget : AppWidgetProvider() {
} }
protected fun pushUpdate( protected fun pushUpdate(
context: Context, appWidgetIds: IntArray?, views: RemoteViews context: Context,
appWidgetIds: IntArray?,
views: RemoteViews
) { ) {
val appWidgetManager = AppWidgetManager.getInstance(context) val appWidgetManager = AppWidgetManager.getInstance(context)
if (appWidgetIds != null) { if (appWidgetIds != null) {
@ -86,7 +90,9 @@ abstract class BaseAppWidget : AppWidgetProvider() {
} }
protected fun buildPendingIntent( protected fun buildPendingIntent(
context: Context, action: String, serviceName: ComponentName context: Context,
action: String,
serviceName: ComponentName
): PendingIntent { ): PendingIntent {
val intent = Intent(action) val intent = Intent(action)
intent.component = serviceName intent.component = serviceName
@ -169,7 +175,11 @@ abstract class BaseAppWidget : AppWidgetProvider() {
} }
protected fun composeRoundedRectPath( protected fun composeRoundedRectPath(
rect: RectF, tl: Float, tr: Float, bl: Float, br: Float rect: RectF,
tl: Float,
tr: Float,
bl: Float,
br: Float
): Path { ): Path {
val path = Path() val path = Path()
path.moveTo(rect.left + tl, rect.top) path.moveTo(rect.left + tl, rect.top)

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import androidx.room.* import androidx.room.*
@ -18,4 +32,4 @@ interface BlackListStoreDao {
@Query("SELECT * FROM BlackListStoreEntity") @Query("SELECT * FROM BlackListStoreEntity")
fun blackListPaths(): List<BlackListStoreEntity> fun blackListPaths(): List<BlackListStoreEntity>
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import androidx.room.Entity import androidx.room.Entity
@ -7,4 +21,4 @@ import androidx.room.PrimaryKey
class BlackListStoreEntity( class BlackListStoreEntity(
@PrimaryKey @PrimaryKey
val path: String val path: String
) )

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
@ -23,4 +37,4 @@ interface HistoryDao {
@Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC LIMIT $HISTORY_LIMIT") @Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC LIMIT $HISTORY_LIMIT")
fun observableHistorySongs(): LiveData<List<HistoryEntity>> fun observableHistorySongs(): LiveData<List<HistoryEntity>>
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
@ -29,4 +43,4 @@ class HistoryEntity(
val albumArtist: String?, val albumArtist: String?,
@ColumnInfo(name = "time_played") @ColumnInfo(name = "time_played")
val timePlayed: Long val timePlayed: Long
) )

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import androidx.room.* import androidx.room.*
@ -15,4 +29,4 @@ interface LyricsDao {
@Update @Update
fun updateLyrics(lyricsEntity: LyricsEntity) fun updateLyrics(lyricsEntity: LyricsEntity)
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import androidx.room.Entity import androidx.room.Entity
@ -7,4 +21,4 @@ import androidx.room.PrimaryKey
class LyricsEntity( class LyricsEntity(
@PrimaryKey val songId: Int, @PrimaryKey val songId: Int,
val lyrics: String val lyrics: String
) )

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import androidx.room.* import androidx.room.*
@ -24,4 +38,4 @@ interface PlayCountDao {
@Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id") @Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id")
fun updateQuantity(id: Long) fun updateQuantity(id: Long)
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
@ -31,4 +45,4 @@ class PlayCountEntity(
val timePlayed: Long, val timePlayed: Long,
@ColumnInfo(name = "play_count") @ColumnInfo(name = "play_count")
var playCount: Int var playCount: Int
) )

View file

@ -1,10 +1,21 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.room.* import androidx.room.*
import io.github.muntashirakon.music.db.PlaylistEntity
import io.github.muntashirakon.music.db.PlaylistWithSongs
import io.github.muntashirakon.music.db.SongEntity
@Dao @Dao
interface PlaylistDao { interface PlaylistDao {
@ -48,12 +59,9 @@ interface PlaylistDao {
@Delete @Delete
suspend fun deletePlaylistSongs(songs: List<SongEntity>) suspend fun deletePlaylistSongs(songs: List<SongEntity>)
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
fun favoritesSongsLiveData(playlistId: Long): LiveData<List<SongEntity>> fun favoritesSongsLiveData(playlistId: Long): LiveData<List<SongEntity>>
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
fun favoritesSongs(playlistId: Long): List<SongEntity> fun favoritesSongs(playlistId: Long): List<SongEntity>
}
}

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import android.os.Parcelable import android.os.Parcelable
@ -14,4 +28,4 @@ class PlaylistEntity(
val playListId: Long = 0, val playListId: Long = 0,
@ColumnInfo(name = "playlist_name") @ColumnInfo(name = "playlist_name")
val playlistName: String val playlistName: String
) : Parcelable ) : Parcelable

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import android.os.Parcelable import android.os.Parcelable
@ -14,4 +28,3 @@ data class PlaylistWithSongs(
) )
val songs: List<SongEntity> val songs: List<SongEntity>
) : Parcelable ) : Parcelable

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import androidx.room.Database import androidx.room.Database
@ -14,4 +28,4 @@ abstract class RetroDatabase : RoomDatabase() {
abstract fun playCountDao(): PlayCountDao abstract fun playCountDao(): PlayCountDao
abstract fun historyDao(): HistoryDao abstract fun historyDao(): HistoryDao
abstract fun lyricsDao(): LyricsDao abstract fun lyricsDao(): LyricsDao
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import android.os.Parcelable import android.os.Parcelable
@ -36,4 +50,3 @@ class SongEntity(
@ColumnInfo(name = "album_artist") @ColumnInfo(name = "album_artist")
val albumArtist: String? val albumArtist: String?
) : Parcelable ) : Parcelable

View file

@ -1,7 +1,27 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.db package io.github.muntashirakon.music.db
import io.github.muntashirakon.music.model.Song import io.github.muntashirakon.music.model.Song
fun List<HistoryEntity>.fromHistoryToSongs(): List<Song> {
return map {
it.toSong()
}
}
fun List<SongEntity>.toSongs(): List<Song> { fun List<SongEntity>.toSongs(): List<Song> {
return map { return map {
it.toSong() it.toSong()

View file

@ -1,7 +1,22 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.dialogs package io.github.muntashirakon.music.dialogs
import android.app.Dialog import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.widget.ArrayAdapter
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@ -9,7 +24,6 @@ import io.github.muntashirakon.music.EXTRA_PLAYLISTS
import io.github.muntashirakon.music.EXTRA_SONG import io.github.muntashirakon.music.EXTRA_SONG
import io.github.muntashirakon.music.R import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.db.PlaylistEntity import io.github.muntashirakon.music.db.PlaylistEntity
import io.github.muntashirakon.music.db.SongEntity
import io.github.muntashirakon.music.db.toSongsEntity import io.github.muntashirakon.music.db.toSongsEntity
import io.github.muntashirakon.music.extensions.colorButtons import io.github.muntashirakon.music.extensions.colorButtons
import io.github.muntashirakon.music.extensions.extraNotNull import io.github.muntashirakon.music.extensions.extraNotNull
@ -41,30 +55,39 @@ class AddToPlaylistDialog : DialogFragment() {
} }
} }
private fun playlistAdapter(playlists: List<String>): ArrayAdapter<String> {
val adapter = ArrayAdapter<String>(requireContext(), R.layout.item_simple_text, R.id.title)
adapter.addAll(playlists)
return adapter
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val playlistEntities: List<PlaylistEntity> = val playlistEntities = extraNotNull<List<PlaylistEntity>>(EXTRA_PLAYLISTS).value
extraNotNull<List<PlaylistEntity>>(EXTRA_PLAYLISTS).value val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
val songs: List<Song> = extraNotNull<List<Song>>(EXTRA_SONG).value val playlistNames = mutableListOf<String>()
val playlistNames: MutableList<String> = mutableListOf()
playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist)) playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist))
for (entity: PlaylistEntity in playlistEntities) { for (entity: PlaylistEntity in playlistEntities) {
playlistNames.add(entity.playlistName) playlistNames.add(entity.playlistName)
} }
return materialDialog(R.string.add_playlist_title) return materialDialog(R.string.add_playlist_title)
.setItems(playlistNames.toTypedArray()) { _, which -> .setAdapter(
playlistAdapter(playlistNames)
) { dialog, which ->
if (which == 0) { if (which == 0) {
CreatePlaylistDialog.create(songs) showCreateDialog(songs)
.show(requireActivity().supportFragmentManager, "Dialog")
} else { } else {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val songEntities: List<SongEntity> = val songEntities = songs.toSongsEntity(playlistEntities[which - 1])
songs.toSongsEntity(playlistEntities[which - 1])
libraryViewModel.insertSongs(songEntities) libraryViewModel.insertSongs(songEntities)
libraryViewModel.forceReload(Playlists) libraryViewModel.forceReload(Playlists)
} }
} }
dismiss() dialog.dismiss()
} }
.create().colorButtons() .create().colorButtons()
} }
}
private fun showCreateDialog(songs: List<Song>) {
CreatePlaylistDialog.create(songs).show(requireActivity().supportFragmentManager, "Dialog")
}
}

View file

@ -7,150 +7,149 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import code.name.monkey.retromusic.R;
import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.MaterialDialog;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import io.github.muntashirakon.music.R; public class BlacklistFolderChooserDialog extends DialogFragment
implements MaterialDialog.ListCallback {
public class BlacklistFolderChooserDialog extends DialogFragment implements MaterialDialog.ListCallback { String initialPath = Environment.getExternalStorageDirectory().getAbsolutePath();
private File parentFolder;
private File[] parentContents;
private boolean canGoUp = false;
private FolderCallback callback;
String initialPath = Environment.getExternalStorageDirectory().getAbsolutePath(); public static BlacklistFolderChooserDialog create() {
private File parentFolder; return new BlacklistFolderChooserDialog();
private File[] parentContents; }
private boolean canGoUp = false;
private FolderCallback callback;
public static BlacklistFolderChooserDialog create() { private String[] getContentsArray() {
return new BlacklistFolderChooserDialog(); if (parentContents == null) {
if (canGoUp) {
return new String[] {".."};
}
return new String[] {};
} }
String[] results = new String[parentContents.length + (canGoUp ? 1 : 0)];
private String[] getContentsArray() { if (canGoUp) {
if (parentContents == null) { results[0] = "..";
if (canGoUp) {
return new String[]{".."};
}
return new String[]{};
}
String[] results = new String[parentContents.length + (canGoUp ? 1 : 0)];
if (canGoUp) {
results[0] = "..";
}
for (int i = 0; i < parentContents.length; i++) {
results[canGoUp ? i + 1 : i] = parentContents[i].getName();
}
return results;
} }
for (int i = 0; i < parentContents.length; i++) {
private File[] listFiles() { results[canGoUp ? i + 1 : i] = parentContents[i].getName();
File[] contents = parentFolder.listFiles();
List<File> results = new ArrayList<>();
if (contents != null) {
for (File fi : contents) {
if (fi.isDirectory()) {
results.add(fi);
}
}
Collections.sort(results, new FolderSorter());
return results.toArray(new File[results.size()]);
}
return null;
} }
return results;
}
@NonNull private File[] listFiles() {
@Override File[] contents = parentFolder.listFiles();
public Dialog onCreateDialog(Bundle savedInstanceState) { List<File> results = new ArrayList<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M if (contents != null) {
&& ActivityCompat.checkSelfPermission( for (File fi : contents) {
if (fi.isDirectory()) {
results.add(fi);
}
}
Collections.sort(results, new FolderSorter());
return results.toArray(new File[results.size()]);
}
return null;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ActivityCompat.checkSelfPermission(
requireActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) requireActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) { != PackageManager.PERMISSION_GRANTED) {
return new MaterialDialog.Builder(requireActivity()) return new MaterialDialog.Builder(requireActivity())
.title(R.string.md_error_label) .title(R.string.md_error_label)
.content(R.string.md_storage_perm_error) .content(R.string.md_storage_perm_error)
.positiveText(android.R.string.ok) .positiveText(android.R.string.ok)
.build(); .build();
} }
if (savedInstanceState == null) { if (savedInstanceState == null) {
savedInstanceState = new Bundle(); savedInstanceState = new Bundle();
} }
if (!savedInstanceState.containsKey("current_path")) { if (!savedInstanceState.containsKey("current_path")) {
savedInstanceState.putString("current_path", initialPath); savedInstanceState.putString("current_path", initialPath);
} }
parentFolder = new File(savedInstanceState.getString("current_path", File.pathSeparator)); parentFolder = new File(savedInstanceState.getString("current_path", File.pathSeparator));
checkIfCanGoUp(); checkIfCanGoUp();
parentContents = listFiles(); parentContents = listFiles();
MaterialDialog.Builder builder = new MaterialDialog.Builder(requireContext()) MaterialDialog.Builder builder =
.title(parentFolder.getAbsolutePath()) new MaterialDialog.Builder(requireContext())
.items((CharSequence[]) getContentsArray()) .title(parentFolder.getAbsolutePath())
.itemsCallback(this) .items((CharSequence[]) getContentsArray())
.autoDismiss(false) .itemsCallback(this)
.onPositive((dialog, which) -> { .autoDismiss(false)
callback.onFolderSelection(BlacklistFolderChooserDialog.this, parentFolder); .onPositive(
dismiss(); (dialog, which) -> {
callback.onFolderSelection(BlacklistFolderChooserDialog.this, parentFolder);
dismiss();
}) })
.onNegative((materialDialog, dialogAction) -> dismiss()) .onNegative((materialDialog, dialogAction) -> dismiss())
.positiveText(R.string.add_action) .positiveText(R.string.add_action)
.negativeText(android.R.string.cancel); .negativeText(android.R.string.cancel);
return builder.build(); return builder.build();
}
@Override
public void onSelection(MaterialDialog materialDialog, View view, int i, CharSequence s) {
if (canGoUp && i == 0) {
parentFolder = parentFolder.getParentFile();
if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
parentFolder = parentFolder.getParentFile();
}
checkIfCanGoUp();
} else {
parentFolder = parentContents[canGoUp ? i - 1 : i];
canGoUp = true;
if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
parentFolder = Environment.getExternalStorageDirectory();
}
} }
reload();
}
private void checkIfCanGoUp() {
canGoUp = parentFolder.getParent() != null;
}
private void reload() {
parentContents = listFiles();
MaterialDialog dialog = (MaterialDialog) getDialog();
dialog.setTitle(parentFolder.getAbsolutePath());
dialog.setItems((CharSequence[]) getContentsArray());
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("current_path", parentFolder.getAbsolutePath());
}
public void setCallback(FolderCallback callback) {
this.callback = callback;
}
public interface FolderCallback {
void onFolderSelection(@NonNull BlacklistFolderChooserDialog dialog, @NonNull File folder);
}
private static class FolderSorter implements Comparator<File> {
@Override @Override
public void onSelection(MaterialDialog materialDialog, View view, int i, CharSequence s) { public int compare(File lhs, File rhs) {
if (canGoUp && i == 0) { return lhs.getName().compareTo(rhs.getName());
parentFolder = parentFolder.getParentFile();
if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
parentFolder = parentFolder.getParentFile();
}
checkIfCanGoUp();
} else {
parentFolder = parentContents[canGoUp ? i - 1 : i];
canGoUp = true;
if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
parentFolder = Environment.getExternalStorageDirectory();
}
}
reload();
} }
}
private void checkIfCanGoUp() { }
canGoUp = parentFolder.getParent() != null;
}
private void reload() {
parentContents = listFiles();
MaterialDialog dialog = (MaterialDialog) getDialog();
dialog.setTitle(parentFolder.getAbsolutePath());
dialog.setItems((CharSequence[]) getContentsArray());
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("current_path", parentFolder.getAbsolutePath());
}
public void setCallback(FolderCallback callback) {
this.callback = callback;
}
public interface FolderCallback {
void onFolderSelection(@NonNull BlacklistFolderChooserDialog dialog, @NonNull File folder);
}
private static class FolderSorter implements Comparator<File> {
@Override
public int compare(File lhs, File rhs) {
return lhs.getName().compareTo(rhs.getName());
}
}
}

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.dialogs package io.github.muntashirakon.music.dialogs
import android.app.Dialog import android.app.Dialog
@ -26,7 +40,7 @@ import kotlinx.coroutines.launch
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class CreatePlaylistDialog : DialogFragment() { class CreatePlaylistDialog : DialogFragment() {
private val libraryViewModel by sharedViewModel<LibraryViewModel>() private val io.github.muntashirakon.music by sharedViewModel<LibraryViewModel>()
companion object { companion object {
fun create(song: Song): CreatePlaylistDialog { fun create(song: Song): CreatePlaylistDialog {
@ -54,17 +68,8 @@ class CreatePlaylistDialog : DialogFragment() {
) { _, _ -> ) { _, _ ->
val playlistName = playlistView.text.toString() val playlistName = playlistView.text.toString()
if (!TextUtils.isEmpty(playlistName)) { if (!TextUtils.isEmpty(playlistName)) {
lifecycleScope.launch(Dispatchers.IO) { io.github.muntashirakon.music.addToPlaylist(playlistName, songs)
if (libraryViewModel.checkPlaylistExists(playlistName).isEmpty()) {
val playlistId: Long =
libraryViewModel.createPlaylist(PlaylistEntity(playlistName = playlistName))
libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId) })
libraryViewModel.forceReload(Playlists)
} else {
Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT)
.show()
}
}
} else { } else {
playlistContainer.error = "Playlist is can't be empty" playlistContainer.error = "Playlist is can't be empty"
} }
@ -72,4 +77,4 @@ class CreatePlaylistDialog : DialogFragment() {
.create() .create()
.colorButtons() .colorButtons()
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.dialogs package io.github.muntashirakon.music.dialogs
import android.app.Dialog import android.app.Dialog
@ -65,5 +79,4 @@ class DeletePlaylistDialog : DialogFragment() {
.create() .create()
.colorButtons() .colorButtons()
} }
}
}

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.dialogs package io.github.muntashirakon.music.dialogs
import android.app.Dialog import android.app.Dialog
@ -67,4 +81,4 @@ class DeleteSongsDialog : DialogFragment() {
.create() .create()
.colorButtons() .colorButtons()
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.dialogs package io.github.muntashirakon.music.dialogs
import android.app.Dialog import android.app.Dialog
@ -21,4 +35,4 @@ class ImportPlaylistDialog : DialogFragment() {
.create() .create()
.colorButtons() .colorButtons()
} }
} }

View file

@ -1,60 +0,0 @@
package io.github.muntashirakon.music.dialogs
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.extensions.accentTextColor
import io.github.muntashirakon.music.extensions.hide
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.network.Result
import io.github.muntashirakon.music.repository.Repository
import kotlinx.android.synthetic.main.lyrics_dialog.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.inject
class LyricsDialog : DialogFragment() {
override fun getTheme(): Int {
return R.style.MaterialAlertDialogTheme
}
private val repository by inject<Repository>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.lyrics_dialog, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val song = MusicPlayerRemote.currentSong
dialogTitle.text = song.title
syncedLyrics.accentTextColor()
lifecycleScope.launch(IO) {
val result: Result<String> = repository.lyrics(
song.artistName,
song.title
)
withContext(Main) {
when (result) {
is Result.Error -> progressBar.hide()
is Result.Loading -> println("Loading")
is Result.Success -> {
progressBar.hide()
lyricsText.text = result.data
}
}
}
}
}
}

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.dialogs package io.github.muntashirakon.music.dialogs
import android.app.Dialog import android.app.Dialog
@ -12,7 +26,6 @@ import io.github.muntashirakon.music.extensions.colorButtons
import io.github.muntashirakon.music.extensions.extraNotNull import io.github.muntashirakon.music.extensions.extraNotNull
import io.github.muntashirakon.music.extensions.materialDialog import io.github.muntashirakon.music.extensions.materialDialog
import io.github.muntashirakon.music.fragments.LibraryViewModel import io.github.muntashirakon.music.fragments.LibraryViewModel
import io.github.muntashirakon.music.fragments.ReloadType.Playlists
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class RemoveSongFromPlaylistDialog : DialogFragment() { class RemoveSongFromPlaylistDialog : DialogFragment() {
@ -60,10 +73,9 @@ class RemoveSongFromPlaylistDialog : DialogFragment() {
.setMessage(pair.second) .setMessage(pair.second)
.setPositiveButton(R.string.remove_action) { _, _ -> .setPositiveButton(R.string.remove_action) { _, _ ->
libraryViewModel.deleteSongsInPlaylist(songs) libraryViewModel.deleteSongsInPlaylist(songs)
libraryViewModel.forceReload(Playlists)
} }
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.create() .create()
.colorButtons() .colorButtons()
} }
} }

View file

@ -1,3 +1,17 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.dialogs package io.github.muntashirakon.music.dialogs
import android.app.Dialog import android.app.Dialog
@ -54,4 +68,4 @@ class RenamePlaylistDialog : DialogFragment() {
.create() .create()
.colorButtons() .colorButtons()
} }
} }

View file

@ -1,6 +1,21 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.dialogs package io.github.muntashirakon.music.dialogs
import android.app.Dialog import android.app.Dialog
import android.media.MediaScannerConnection
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
@ -18,7 +33,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
class SavePlaylistDialog : DialogFragment() { class SavePlaylistDialog : DialogFragment() {
companion object { companion object {
fun create(playlistWithSongs: PlaylistWithSongs): SavePlaylistDialog { fun create(playlistWithSongs: PlaylistWithSongs): SavePlaylistDialog {
@ -33,9 +47,14 @@ class SavePlaylistDialog : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val playlistWithSongs: PlaylistWithSongs = val playlistWithSongs = extraNotNull<PlaylistWithSongs>(EXTRA_PLAYLIST).value
extraNotNull<PlaylistWithSongs>(EXTRA_PLAYLIST).value val file = PlaylistsUtil.savePlaylistWithSongs(playlistWithSongs)
val file = PlaylistsUtil.savePlaylistWithSongs(requireContext(), playlistWithSongs) MediaScannerConnection.scanFile(
requireActivity(),
arrayOf<String>(file.path),
null
) { _, _ ->
}
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
Toast.makeText( Toast.makeText(
requireContext(), requireContext(),
@ -52,4 +71,4 @@ class SavePlaylistDialog : DialogFragment() {
.setView(R.layout.loading) .setView(R.layout.loading)
.create().colorButtons() .create().colorButtons()
} }
} }

View file

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2019 Hemanth Savarala. * Copyright (c) 2020 Hemanth Savarla.
* *
* Licensed under the GNU General Public License v3 * Licensed under the GNU General Public License v3
* *
* This is free software: you can redistribute it and/or modify it under * This is free software: you can redistribute it and/or modify it
* the terms of the GNU General Public License as published by * under the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package io.github.muntashirakon.music.dialogs package io.github.muntashirakon.music.dialogs
import android.annotation.SuppressLint import android.annotation.SuppressLint
@ -130,7 +130,6 @@ class SleepTimerDialog : DialogFragment() {
} }
.create() .create()
.colorButtons() .colorButtons()
} }
private fun updateTimeDisplayTime() { private fun updateTimeDisplayTime() {
@ -173,4 +172,4 @@ class SleepTimerDialog : DialogFragment() {
updateCancelButton() updateCancelButton()
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show more