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.
### 🏠 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.
### 📦 Included Features
@ -49,33 +49,32 @@ favorite songs. No other music player has this feature.
- Driving Mode
- Headset/Bluetooth support
- Music duration filter
- Folder support - Play song by folder
- Folder support - Play songs by folder
- Gapless playback
- Volume controls
- Carousel effect for an album cover
- Carousel effect for album covers
- Home screen widgets
- Lock screen playback controls
- Lyrics screen (download and sync with music)
- Sleep Timer
- Sleep timer
- Easy drag to sort playlist & play queue
- Tag editor
- Create, edit and import playlists
- Playing queue with reorder
- User profile
- 30 Languages support
- 30+ languages support
- Browse and play your music by songs, albums, artists, playlists and
genre
- 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
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
>doesn't support music downloading or online music streaming.
> Please note: Metro is an offline music player app. It doesn't support music downloading or online music streaming.

View file

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

View file

@ -26,13 +26,11 @@
-dontwarn java.lang.invoke.*
-dontwarn **$$Lambda$*
-dontwarn javax.annotation.**
# RetroFit
-dontwarn retrofit.**
-keep class retrofit.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-dontwarn javax.annotation.**
# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
@ -41,14 +39,24 @@
public *;
}
# OkHttp
-keepattributes Signature
-keepattributes *Annotation*
-keep interface com.squareup.okhttp3.** { *; }
-dontwarn com.squareup.okhttp3.**
-dontwarn
-ignorewarnings
#-dontwarn
#-ignorewarnings
-dontshrink
-dontobfuscate
#-dontwarn android.support.v8.renderscript.*
#-keepclassmembers class android.support.v8.renderscript.RenderScript {
# native *** rsn*(...);
# native *** n*(...);
#}
-dontwarn org.jaudiotagger.**
-keep class org.jaudiotagger.** { *; }
#-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:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="circleImageView" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">5%</item>
</style>
</resources>

View file

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

View file

@ -3,24 +3,30 @@
"name": "Hemanth Savarala",
"summary": "Lead Developer & Designer",
"link": "https://github.com/h4h13",
"profile_image": "https://i.imgur.com/AoVs9oj.jpg"
"image": "https://i.imgur.com/AoVs9oj.jpg"
},
{
"name": "Lennart Glamann",
"summary": "Play Store banner and Images",
"summary": "Play Store Banner & Images",
"link": "https://t.me/FlixbusLennart",
"profile_image": "https://i.imgur.com/Q5Nsx1R.jpg"
"image": "https://i.imgur.com/Q5Nsx1R.jpg"
},
{
"name": "Daksh P. Jain",
"summary": "Support Representative & Moderator",
"link": "https://daksh.eu.org",
"profile_image": "https://i.imgur.com/fnYpg65.jpg"
"image": "https://i.imgur.com/fnYpg65.jpg"
},
{
"name": "Milind Goel",
"summary": "Support Representative & Moderator",
"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
*
* 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 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
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
*
* 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 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
import android.provider.BaseColumns
@ -46,9 +45,9 @@ object Constants {
MediaStore.Audio.AudioColumns.ALBUM_ID, // 7
MediaStore.Audio.AudioColumns.ALBUM, // 8
MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
MediaStore.Audio.AudioColumns.ARTIST,// 10
MediaStore.Audio.AudioColumns.COMPOSER,// 11
"album_artist"//12
MediaStore.Audio.AudioColumns.ARTIST, // 10
MediaStore.Audio.AudioColumns.COMPOSER, // 11
"album_artist" // 12
)
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 TOGGLE_HEADSET = "toggle_headset"
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 USER_NAME = "user_name"
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 TOGGLE_SEPARATE_LINE = "toggle_separate_line"
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 ALBUM_COVER_STYLE = "album_cover_style_id"
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_ALBUM_SORT_ORDER = "artist_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 ARTIST_SONG_SORT_ORDER = "artist_song_sort_order"
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 RECENTLY_PLAYED_CUTOFF = "recently_played_interval"
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 LYRICS_OPTIONS = "lyrics_tab_position"
const val CHOOSE_EQUALIZER = "choose_equalizer"
const val EQUALIZER = "equalizer"
const val TOGGLE_SHUFFLE = "toggle_shuffle"
const val SONG_GRID_STYLE = "song_grid_style"
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
import androidx.annotation.IntDef
@ -25,4 +39,4 @@ const val GENRES = 6
const val PLAYLISTS = 7
const val HISTORY_PLAYLIST = 8
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.Resources;
import android.os.LocaleList;
import java.util.Locale;
import code.name.monkey.appthemehelper.util.VersionUtils;
import java.util.Locale;
public class LanguageContextWrapper extends ContextWrapper {
public LanguageContextWrapper(Context base) {
super(base);
public LanguageContextWrapper(Context 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) {
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);
}
}
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.genres.GenreDetailsViewModel
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.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.util.FilePathUtil
import kotlinx.coroutines.Dispatchers.IO
@ -36,15 +38,9 @@ val networkModule = module {
single {
provideLastFmRetrofit(get())
}
single {
provideDeezerRest(get())
}
single {
provideLastFmRest(get())
}
single {
provideLyrics(get())
}
}
private val roomModule = module {
@ -93,7 +89,6 @@ private val mainModule = module {
single {
androidContext().contentResolver
}
}
private val dataModule = module {
single {
@ -109,7 +104,7 @@ private val dataModule = module {
get(),
get(),
get(),
get()
get(),
)
} bind Repository::class
@ -154,6 +149,9 @@ private val dataModule = module {
get()
)
}
single {
RealLocalDataRepository(get())
} bind LocalDataRepository::class
}
private val viewModules = module {
@ -189,10 +187,6 @@ private val viewModules = module {
genre
)
}
viewModel {
SearchViewModel(get())
}
}
val appModules = listOf(mainModule, dataModule, viewModules, networkModule, roomModule)

View file

@ -4,36 +4,32 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import org.jetbrains.annotations.NotNull;
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;
}
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);
}
}
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
*
* 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 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
import android.animation.ObjectAnimator
@ -234,4 +234,4 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
}
}

View file

@ -18,82 +18,86 @@ import android.graphics.Color;
import android.os.Bundle;
import android.view.MenuItem;
import android.webkit.WebView;
import androidx.annotation.NonNull;
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.util.ATHUtil;
import code.name.monkey.appthemehelper.util.ColorUtil;
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper;
import io.github.muntashirakon.music.R;
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 {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
setDrawUnderStatusBar();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_license);
setStatusbarColorAuto();
setNavigationbarColorAuto();
setLightNavigationBar(true);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ToolbarContentTintHelper.colorBackButton(toolbar);
toolbar.setBackgroundColor(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface));
WebView webView = findViewById(R.id.license);
try {
StringBuilder buf = new StringBuilder();
InputStream json = getAssets().open("oldindex.html");
BufferedReader in = new BufferedReader(new InputStreamReader(json, StandardCharsets.UTF_8));
String str;
while ((str = in.readLine()) != null) {
buf.append(str);
}
in.close();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
setDrawUnderStatusBar();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_license);
setStatusbarColorAuto();
setNavigationbarColorAuto();
setLightNavigationBar(true);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ToolbarContentTintHelper.colorBackButton(toolbar);
toolbar.setBackgroundColor(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface));
WebView webView = findViewById(R.id.license);
try {
StringBuilder buf = new StringBuilder();
InputStream json = getAssets().open("oldindex.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 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 changeLog = buf.toString()
.replace("{style-placeholder}",
String.format("body { background-color: %s; color: %s; }", backgroundColor, contentColor))
.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");
}
// Inject color values for WebView body background and links
final boolean isDark = ATHUtil.INSTANCE.isWindowBackgroundDark(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 changeLog =
buf.toString()
.replace(
"{style-placeholder}",
String.format(
"body { background-color: %s; color: %s; }", backgroundColor, contentColor))
.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");
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
private String colorToCSS(int color) {
return String.format("rgb(%d, %d, %d)", Color.red(color), Color.green(color),
Color.blue(color)); // on API 29, WebView doesn't load with hex colors
}
private String colorToCSS(int color) {
return String.format(
"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
import android.app.KeyguardManager
@ -9,7 +23,8 @@ import android.view.WindowManager
import androidx.core.view.ViewCompat
import io.github.muntashirakon.music.R
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.SongGlideRequest
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.*
class LockScreenActivity : AbsMusicServiceActivity() {
private var fragment: LockScreenPlayerControlsFragment? = null
private var fragment: LockScreenControlsFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
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
)
}
lockScreenInit()
setContentView(R.layout.activity_lock_screen)
hideStatusBar()
setStatusbarColorAuto()
@ -67,8 +73,7 @@ class LockScreenActivity : AbsMusicServiceActivity() {
Slidr.attach(this, config)
fragment =
supportFragmentManager.findFragmentById(R.id.playback_controls_fragment) as LockScreenPlayerControlsFragment?
fragment = whichFragment<LockScreenControlsFragment>(R.id.playback_controls_fragment)
findViewById<View>(R.id.slide).apply {
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() {
super.onPlayingMetaChanged()
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
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
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.util.ToolbarContentTintHelper
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.util.LyricUtil
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.*
class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.Callback {
@ -31,9 +51,20 @@ class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.
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?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_lyrics)
ViewCompat.setTransitionName(container, "lyrics")
setStatusbarColorAuto()
setTaskDescriptionColorAuto()
setNavigationbarColorAuto()
@ -122,4 +153,4 @@ class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.
}
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
import android.content.Intent
@ -8,17 +22,45 @@ import android.os.Bundle
import android.provider.MediaStore
import android.view.View
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.extensions.findNavController
import io.github.muntashirakon.music.helper.MusicPlayerRemote
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.repository.PlaylistSongsLoader
import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.util.PreferenceUtil
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import org.koin.android.ext.android.get
class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener {
companion object {
@ -28,21 +70,43 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_main_content)
return wrapSlidingMusicPanel()
}
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
if (!hasPermissions()) {
findNavController(R.id.fragment_container).navigate(R.id.permissionFragment)
}
setStatusbarColorAuto()
setNavigationbarColorAuto()
setLightNavigationBar(true)
setTaskDescriptionColorAuto()
hideStatusBar()
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 =
@ -98,8 +162,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
val id = parseLongFromIntent(intent, "playlistId", "playlist")
if (id >= 0L) {
val position: Int = intent.getIntExtra("position", 0)
val songs: List<Song> =
PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id)
val songs: List<Song> = PlaylistSongsLoader.getPlaylistSongList(get(), id)
MusicPlayerRemote.openQueue(songs, position, true)
handled = true
}
@ -107,8 +170,9 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
val id = parseLongFromIntent(intent, "albumId", "album")
if (id >= 0L) {
val position: Int = intent.getIntExtra("position", 0)
val songs = libraryViewModel.albumById(id).songs
MusicPlayerRemote.openQueue(
libraryViewModel.albumById(id).songs,
songs,
position,
true
)
@ -118,8 +182,9 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
val id = parseLongFromIntent(intent, "artistId", "artist")
if (id >= 0L) {
val position: Int = intent.getIntExtra("position", 0)
val songs: List<Song> = libraryViewModel.artistById(id).songs
MusicPlayerRemote.openQueue(
libraryViewModel.artistById(id).songs,
songs,
position,
true
)
@ -130,11 +195,11 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
setIntent(Intent())
}
}
}
private fun parseLongFromIntent(
intent: Intent, longKey: String,
intent: Intent,
longKey: String,
stringKey: String
): Long {
var id = intent.getLongExtra(longKey, -1)
@ -150,4 +215,4 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
}
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
import android.content.Intent
@ -13,7 +27,6 @@ import io.github.muntashirakon.music.extensions.show
import io.github.muntashirakon.music.util.RingtoneManager
import kotlinx.android.synthetic.main.activity_permission.*
class PermissionActivity : AbsMusicServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -37,7 +50,7 @@ class PermissionActivity : AbsMusicServiceActivity() {
}
finish.accentBackgroundColor()
finish.setOnClickListener {
if (hasPermissions() && !RingtoneManager.requiresDialog(this)) {
if (hasPermissions()) {
startActivity(
Intent(this, MainActivity::class.java).addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK or
@ -56,4 +69,4 @@ class PermissionActivity : AbsMusicServiceActivity() {
)
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
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
import android.os.Bundle
import android.view.MenuItem
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils
import com.afollestad.materialdialogs.color.ColorChooserDialog
@ -29,10 +44,26 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
applyToolbar(toolbar)
val navController: NavController = findNavController(R.id.contentFrame)
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 {
return findNavController(R.id.contentFrame).navigateUp() || super.onSupportNavigateUp()
}
@ -49,7 +80,6 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
}
override fun onColorChooserDismissed(dialog: ColorChooserDialog) {
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -58,4 +88,4 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
}
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
*
* 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 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
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
import android.app.Activity
@ -11,12 +25,6 @@ import android.view.MenuItem
import android.widget.Toast
import code.name.monkey.appthemehelper.util.ColorUtil
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_PROFILE
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.util.ImageUtil
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.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
class UserInfoActivity : AbsBaseActivity() {
@ -55,7 +69,7 @@ class UserInfoActivity : AbsBaseActivity() {
pickNewPhoto()
}
bannerSelect.setOnClickListener {
bannerImage.setOnClickListener {
selectBannerImage()
}
@ -114,7 +128,6 @@ class UserInfoActivity : AbsBaseActivity() {
.start(PICK_IMAGE_REQUEST)
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == PICK_IMAGE_REQUEST) {
@ -209,9 +222,8 @@ class UserInfoActivity : AbsBaseActivity() {
.into(userImage)
}
companion object {
private const val PICK_IMAGE_REQUEST = 9002
private const val PICK_BANNER_REQUEST = 9004
}
}
}

View file

@ -1,23 +1,14 @@
package io.github.muntashirakon.music.activities;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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.util.ATHUtil;
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.activities.base.AbsBaseActivity;
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 {
private static String colorToCSS(int color) {
return String.format(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 String colorToCSS(int color) {
return String.format(
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) {
try {
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
int currentVersion = pInfo.versionCode;
PreferenceUtil.INSTANCE.setLastVersion(currentVersion);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
@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");
}
@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);
}
}
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
import android.Manifest
@ -12,8 +26,8 @@ import android.view.KeyEvent
import android.view.View
import androidx.core.app.ActivityCompat
import code.name.monkey.appthemehelper.ThemeStore
import com.google.android.material.snackbar.Snackbar
import io.github.muntashirakon.music.R
import com.google.android.material.snackbar.Snackbar
abstract class AbsBaseActivity : AbsThemeActivity() {
private var hadPermissions: Boolean = false
@ -46,7 +60,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
if (!hasPermissions()) {
//requestPermissions()
// requestPermissions()
}
}
@ -107,7 +121,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
this@AbsBaseActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE
)
) {
//User has deny from permission dialog
// User has deny from permission dialog
Snackbar.make(
snackBarContainer,
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
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.IBinder
import androidx.lifecycle.lifecycleScope
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.db.toPlayCount
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.service.MusicService.*
import java.lang.ref.WeakReference
import java.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
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 var serviceToken: MusicPlayerRemote.ServiceToken? = null
private var musicStateReceiver: MusicStateReceiver? = null
@ -49,15 +68,15 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
}
}
fun addMusicServiceEventListener(listener: MusicServiceEventListener?) {
if (listener != null) {
mMusicServiceEventListeners.add(listener)
fun addMusicServiceEventListener(listenerI: IMusicServiceEventListener?) {
if (listenerI != null) {
mMusicServiceEventListeners.add(listenerI)
}
}
fun removeMusicServiceEventListener(listener: MusicServiceEventListener?) {
if (listener != null) {
mMusicServiceEventListeners.remove(listener)
fun removeMusicServiceEventListener(listenerI: IMusicServiceEventListener?) {
if (listenerI != null) {
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
import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.FrameLayout
import androidx.annotation.LayoutRes
import androidx.core.view.ViewCompat
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.ColorUtil
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.RetroBottomSheetBehavior
import io.github.muntashirakon.music.extensions.hide
import io.github.muntashirakon.music.extensions.whichFragment
import io.github.muntashirakon.music.extensions.*
import io.github.muntashirakon.music.fragments.LibraryViewModel
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.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.model.CategoryInfo
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.views.BottomNavigationBarTinted
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
import org.koin.androidx.viewmodel.ext.android.viewModel
@ -34,9 +67,10 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
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 cps: NowPlayingScreen? = null
private var nowPlayingScreen: NowPlayingScreen? = null
private var navigationBarColor: Int = 0
private var taskColor: Int = 0
private var lightStatusBar: Boolean = false
@ -44,88 +78,90 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
private var paletteColor: Int = Color.WHITE
protected abstract fun createContentView(): View
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) {
setMiniPlayerAlphaProgress(slideOffset)
dimBackground.show()
dimBackground.alpha = slideOffset
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_EXPANDED -> {
STATE_EXPANDED -> {
onPanelExpanded()
}
BottomSheetBehavior.STATE_COLLAPSED -> {
STATE_COLLAPSED -> {
onPanelCollapsed()
dimBackground.hide()
}
else -> {
println("Do something")
}
}
}
}
fun getBottomSheetBehavior() = bottomSheetBehavior
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(createContentView())
chooseFragmentForTheme()
setupSlidingUpPanel()
setupBottomSheet()
updateColor()
libraryViewModel.paletteColorLiveData.observe(this, Observer {
this.paletteColor = it
onPaletteColorChanged()
})
val themeColor = ATHUtil.resolveColor(this, android.R.attr.windowBackground, Color.GRAY)
dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
dimBackground.setOnClickListener {
println("dimBackground")
}
}
fun getBottomSheetBehavior() = behavior
private fun setupBottomSheet() {
behavior = BottomSheetBehavior.from(slidingPanel) as RetroBottomSheetBehavior
behavior.addBottomSheetCallback(bottomSheetCallbackList)
if (behavior.state == BottomSheetBehavior.STATE_EXPANDED) {
setMiniPlayerAlphaProgress(1f)
}
bottomSheetBehavior = from(slidingPanel) as RetroBottomSheetBehavior
bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
}
override fun onResume() {
super.onResume()
if (cps != PreferenceUtil.nowPlayingScreen) {
if (nowPlayingScreen != PreferenceUtil.nowPlayingScreen) {
postRecreate()
}
if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) {
setMiniPlayerAlphaProgress(1f)
}
}
override fun onDestroy() {
super.onDestroy()
behavior.removeBottomSheetCallback(bottomSheetCallbackList)
bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList)
}
protected fun wrapSlidingMusicPanel(@LayoutRes resId: Int): View {
@SuppressLint("InflateParams")
protected fun wrapSlidingMusicPanel(): View {
val slidingMusicPanelLayout =
layoutInflater.inflate(R.layout.sliding_music_panel_layout, null)
val contentContainer: ViewGroup =
slidingMusicPanelLayout.findViewById(R.id.mainContentFrame)
layoutInflater.inflate(resId, contentContainer)
layoutInflater.inflate(R.layout.activity_main_content, contentContainer)
return slidingMusicPanelLayout
}
fun collapsePanel() {
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
setMiniPlayerAlphaProgress(0f)
bottomSheetBehavior.state = STATE_COLLAPSED
}
fun expandPanel() {
behavior.state = BottomSheetBehavior.STATE_EXPANDED
bottomSheetBehavior.state = STATE_EXPANDED
setMiniPlayerAlphaProgress(1f)
}
private fun setMiniPlayerAlphaProgress(progress: Float) {
if (miniPlayerFragment?.view == null) return
val alpha = 1 - progress
miniPlayerFragment?.view?.alpha = alpha
miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE
@ -150,11 +186,16 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
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) {
BottomSheetBehavior.STATE_EXPANDED -> onPanelExpanded()
BottomSheetBehavior.STATE_COLLAPSED -> onPanelCollapsed()
STATE_EXPANDED -> onPanelExpanded()
STATE_COLLAPSED -> onPanelCollapsed()
else -> {
//playerFragment!!.onHide()
// playerFragment!!.onHide()
}
}
}
@ -165,35 +206,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
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() {
super.onServiceConnected()
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
@ -216,36 +228,38 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
if (!handleBackPress()) super.onBackPressed()
}
open fun handleBackPress(): Boolean {
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
private fun handleBackPress(): Boolean {
if (bottomSheetBehavior.peekHeight != 0 && playerFragment!!.onBackPressed()) return true
if (panelState == STATE_EXPANDED) {
collapsePanel()
return true
}
return false
}
private fun onPaletteColorChanged() {
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
if (panelState == STATE_EXPANDED) {
super.setTaskDescriptionColor(paletteColor)
val isColorLight = ColorUtil.isColorLight(paletteColor)
if (PreferenceUtil.isAdaptiveColor && (cps == Normal || cps == Flat)) {
if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat)) {
super.setLightNavigationBar(true)
super.setLightStatusbar(isColorLight)
} else if (cps == Card || cps == Blur || cps == BlurCard) {
} else if (nowPlayingScreen == Card || nowPlayingScreen == Blur || nowPlayingScreen == BlurCard) {
super.setLightStatusbar(false)
super.setLightNavigationBar(true)
super.setNavigationbarColor(Color.BLACK)
} else if (cps == Color || cps == Tiny || cps == Gradient) {
} else if (nowPlayingScreen == Color || nowPlayingScreen == Tiny || nowPlayingScreen == Gradient) {
super.setNavigationbarColor(paletteColor)
super.setLightNavigationBar(isColorLight)
super.setLightStatusbar(isColorLight)
} else if (cps == Full) {
} else if (nowPlayingScreen == Full) {
super.setNavigationbarColor(paletteColor)
super.setLightNavigationBar(isColorLight)
super.setLightStatusbar(false)
} else if (cps == Classic) {
} else if (nowPlayingScreen == Classic) {
super.setLightStatusbar(false)
} else if (cps == Fit) {
} else if (nowPlayingScreen == Fit) {
super.setLightStatusbar(false)
} else {
super.setLightStatusbar(
@ -263,38 +277,32 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
override fun setLightStatusbar(enabled: Boolean) {
lightStatusBar = enabled
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
if (panelState == STATE_COLLAPSED) {
super.setLightStatusbar(enabled)
}
}
override fun setLightNavigationBar(enabled: Boolean) {
lightNavigationBar = enabled
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
if (panelState == STATE_COLLAPSED) {
super.setLightNavigationBar(enabled)
}
}
override fun setNavigationbarColor(color: Int) {
navigationBarColor = color
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
if (panelState == STATE_COLLAPSED) {
super.setNavigationbarColor(color)
}
}
override fun setTaskDescriptionColor(color: Int) {
taskColor = color
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
if (panelState == STATE_COLLAPSED) {
super.setTaskDescriptionColor(color)
}
}
fun hideBottomNavigation() {
behavior.isHideable = true
behavior.peekHeight = 0
hideBottomBarVisibility(false)
}
fun updateTabs() {
bottomNavigationView.menu.clear()
val currentTabs: List<CategoryInfo> = PreferenceUtil.libraryCategory
@ -308,4 +316,74 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
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
import android.content.Context
@ -37,7 +51,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
MaterialDialogsUtil.updateMaterialDialogsThemeSingleton(this)
}
private fun updateTheme() {
setTheme(ThemeManager.getThemeResValue(this))
setDefaultNightMode(ThemeManager.getNightMode(this))
@ -204,4 +217,4 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
super.attachBaseContext(LanguageContextWrapper.wrap(newBase, Locale(code)))
} 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
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.floatingactionbutton.FloatingActionButton
import com.google.android.material.textfield.TextInputLayout
import java.io.IOException
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_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.RequestException
import org.eclipse.egit.github.core.service.IssueService
import java.io.IOException
private const val RESULT_SUCCESS = "RESULT_OK"
private const val RESULT_BAD_CREDENTIALS = "RESULT_BAD_CREDENTIALS"
@ -306,7 +320,6 @@ open class BugReportActivity : AbsThemeActivity() {
}
}
companion object {
fun report(

View file

@ -5,129 +5,197 @@ import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.IntRange;
import org.jetbrains.annotations.NotNull;
import code.name.monkey.retromusic.util.PreferenceUtil;
import java.util.Arrays;
import java.util.Locale;
import io.github.muntashirakon.music.util.PreferenceUtil;
public class DeviceInfo {
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
private final String[] abis = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
Build.SUPPORTED_ABIS : new String[]{Build.CPU_ABI, Build.CPU_ABI2};
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
private final String[] abis =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
? Build.SUPPORTED_ABIS
: new String[] {Build.CPU_ABI, Build.CPU_ABI2};
@SuppressLint("NewApi")
private final String[] abis32Bits = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
Build.SUPPORTED_32_BIT_ABIS : null;
@SuppressLint("NewApi")
private final String[] abis32Bits =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? Build.SUPPORTED_32_BIT_ABIS : null;
@SuppressLint("NewApi")
private final String[] abis64Bits = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
Build.SUPPORTED_64_BIT_ABIS : null;
@SuppressLint("NewApi")
private final String[] abis64Bits =
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)
private final int sdkVersion = Build.VERSION.SDK_INT;
@IntRange(from = 0)
private final int sdkVersion = Build.VERSION.SDK_INT;
private final int versionCode;
private final int versionCode;
private final String versionName;
private final String selectedLang;
private final String versionName;
private final String selectedLang;
public DeviceInfo(Context context) {
PackageInfo packageInfo;
try {
packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
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();
public DeviceInfo(Context context) {
PackageInfo packageInfo;
try {
packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
packageInfo = null;
}
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";
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();
}
@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
public String toString() {
return "App version: " + versionName + "\n"
+ "App version code: " + versionCode + "\n"
+ "Android build version: " + buildVersion + "\n"
+ "Android release version: " + releaseVersion + "\n"
+ "Android SDK version: " + sdkVersion + "\n"
+ "Android build ID: " + buildID + "\n"
+ "Device brand: " + 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;
}
public String toString() {
return "App version: "
+ versionName
+ "\n"
+ "App version code: "
+ versionCode
+ "\n"
+ "Android build version: "
+ buildVersion
+ "\n"
+ "Android release version: "
+ releaseVersion
+ "\n"
+ "Android SDK version: "
+ sdkVersion
+ "\n"
+ "Android build ID: "
+ buildID
+ "\n"
+ "Device brand: "
+ 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;
import io.github.muntashirakon.music.activities.bugreport.model.github.ExtraInfo;
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) {
this.title = title;
this.description = description;
this.deviceInfo = deviceInfo;
this.extraInfo = extraInfo;
}
public Report(String title, String description, DeviceInfo deviceInfo, ExtraInfo extraInfo) {
this.title = title;
this.description = description;
this.deviceInfo = deviceInfo;
this.extraInfo = extraInfo;
}
public String getDescription() {
return description + "\n\n"
+ "-\n\n"
+ deviceInfo.toMarkdown() + "\n\n"
+ extraInfo.toMarkdown();
}
public String getDescription() {
return description
+ "\n\n"
+ "-\n\n"
+ deviceInfo.toMarkdown()
+ "\n\n"
+ extraInfo.toMarkdown();
}
public String getTitle() {
return title;
}
public String getTitle() {
return title;
}
}

View file

@ -5,58 +5,57 @@ import java.util.Map;
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) {
extraInfo.put(key, value);
public void put(String key, String 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) {
extraInfo.put(key, Boolean.toString(value));
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");
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 "";
}
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();
}
return output.toString();
}
}

View file

@ -4,38 +4,37 @@ import android.text.TextUtils;
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) {
this.username = username;
this.password = password;
this.apiToken = null;
}
public GithubLogin(String username, String password) {
this.username = username;
this.password = password;
this.apiToken = null;
}
public GithubLogin(String apiToken) {
this.username = null;
this.password = null;
this.apiToken = apiToken;
}
public GithubLogin(String apiToken) {
this.username = null;
this.password = null;
this.apiToken = apiToken;
}
public String getApiToken() {
return apiToken;
}
public String getApiToken() {
return apiToken;
}
public String getPassword() {
return password;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
public boolean shouldUseApiToken() {
return TextUtils.isEmpty(username) || TextUtils.isEmpty(password);
}
public String getUsername() {
return username;
}
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 {
private final String repository;
private final String repository;
private final String username;
private final String username;
public GithubTarget(String username, String repository) {
this.username = username;
this.repository = repository;
}
public GithubTarget(String username, String repository) {
this.username = username;
this.repository = repository;
}
public String getRepository() {
return repository;
}
public String getRepository() {
return repository;
}
public String getUsername() {
return username;
}
public String getUsername() {
return username;
}
}

View file

@ -16,57 +16,58 @@ package io.github.muntashirakon.music.activities.saf;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Nullable;
import io.github.muntashirakon.music.R;
import com.heinrichreimersoftware.materialintro.app.IntroActivity;
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 static final int REQUEST_CODE_SAF_GUIDE = 98;
public static final int REQUEST_CODE_SAF_GUIDE = 98;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setButtonCtaVisible(false);
setButtonNextVisible(false);
setButtonBackVisible(false);
setButtonCtaVisible(false);
setButtonNextVisible(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()
.title(title)
.description(Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
? R.string.saf_guide_slide1_description_before_o : R.string.saf_guide_slide1_description)
.image(R.drawable.saf_guide_1)
.background(R.color.md_deep_purple_300)
.backgroundDark(R.color.md_deep_purple_400)
.layout(R.layout.fragment_simple_slide_large_image)
.build());
addSlide(new SimpleSlide.Builder()
.title(R.string.saf_guide_slide2_title)
.description(R.string.saf_guide_slide2_description)
.image(R.drawable.saf_guide_2)
.background(R.color.md_deep_purple_500)
.backgroundDark(R.color.md_deep_purple_600)
.layout(R.layout.fragment_simple_slide_large_image)
.build());
addSlide(new SimpleSlide.Builder()
.title(R.string.saf_guide_slide3_title)
.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());
}
addSlide(
new SimpleSlide.Builder()
.title(title)
.description(
Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
? R.string.saf_guide_slide1_description_before_o
: R.string.saf_guide_slide1_description)
.image(R.drawable.saf_guide_1)
.background(R.color.md_deep_purple_300)
.backgroundDark(R.color.md_deep_purple_400)
.layout(R.layout.fragment_simple_slide_large_image)
.build());
addSlide(
new SimpleSlide.Builder()
.title(R.string.saf_guide_slide2_title)
.description(R.string.saf_guide_slide2_description)
.image(R.drawable.saf_guide_2)
.background(R.color.md_deep_purple_500)
.backgroundDark(R.color.md_deep_purple_600)
.layout(R.layout.fragment_simple_slide_large_image)
.build());
addSlide(
new SimpleSlide.Builder()
.title(R.string.saf_guide_slide3_title)
.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
import android.app.Activity
import android.app.SearchManager
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
@ -16,18 +28,19 @@ import android.view.animation.OvershootInterpolator
import androidx.appcompat.app.AlertDialog
import code.name.monkey.appthemehelper.ThemeStore
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 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.drawable
import io.github.muntashirakon.music.activities.base.AbsBaseActivity
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.util.RetroUtil
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 org.jaudiotagger.audio.AudioFile
import org.jaudiotagger.audio.AudioFileIO
@ -49,6 +62,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private val currentSongPath: String? = null
private var savedTags: Map<FieldKey, String>? = null
private var savedArtworkInfo: ArtworkInfo? = null
protected abstract val contentViewLayout: Int
protected abstract fun loadImageFromFile(selectedFile: Uri?)
protected val show: AlertDialog
get() =
@ -62,7 +77,6 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
}
}
.show()
protected abstract val contentViewLayout: Int
internal val albumArtist: String?
get() {
@ -182,6 +196,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
getIntentExtras()
songPaths = getSongPaths()
println(songPaths?.size)
if (songPaths!!.isEmpty()) {
finish()
}
@ -198,9 +213,9 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private fun setUpImageView() {
loadCurrentImage()
items = listOf(
getString(io.github.muntashirakon.music.R.string.pick_from_local_storage),
getString(io.github.muntashirakon.music.R.string.web_search),
getString(io.github.muntashirakon.music.R.string.remove_cover)
getString(R.string.pick_from_local_storage),
getString(R.string.web_search),
getString(R.string.remove_cover)
)
editorImage?.setOnClickListener { show }
}
@ -211,7 +226,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
startActivityForResult(
Intent.createChooser(
intent,
getString(io.github.muntashirakon.music.R.string.pick_from_local_storage)
getString(R.string.pick_from_local_storage)
), REQUEST_CODE_SELECT_IMAGE
)
}
@ -223,20 +238,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
protected abstract fun deleteImage()
private fun setUpFab() {
saveFab.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(
MaterialValueHelper.getPrimaryTextColor(
this,
ColorUtil.isColorLight(
ThemeStore.accentColor(
this
)
)
)
).apply {
saveFab.setTextColor(this)
saveFab.iconTint = this
}
saveFab.accentColor()
saveFab.apply {
scaleX = 0f
scaleY = 0f
@ -324,35 +326,25 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
}
protected fun writeValuesToFiles(
fieldKeyValueMap: Map<FieldKey, String>, artworkInfo: ArtworkInfo?
fieldKeyValueMap: Map<FieldKey, String>,
artworkInfo: ArtworkInfo?
) {
RetroUtil.hideSoftKeyboard(this)
hideFab()
savedSongPaths = songPaths
savedTags = fieldKeyValueMap
savedArtworkInfo = artworkInfo
if (!SAFUtil.isSAFRequired(savedSongPaths)) {
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
)
}
}
}
println(fieldKeyValueMap)
WriteTagsAsyncTask(this).execute(
LoadingInfo(
songPaths,
fieldKeyValueMap,
artworkInfo
)
)
}
private fun writeTags(paths: List<String>?) {
WriteTagsAsyncTask(this).execute(
WriteTagsAsyncTask.LoadingInfo(
LoadingInfo(
paths,
savedTags,
savedArtworkInfo
@ -360,6 +352,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
when (requestCode) {
@ -385,7 +378,6 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
}
}
protected abstract fun loadImageFromFile(selectedFile: Uri?)
private fun getAudioFile(path: String): AudioFile {
return try {
@ -396,7 +388,6 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
}
}
class ArtworkInfo constructor(val albumId: Long, val artwork: Bitmap?)
companion object {
@ -405,5 +396,4 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private val TAG = AbsTagEditorActivity::class.java.simpleName
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
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.glide.palette.BitmapPaletteTranscoder
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.util.ImageUtil
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.request.animation.GlideAnimation
import com.bumptech.glide.request.target.SimpleTarget
import java.util.*
import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.tag.FieldKey
import java.util.*
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
@ -155,7 +170,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
override fun save() {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
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.ALBUM_ARTIST] = albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.GENRE] = genreTitle.text.toString()
@ -163,8 +178,11 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
writeValuesToFiles(
fieldKeyValueMap,
if (deleteAlbumArt) ArtworkInfo(id, null)
else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)
when {
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
import android.net.Uri
@ -88,11 +102,7 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
writeValuesToFiles(fieldKeyValueMap, null)
}
override fun getSongPaths(): List<String> {
val paths = ArrayList<String>(1)
paths.add(songRepository.song(id).data)
return paths
}
override fun getSongPaths(): List<String> = listOf(songRepository.song(id).data)
override fun loadImageFromFile(selectedFile: Uri?) {
}
@ -111,5 +121,3 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
val TAG: String = SongTagEditorActivity::class.java.simpleName
}
}

View file

@ -5,67 +5,54 @@ import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
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.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.Tag;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.images.Artwork;
import org.jaudiotagger.tag.images.ArtworkFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import io.github.muntashirakon.music.R;
import io.github.muntashirakon.music.misc.DialogAsyncTask;
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.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(@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();
public WriteTagsAsyncTask(Context context) {
super(context);
}
@Override
protected String[] doInBackground(LoadingInfo... params) {
protected List<String> doInBackground(LoadingInfo... params) {
try {
LoadingInfo info = params[0];
Artwork artwork = null;
File albumArtFile = null;
if (info.artworkInfo != null && info.artworkInfo.getArtwork() != null) {
if (info.getArtworkInfo() != null && info.getArtworkInfo().getArtwork() != null) {
try {
albumArtFile = MusicUtil.INSTANCE.createAlbumArtFile().getCanonicalFile();
info.artworkInfo.getArtwork()
.compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(albumArtFile));
info.getArtworkInfo().getArtwork().compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(albumArtFile));
artwork = ArtworkFactory.createArtworkFromFile(albumArtFile);
} catch (IOException e) {
e.printStackTrace();
@ -75,21 +62,14 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
int counter = 0;
boolean wroteArtwork = false;
boolean deletedArtwork = false;
for (String filePath : info.filePaths) {
publishProgress(++counter, info.filePaths.size());
for (String filePath : info.getFilePaths()) {
publishProgress(++counter, info.getFilePaths().size());
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));
Tag tag = audioFile.getTagOrCreateAndSetDefault();
if (info.fieldKeyValueMap != null) {
for (Map.Entry<FieldKey, String> entry : info.fieldKeyValueMap.entrySet()) {
if (info.getFieldKeyValueMap() != null) {
for (Map.Entry<FieldKey, String> entry : info.getFieldKeyValueMap().entrySet()) {
try {
tag.setField(entry.getKey(), entry.getValue());
} catch (Exception e) {
@ -98,8 +78,8 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
}
}
if (info.artworkInfo != null) {
if (info.artworkInfo.getArtwork() == null) {
if (info.getArtworkInfo() != null) {
if (info.getArtworkInfo().getArtwork() == null) {
tag.deleteArtworkField();
deletedArtwork = true;
} else if (artwork != null) {
@ -109,10 +89,8 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
}
}
Activity activity = this.activity.get();
SAFUtil.write(activity, audioFile, safUri);
} catch (@NonNull Exception e) {
audioFile.commit();
} catch (@NonNull CannotReadException | IOException | CannotWriteException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
e.printStackTrace();
}
}
@ -120,24 +98,13 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
Context context = getContext();
if (context != null) {
if (wroteArtwork) {
MusicUtil.INSTANCE.insertAlbumArt(context, info.artworkInfo.getAlbumId(), albumArtFile.getPath());
MusicUtil.INSTANCE.insertAlbumArt(context, info.getArtworkInfo().getAlbumId(), albumArtFile.getPath());
} else if (deletedArtwork) {
MusicUtil.INSTANCE.deleteAlbumArt(context, info.artworkInfo.getAlbumId());
MusicUtil.INSTANCE.deleteAlbumArt(context, info.getArtworkInfo().getAlbumId());
}
}
Collection<String> paths = info.filePaths;
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()]);
return info.getFilePaths();
} catch (Exception e) {
e.printStackTrace();
return null;
@ -145,48 +112,40 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
}
@Override
protected void onCancelled(String[] toBeScanned) {
super.onCancelled(toBeScanned);
scan(toBeScanned);
}
@Override
protected void onPostExecute(String[] toBeScanned) {
protected void onPostExecute(List<String> toBeScanned) {
super.onPostExecute(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
protected void onProgressUpdate(@NonNull Dialog dialog, Integer... values) {
super.onProgressUpdate(dialog, values);
//((MaterialDialog) dialog).setMaxProgress(values[1]);
//((MaterialDialog) dialog).setProgress(values[0]);
((MaterialDialog) dialog).setMaxProgress(values[1]);
((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.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.checkbox.MaterialCheckBox;
import java.util.List;
import code.name.monkey.appthemehelper.ThemeStore;
import io.github.muntashirakon.music.R;
import io.github.muntashirakon.music.model.CategoryInfo;
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>
implements SwipeAndDragHelper.ActionCompletionContract {
implements SwipeAndDragHelper.ActionCompletionContract {
private List<CategoryInfo> categoryInfos;
private ItemTouchHelper touchHelper;
private List<CategoryInfo> categoryInfos;
private ItemTouchHelper touchHelper;
public CategoryInfoAdapter() {
SwipeAndDragHelper swipeAndDragHelper = new SwipeAndDragHelper(this);
touchHelper = new ItemTouchHelper(swipeAndDragHelper);
}
public CategoryInfoAdapter() {
SwipeAndDragHelper swipeAndDragHelper = new SwipeAndDragHelper(this);
touchHelper = new ItemTouchHelper(swipeAndDragHelper);
}
public void attachToRecyclerView(RecyclerView recyclerView) {
touchHelper.attachToRecyclerView(recyclerView);
}
public void attachToRecyclerView(RecyclerView recyclerView) {
touchHelper.attachToRecyclerView(recyclerView);
}
@NonNull
public List<CategoryInfo> getCategoryInfos() {
return categoryInfos;
}
@NonNull
public List<CategoryInfo> getCategoryInfos() {
return categoryInfos;
}
public void setCategoryInfos(@NonNull List<CategoryInfo> categoryInfos) {
this.categoryInfos = categoryInfos;
notifyDataSetChanged();
}
public void setCategoryInfos(@NonNull List<CategoryInfo> categoryInfos) {
this.categoryInfos = categoryInfos;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return categoryInfos.size();
}
@Override
public int getItemCount() {
return categoryInfos.size();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
CategoryInfo categoryInfo = categoryInfos.get(position);
@SuppressLint("ClickableViewAccessibility")
@Override
public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
CategoryInfo categoryInfo = categoryInfos.get(position);
holder.checkBox.setChecked(categoryInfo.isVisible());
holder.title.setText(holder.title.getResources().getString(categoryInfo.getCategory().getStringRes()));
holder.checkBox.setChecked(categoryInfo.isVisible());
holder.title.setText(
holder.title.getResources().getString(categoryInfo.getCategory().getStringRes()));
holder.itemView.setOnClickListener(v -> {
if (!(categoryInfo.isVisible() && isLastCheckedCategory(categoryInfo))) {
categoryInfo.setVisible(!categoryInfo.isVisible());
holder.checkBox.setChecked(categoryInfo.isVisible());
} else {
Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category,
Toast.LENGTH_SHORT).show();
}
holder.itemView.setOnClickListener(
v -> {
if (!(categoryInfo.isVisible() && isLastCheckedCategory(categoryInfo))) {
categoryInfo.setVisible(!categoryInfo.isVisible());
holder.checkBox.setChecked(categoryInfo.isVisible());
} else {
Toast.makeText(
holder.itemView.getContext(),
R.string.you_have_to_select_at_least_one_category,
Toast.LENGTH_SHORT)
.show();
}
});
holder.dragView.setOnTouchListener((view, event) -> {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
touchHelper.startDrag(holder);
}
return false;
}
);
}
holder.dragView.setOnTouchListener(
(view, event) -> {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
touchHelper.startDrag(holder);
}
return false;
});
}
@Override
@NonNull
public CategoryInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.preference_dialog_library_categories_listitem, parent, false);
return new ViewHolder(view);
}
@Override
@NonNull
public CategoryInfoAdapter.ViewHolder onCreateViewHolder(
@NonNull ViewGroup parent, int viewType) {
View view =
LayoutInflater.from(parent.getContext())
.inflate(R.layout.preference_dialog_library_categories_listitem, parent, false);
return new ViewHolder(view);
}
@Override
public void onViewMoved(int oldPosition, int newPosition) {
CategoryInfo categoryInfo = categoryInfos.get(oldPosition);
categoryInfos.remove(oldPosition);
categoryInfos.add(newPosition, categoryInfo);
notifyItemMoved(oldPosition, newPosition);
}
@Override
public void onViewMoved(int oldPosition, int newPosition) {
CategoryInfo categoryInfo = categoryInfos.get(oldPosition);
categoryInfos.remove(oldPosition);
categoryInfos.add(newPosition, categoryInfo);
notifyItemMoved(oldPosition, newPosition);
}
private boolean isLastCheckedCategory(CategoryInfo categoryInfo) {
if (categoryInfo.isVisible()) {
for (CategoryInfo c : categoryInfos) {
if (c != categoryInfo && c.isVisible()) {
return false;
}
}
private boolean isLastCheckedCategory(CategoryInfo categoryInfo) {
if (categoryInfo.isVisible()) {
for (CategoryInfo c : categoryInfos) {
if (c != categoryInfo && c.isVisible()) {
return false;
}
return true;
}
}
return true;
}
static class ViewHolder extends RecyclerView.ViewHolder {
private MaterialCheckBox checkBox;
private View dragView;
private TextView title;
static class ViewHolder extends RecyclerView.ViewHolder {
private MaterialCheckBox checkBox;
private View dragView;
private TextView title;
ViewHolder(View view) {
super(view);
checkBox = view.findViewById(R.id.checkbox);
checkBox.setButtonTintList(
ColorStateList.valueOf(ThemeStore.Companion.accentColor(checkBox.getContext())));
title = view.findViewById(R.id.title);
dragView = view.findViewById(R.id.drag_view);
}
ViewHolder(View view) {
super(view);
checkBox = view.findViewById(R.id.checkbox);
checkBox.setButtonTintList(
ColorStateList.valueOf(ThemeStore.Companion.accentColor(checkBox.getContext())));
title = view.findViewById(R.id.title);
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
import android.app.Activity
@ -59,6 +73,11 @@ class ContributorAdapter(
return contributors.size
}
fun swapData(it: List<Contributor>) {
contributors = it
notifyDataSetChanged()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.findViewById(R.id.title)
val text: TextView = itemView.findViewById(R.id.text)
@ -68,7 +87,7 @@ class ContributorAdapter(
title.text = contributor.name
text.text = contributor.summary
Glide.with(image.context)
.load(contributor.profileImage)
.load(contributor.image)
.error(R.drawable.ic_account)
.placeholder(R.drawable.ic_account)
.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
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -23,14 +36,12 @@ class GenreAdapter(
var dataSet: List<Genre>,
private val mItemLayoutRes: Int
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
val colors = listOf<Int>(Color.RED, Color.BLUE)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val genre = dataSet[position]
holder.title?.text = genre.name
holder.text?.text = String.format(
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
import android.view.LayoutInflater
@ -15,23 +29,23 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore
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.adapter.album.AlbumAdapter
import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
import io.github.muntashirakon.music.adapter.song.SongAdapter
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.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.util.PreferenceUtil
import com.bumptech.glide.Glide
import com.google.android.material.card.MaterialCardView
class HomeAdapter(
private val activity: AppCompatActivity
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), ArtistClickListener, AlbumClickListener {
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener {
private var list = listOf<Home>()
@ -121,7 +135,6 @@ class HomeAdapter(
viewHolder.bind(home)
}
PLAYLISTS -> {
}
}
}
@ -181,7 +194,6 @@ class HomeAdapter(
.asBitmap()
.build()
.into(itemView.findViewById(id))
}
}
}
@ -225,21 +237,22 @@ class HomeAdapter(
}
fun artistsAdapter(artists: List<Artist>) =
ArtistAdapter(activity, artists, PreferenceUtil.homeGridStyle, null, this)
ArtistAdapter(activity, artists, PreferenceUtil.homeArtistGridStyle, null, this)
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 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(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to artistId),
null,
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),
null,
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
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore
import com.bumptech.glide.Glide
import io.github.muntashirakon.music.*
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.ArtistGlideRequest
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.repository.PlaylistSongsLoader
import io.github.muntashirakon.music.util.MusicUtil
import com.bumptech.glide.Glide
import java.util.*
class SearchAdapter(
private val activity: FragmentActivity,
private var dataSet: List<Any>
) : RecyclerView.Adapter<SearchAdapter.ViewHolder>() {
fun swapDataSet(dataSet: MutableList<Any>) {
fun swapDataSet(dataSet: List<Any>) {
this.dataSet = dataSet
notifyDataSetChanged()
}
@ -34,7 +52,7 @@ class SearchAdapter(
if (dataSet[position] is Album) return ALBUM
if (dataSet[position] is Artist) return ARTIST
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
}
@ -56,42 +74,52 @@ class SearchAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (getItemViewType(position)) {
ALBUM -> {
val album = dataSet.get(position) as Album
holder.imageTextContainer?.isVisible = true
val album = dataSet[position] as Album
holder.title?.text = album.title
holder.text?.text = album.artistName
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore().build().into(holder.image)
}
ARTIST -> {
val artist = dataSet.get(position) as Artist
holder.imageTextContainer?.isVisible = true
val artist = dataSet[position] as Artist
holder.title?.text = artist.name
holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
ArtistGlideRequest.Builder.from(Glide.with(activity), artist).build()
.into(holder.image)
}
SONG -> {
val song = dataSet.get(position) as Song
val song = dataSet[position] as Song
holder.title?.text = song.title
holder.text?.text = song.albumName
}
GENRE -> {
val genre = dataSet.get(position) as Genre
val genre = dataSet[position] as Genre
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 -> {
val playlist = dataSet.get(position) as Playlist
holder.title?.text = playlist.name
holder.text?.text = MusicUtil.getPlaylistInfoString(activity, getSongs(playlist))
val playlist = dataSet[position] as PlaylistWithSongs
holder.title?.text = playlist.playlistEntity.playlistName
holder.text?.text = MusicUtil.playlistInfoString(activity, playlist.songs)
}
else -> {
holder.title?.text = dataSet.get(position).toString()
holder.title?.text = dataSet[position].toString()
holder.title?.setTextColor(ThemeStore.accentColor(activity))
}
}
}
private fun getSongs(playlist: Playlist): java.util.ArrayList<Song> {
val songs = java.util.ArrayList<Song>()
private fun getSongs(playlist: Playlist): List<Song> {
val songs = mutableListOf<Song>()
if (playlist is AbsSmartPlaylist) {
songs.addAll(playlist.getSongs())
} else {
@ -107,7 +135,7 @@ class SearchAdapter(
inner class ViewHolder(itemView: View, itemViewType: Int) : MediaEntryViewHolder(itemView) {
init {
itemView.setOnLongClickListener(null)
imageTextContainer?.isInvisible = true
if (itemViewType == SONG) {
menu?.visibility = View.VISIBLE
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
@ -151,12 +179,12 @@ class SearchAdapter(
}
PLAYLIST -> {
activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to (item as Playlist))
R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to (item as PlaylistWithSongs))
)
}
SONG -> {
val playList = ArrayList<Song>()
val playList = mutableListOf<Song>()
playList.add(item as Song)
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");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* Licensed under the GNU General Public License v3
*
* 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
@ -22,31 +21,31 @@ import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
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.adapter.base.AbsMultiSelectAdapter
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import io.github.muntashirakon.music.glide.audiocover.AudioFileCover
import io.github.muntashirakon.music.interfaces.CabHolder
import io.github.muntashirakon.music.interfaces.Callbacks
import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.interfaces.ICallbacks
import io.github.muntashirakon.music.util.MusicUtil
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.text.DecimalFormat
import kotlin.math.log10
import kotlin.math.pow
import me.zhanghai.android.fastscroll.PopupTextProvider
class SongFileAdapter(
private val activity: AppCompatActivity,
private var dataSet: List<File>,
private val itemLayoutRes: Int,
private val callbacks: Callbacks?,
cabHolder: CabHolder?
private val ICallbacks: ICallbacks?,
ICabHolder: ICabHolder?
) : AbsMultiSelectAdapter<SongFileAdapter.ViewHolder, File>(
activity, cabHolder, R.menu.menu_media_selection
activity, ICabHolder, R.menu.menu_media_selection
), PopupTextProvider {
init {
@ -136,8 +135,8 @@ class SongFileAdapter(
}
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<File>) {
if (callbacks == null) return
callbacks.onMultipleItemAction(menuItem, selection as ArrayList<File>)
if (ICallbacks == null) return
ICallbacks.onMultipleItemAction(menuItem, selection as ArrayList<File>)
}
override fun getPopupText(position: Int): String {
@ -148,15 +147,14 @@ class SongFileAdapter(
return MusicUtil.getSectionName(dataSet[position].name)
}
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init {
if (menu != null && callbacks != null) {
if (menu != null && ICallbacks != null) {
menu?.setOnClickListener { v ->
val position = layoutPosition
if (isPositionInRange(position)) {
callbacks.onFileMenuClicked(dataSet[position], v)
ICallbacks.onFileMenuClicked(dataSet[position], v)
}
}
}
@ -171,7 +169,7 @@ class SongFileAdapter(
if (isInQuickSelectMode) {
toggleChecked(position)
} 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]
}
}
}
}

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
import android.app.Activity
@ -49,4 +63,4 @@ class TranslatorsAdapter(
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
import android.content.res.ColorStateList
@ -6,7 +20,23 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
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 io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
@ -29,11 +59,11 @@ open class AlbumAdapter(
protected val activity: FragmentActivity,
var dataSet: List<Album>,
protected var itemLayoutRes: Int,
cabHolder: CabHolder?,
private val albumClickListener: AlbumClickListener?
ICabHolder: ICabHolder?,
private val albumClickListener: IAlbumClickListener?
) : AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album>(
activity,
cabHolder,
ICabHolder,
R.menu.menu_media_selection
), PopupTextProvider {
@ -75,7 +105,7 @@ open class AlbumAdapter(
holder.title?.text = getAlbumTitle(album)
holder.text?.text = getAlbumText(album)
holder.playSongs?.setOnClickListener {
album.songs?.let { songs ->
album.songs.let { songs ->
MusicPlayerRemote.openQueue(
songs,
0,
@ -116,7 +146,7 @@ open class AlbumAdapter(
}
override fun getItemId(position: Int): Long {
return dataSet[position].id.toLong()
return dataSet[position].id
}
override fun getIdentifier(position: Int): Album? {
@ -128,7 +158,8 @@ open class AlbumAdapter(
}
override fun onMultipleItemAction(
menuItem: MenuItem, selection: List<Album>
menuItem: MenuItem,
selection: List<Album>
) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
}
@ -161,7 +192,7 @@ open class AlbumAdapter(
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init {
setImageTransitionName(activity.getString(R.string.transition_album_art))
setImageTransitionName("Album")
menu?.visibility = View.GONE
}
@ -170,6 +201,7 @@ open class AlbumAdapter(
if (isInQuickSelectMode) {
toggleChecked(layoutPosition)
} else {
ViewCompat.setTransitionName(itemView, "album")
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
import android.os.Bundle
@ -5,6 +19,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.lifecycleScope
@ -88,9 +103,9 @@ class AlbumCoverPagerAdapter(
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
ViewCompat.setTransitionName(view, "lyrics")
albumCover = view.findViewById(R.id.player_image)
albumCover.setOnClickListener {
//LyricsDialog().show(childFragmentManager, "LyricsDialog")
view.setOnClickListener {
showLyricsDialog()
}
return view
@ -98,14 +113,14 @@ class AlbumCoverPagerAdapter(
private fun showLyricsDialog() {
lifecycleScope.launch(Dispatchers.IO) {
val data: String = MusicUtil.getLyrics(song) ?: "No lyrics found"
val data: String? = MusicUtil.getLyrics(song)
withContext(Dispatchers.Main) {
MaterialAlertDialogBuilder(
requireContext(),
R.style.ThemeOverlay_MaterialComponents_Dialog_Alert
).apply {
setTitle(song.title)
setMessage(data)
setMessage(if (data.isNullOrEmpty()) "No lyrics found" else data)
setNegativeButton(R.string.synced_lyrics) { _, _ ->
NavigationUtil.goToLyrics(requireActivity())
}
@ -197,4 +212,3 @@ class AlbumCoverPagerAdapter(
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
import android.view.View
import android.view.ViewGroup
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.RetroMusicColoredTarget
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.util.MusicUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
@ -16,10 +30,10 @@ import com.bumptech.glide.Glide
class HorizontalAlbumAdapter(
activity: FragmentActivity,
dataSet: List<Album>,
cabHolder: CabHolder?,
albumClickListener: AlbumClickListener
ICabHolder: ICabHolder?,
albumClickListener: IAlbumClickListener
) : AlbumAdapter(
activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, cabHolder, albumClickListener
activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, ICabHolder, albumClickListener
) {
override fun createViewHolder(view: View, viewType: Int): ViewHolder {
@ -29,8 +43,8 @@ class HorizontalAlbumAdapter(
}
override fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) {
//holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
//holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
// holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
// holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
}
override fun loadAlbumCover(album: Album, holder: ViewHolder) {
@ -51,7 +65,7 @@ class HorizontalAlbumAdapter(
}
override fun getItemViewType(position: Int): Int {
return HorizontalAdapterHelper.getItemViewtype(position, itemCount)
return HorizontalAdapterHelper.getItemViewType(position, itemCount)
}
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
import android.content.res.ColorStateList
@ -8,31 +22,31 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.fragment.app.FragmentActivity
import com.bumptech.glide.Glide
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.extensions.hide
import io.github.muntashirakon.music.fragments.artists.ArtistClickListener
import io.github.muntashirakon.music.glide.ArtistGlideRequest
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
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.Song
import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
import me.zhanghai.android.fastscroll.PopupTextProvider
import com.bumptech.glide.Glide
import java.util.*
import me.zhanghai.android.fastscroll.PopupTextProvider
class ArtistAdapter(
val activity: FragmentActivity,
var dataSet: List<Artist>,
var itemLayoutRes: Int,
cabHolder: CabHolder?,
private val artistClickListener: ArtistClickListener
val ICabHolder: ICabHolder?,
val IArtistClickListener: IArtistClickListener
) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>(
activity, cabHolder, R.menu.menu_media_selection
activity, ICabHolder, R.menu.menu_media_selection
), PopupTextProvider {
init {
@ -45,7 +59,7 @@ class ArtistAdapter(
}
override fun getItemId(position: Int): Long {
return dataSet[position].id.toLong()
return dataSet[position].id
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -107,7 +121,8 @@ class ArtistAdapter(
}
override fun onMultipleItemAction(
menuItem: MenuItem, selection: List<Artist>
menuItem: MenuItem,
selection: List<Artist>
) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
}
@ -140,11 +155,8 @@ class ArtistAdapter(
toggleChecked(layoutPosition)
} else {
image?.let {
ViewCompat.setTransitionName(
it,
activity.getString(R.string.transition_artist_image)
)
artistClickListener.onArtist(dataSet[layoutPosition].id, it)
ViewCompat.setTransitionName(itemView, "album")
IArtistClickListener.onArtist(dataSet[layoutPosition].id, itemView)
}
}
}

View file

@ -3,132 +3,127 @@ package io.github.muntashirakon.music.adapter.base;
import android.content.Context;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.MenuRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import io.github.muntashirakon.music.R;
import io.github.muntashirakon.music.interfaces.ICabHolder;
import com.afollestad.materialcab.MaterialCab;
import java.util.ArrayList;
import java.util.List;
import io.github.muntashirakon.music.R;
import io.github.muntashirakon.music.interfaces.CabHolder;
public abstract class AbsMultiSelectAdapter<V extends RecyclerView.ViewHolder, I>
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>
implements MaterialCab.Callback {
public AbsMultiSelectAdapter(
@NonNull Context context, @Nullable ICabHolder ICabHolder, @MenuRes int menuRes) {
this.ICabHolder = ICabHolder;
checked = new ArrayList<>();
this.menuRes = menuRes;
this.context = context;
}
@Nullable
private final CabHolder cabHolder;
private final Context context;
private MaterialCab cab;
private List<I> checked;
private int menuRes;
@Override
public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
return true;
}
public AbsMultiSelectAdapter(@NonNull Context context, @Nullable CabHolder cabHolder, @MenuRes int menuRes) {
this.cabHolder = cabHolder;
checked = new ArrayList<>();
this.menuRes = menuRes;
this.context = context;
@Override
public boolean onCabFinished(MaterialCab materialCab) {
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;
}
@Override
public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
return true;
}
@Override
public boolean onCabFinished(MaterialCab materialCab) {
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();
protected void checkAll() {
if (ICabHolder != null) {
checked.clear();
for (int i = 0; i < getItemCount(); i++) {
I identifier = getIdentifier(i);
if (identifier != null) {
checked.add(identifier);
}
return true;
}
notifyDataSetChanged();
updateCab();
}
}
protected void checkAll() {
if (cabHolder != null) {
checked.clear();
for (int i = 0; i < getItemCount(); i++) {
I identifier = getIdentifier(i);
if (identifier != null) {
checked.add(identifier);
}
}
notifyDataSetChanged();
updateCab();
}
}
@Nullable
protected abstract I getIdentifier(int position);
@Nullable
protected abstract I getIdentifier(int position);
protected String getName(I object) {
return object.toString();
}
protected String getName(I object) {
return object.toString();
}
protected boolean isChecked(I identifier) {
return checked.contains(identifier);
}
protected boolean isChecked(I identifier) {
return checked.contains(identifier);
}
protected boolean isInQuickSelectMode() {
return cab != null && cab.isActive();
}
protected boolean isInQuickSelectMode() {
return cab != null && cab.isActive();
}
protected abstract void onMultipleItemAction(MenuItem menuItem, List<I> selection);
protected abstract void onMultipleItemAction(MenuItem menuItem, List<I> selection);
protected void setMultiSelectMenuRes(@MenuRes int menuRes) {
this.menuRes = menuRes;
}
protected void setMultiSelectMenuRes(@MenuRes int menuRes) {
this.menuRes = menuRes;
}
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;
}
protected boolean toggleChecked(final int position) {
if (ICabHolder != null) {
I identifier = getIdentifier(position);
if (identifier == null) {
return false;
}
}
private void clearChecked() {
checked.clear();
notifyDataSetChanged();
}
if (!checked.remove(identifier)) {
checked.add(identifier);
}
private void updateCab() {
if (cabHolder != null) {
if (cab == null || !cab.isActive()) {
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));
}
}
notifyItemChanged(position);
updateCab();
return true;
}
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.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import io.github.muntashirakon.music.R;
import com.google.android.material.card.MaterialCardView;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableSwipeableItemViewHolder;
import io.github.muntashirakon.music.R;
public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHolder
implements View.OnLongClickListener, View.OnClickListener {
implements View.OnLongClickListener, View.OnClickListener {
@Nullable
public View dragView;
@Nullable public View dragView;
@Nullable
public View dummyContainer;
@Nullable public View dummyContainer;
@Nullable
public ImageView image;
@Nullable
public ImageView artistImage;
@Nullable public ImageView image;
@Nullable
public ImageView playerImage;
@Nullable public ImageView artistImage;
@Nullable
public ViewGroup imageContainer;
@Nullable public ImageView playerImage;
@Nullable
public MaterialCardView imageContainerCard;
@Nullable public MaterialCardView imageContainerCard;
@Nullable
public TextView imageText;
@Nullable public TextView imageText;
@Nullable
public MaterialCardView imageTextContainer;
@Nullable public MaterialCardView imageTextContainer;
@Nullable
public View mask;
@Nullable public View mask;
@Nullable
public View menu;
@Nullable public View menu;
@Nullable
public View paletteColorContainer;
@Nullable public View paletteColorContainer;
@Nullable
public ImageButton playSongs;
@Nullable public ImageButton playSongs;
@Nullable
public RecyclerView recyclerView;
@Nullable public RecyclerView recyclerView;
@Nullable
public TextView text;
@Nullable public TextView text;
@Nullable
public TextView time;
@Nullable public TextView text2;
@Nullable
public TextView title;
@Nullable public TextView time;
public MediaEntryViewHolder(@NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
text = itemView.findViewById(R.id.text);
@Nullable public TextView title;
image = itemView.findViewById(R.id.image);
artistImage = itemView.findViewById(R.id.artistImage);
playerImage = itemView.findViewById(R.id.player_image);
time = itemView.findViewById(R.id.time);
public MediaEntryViewHolder(@NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
text = itemView.findViewById(R.id.text);
text2 = itemView.findViewById(R.id.text2);
imageText = itemView.findViewById(R.id.imageText);
imageContainer = itemView.findViewById(R.id.imageContainer);
imageTextContainer = itemView.findViewById(R.id.imageTextContainer);
imageContainerCard = itemView.findViewById(R.id.imageContainerCard);
image = itemView.findViewById(R.id.image);
artistImage = itemView.findViewById(R.id.artistImage);
playerImage = itemView.findViewById(R.id.player_image);
time = itemView.findViewById(R.id.time);
menu = itemView.findViewById(R.id.menu);
dragView = itemView.findViewById(R.id.drag_view);
paletteColorContainer = itemView.findViewById(R.id.paletteColorContainer);
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);
imageText = itemView.findViewById(R.id.imageText);
imageTextContainer = itemView.findViewById(R.id.imageTextContainer);
imageContainerCard = itemView.findViewById(R.id.imageContainerCard);
if (imageContainerCard != null) {
imageContainerCard.setCardBackgroundColor(Color.TRANSPARENT);
}
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
menu = itemView.findViewById(R.id.menu);
dragView = itemView.findViewById(R.id.drag_view);
paletteColorContainer = itemView.findViewById(R.id.paletteColorContainer);
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) {
imageContainerCard.setCardBackgroundColor(Color.TRANSPARENT);
}
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
@Nullable
@Override
public View getSwipeableContainerView() {
return null;
}
@Override
public void onClick(View v) {
}
@Override
public boolean onLongClick(View v) {
return false;
}
public void setImageTransitionName(@NonNull String transitionName) {
itemView.setTransitionName(transitionName);
/* if (imageContainerCard != null) {
imageContainerCard.setTransitionName(transitionName);
}
if (image != null) {
image.setTransitionName(transitionName);
}*/
@Nullable
@Override
public View getSwipeableContainerView() {
return null;
}
@Override
public void onClick(View v) {}
@Override
public boolean onLongClick(View v) {
return false;
}
public void setImageTransitionName(@NonNull String transitionName) {
itemView.setTransitionName(transitionName);
/* if (imageContainerCard != null) {
imageContainerCard.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
import android.view.LayoutInflater
@ -49,4 +63,4 @@ class LegacyPlaylistAdapter(
interface PlaylistClickListener {
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
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.os.AsyncTask
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu
import androidx.core.os.bundleOf
import androidx.core.view.ViewCompat
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.TintHelper
import io.github.muntashirakon.music.EXTRA_PLAYLIST
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
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.helper.menu.PlaylistMenuHelper
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
import io.github.muntashirakon.music.interfaces.CabHolder
import io.github.muntashirakon.music.model.Playlist
import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.interfaces.IPlaylistClickListener
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.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(
private val activity: FragmentActivity,
var dataSet: List<PlaylistWithSongs>,
private var dataSet: List<PlaylistWithSongs>,
private var itemLayoutRes: Int,
cabHolder: CabHolder?
ICabHolder: ICabHolder?,
private val listener: IPlaylistClickListener
) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, PlaylistWithSongs>(
activity,
cabHolder,
ICabHolder,
R.menu.menu_playlists_selection
) {
@ -56,7 +70,7 @@ class PlaylistAdapter(
}
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 {
@ -88,7 +102,7 @@ class PlaylistAdapter(
} else {
holder.menu?.show()
}
//PlaylistBitmapLoader(this, holder, playlist).execute()
//playlistBitmapLoader(activity, holder, playlist)
}
private fun getIconRes(): Drawable = TintHelper.createTintedDrawable(
@ -158,10 +172,8 @@ class PlaylistAdapter(
if (isInQuickSelectMode) {
toggleChecked(layoutPosition)
} else {
activity.findNavController(R.id.fragment_container).navigate(
R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to dataSet[layoutPosition])
)
ViewCompat.setTransitionName(itemView, "playlist")
listener.onPlaylistClick(dataSet[layoutPosition], itemView)
}
}
@ -171,28 +183,35 @@ class PlaylistAdapter(
}
}
class PlaylistBitmapLoader(
private var adapter: PlaylistAdapter,
private var viewHolder: ViewHolder,
private var playlist: Playlist
) : AsyncTask<Void, Void, Bitmap>() {
private fun playlistBitmapLoader(
activity: FragmentActivity,
viewHolder: ViewHolder,
playlist: PlaylistWithSongs
) {
override fun doInBackground(vararg params: Void?): Bitmap {
val songs = PlaylistSongsLoader.getPlaylistSongList(adapter.activity, playlist)
return AutoGeneratedPlaylistBitmap.getBitmap(adapter.activity, songs, false, false)
activity.lifecycleScope.launch(IO) {
val songs = playlist.songs.toSongs()
val bitmap = AutoGeneratedPlaylistBitmap.getBitmap(activity, songs, false, false)
withContext(Main) { viewHolder.image?.setImageBitmap(bitmap) }
}
override fun onPostExecute(result: Bitmap?) {
super.onPostExecute(result)
viewHolder.image?.setImageBitmap(result)
val color = RetroColorUtil.getColor(
RetroColorUtil.generatePalette(
result
),
ATHUtil.resolveColor(adapter.activity, R.attr.colorSurface)
)
viewHolder.paletteColorContainer?.setBackgroundColor(color)
}
/*
override fun doInBackground(vararg params: Void?): Bitmap {
val songs = playlist.songs.toSongs()
return AutoGeneratedPlaylistBitmap.getBitmap(activity, songs, false, false)
}
override fun onPostExecute(result: Bitmap?) {
super.onPostExecute(result)
viewHolder.image?.setImageBitmap(result)
val color = RetroColorUtil.getColor(
RetroColorUtil.generatePalette(
result
),
ATHUtil.resolveColor(activity, R.attr.colorSurface)
)
viewHolder.paletteColorContainer?.setBackgroundColor(color)
}*/
}
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
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
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.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.CabHolder
import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Song
abstract class AbsOffsetSongAdapter(
activity: AppCompatActivity,
activity: FragmentActivity,
dataSet: MutableList<Song>,
@LayoutRes itemLayoutRes: Int,
cabHolder: CabHolder?
) : SongAdapter(activity, dataSet, itemLayoutRes, cabHolder) {
ICabHolder: ICabHolder?
) : SongAdapter(activity, dataSet, itemLayoutRes, ICabHolder) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder {
if (viewType == OFFSET_ITEM) {
@ -76,4 +90,4 @@ abstract class AbsOffsetSongAdapter(
const val OFFSET_ITEM = 0
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
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.toSongs
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.Song
import io.github.muntashirakon.music.util.ViewUtil
@ -23,13 +37,13 @@ class OrderablePlaylistSongAdapter(
activity: FragmentActivity,
dataSet: ArrayList<Song>,
itemLayoutRes: Int,
cabHolder: CabHolder?,
ICabHolder: ICabHolder?,
private val onMoveItemListener: OnMoveItemListener?
) : SongAdapter(
activity,
dataSet,
itemLayoutRes,
cabHolder
ICabHolder
), DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
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
import android.view.MenuItem
@ -5,6 +19,8 @@ import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
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.isPlaying
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.util.MusicUtil
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.ItemDraggableRange
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
@ -41,8 +59,8 @@ class PlayingQueueAdapter(
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
super.onBindViewHolder(holder, position)
holder.imageText?.text = (position - current).toString()
holder.time?.text = MusicUtil.getReadableDurationString(dataSet[position].duration)
val song = dataSet[position]
holder.time?.text = MusicUtil.getReadableDurationString(song.duration)
if (holder.itemViewType == HISTORY || holder.itemViewType == CURRENT) {
setAlpha(holder, 0.5f)
}
@ -58,7 +76,17 @@ class PlayingQueueAdapter(
}
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) {
@ -76,7 +104,6 @@ class PlayingQueueAdapter(
holder.image?.alpha = alpha
holder.title?.alpha = alpha
holder.text?.alpha = alpha
holder.imageText?.alpha = alpha
holder.paletteColorContainer?.alpha = alpha
holder.dragView?.alpha = alpha
holder.menu?.alpha = alpha
@ -129,7 +156,6 @@ class PlayingQueueAdapter(
}
init {
imageText?.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 {
return if (onCheckCanStartDrag(holder!!, position, x, y)) {
return if (onCheckCanStartDrag(holder, position, x, y)) {
SwipeableItemConstants.REACTION_CAN_NOT_SWIPE_BOTH_H
} else {
SwipeableItemConstants.REACTION_CAN_SWIPE_BOTH_H
@ -196,17 +222,17 @@ class PlayingQueueAdapter(
private val isPlaying: Boolean = MusicPlayerRemote.isPlaying
private val songProgressMillis = 0
override fun onPerformAction() {
//currentlyShownSnackbar = null
// currentlyShownSnackbar = null
}
override fun onSlideAnimationEnd() {
//initializeSnackBar(adapter, position, activity, isPlaying)
// initializeSnackBar(adapter, position, activity, isPlaying)
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!!)) {
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!!)
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
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
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 androidx.fragment.app.FragmentActivity
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.CabHolder
import com.google.android.material.button.MaterialButton
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
open class PlaylistSongAdapter(
activity: AppCompatActivity,
private val playlist: PlaylistEntity,
activity: FragmentActivity,
dataSet: MutableList<Song>,
itemLayoutRes: Int,
cabHolder: CabHolder?
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) {
ICabHolder: ICabHolder?
) : SongAdapter(activity, dataSet, itemLayoutRes, ICabHolder) {
init {
this.setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection)
@ -27,45 +41,23 @@ open class PlaylistSongAdapter(
return ViewHolder(view)
}
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
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)
open inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) {
override var songMenuRes: Int
get() = R.menu.menu_item_cannot_delete_single_songs_playlist_song
get() = R.menu.menu_item_playlist_song
set(value) {
super.songMenuRes = value
}
override fun onSongMenuItemClick(item: MenuItem): Boolean {
if (item.itemId == R.id.action_go_to_album) {
activity.findNavController(R.id.fragment_container)
.navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to song.albumId)
)
return true
when (item.itemId) {
R.id.action_remove_from_playlist -> {
RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlist.playListId))
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
return true
}
}
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
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import io.github.muntashirakon.music.R
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 com.google.android.material.button.MaterialButton
@ -12,8 +26,8 @@ class ShuffleButtonSongAdapter(
activity: AppCompatActivity,
dataSet: MutableList<Song>,
itemLayoutRes: Int,
cabHolder: CabHolder?
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) {
ICabHolder: ICabHolder?
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, ICabHolder) {
override fun createViewHolder(view: View): SongAdapter.ViewHolder {
return ViewHolder(view)
@ -49,4 +63,4 @@ class ShuffleButtonSongAdapter(
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
import android.view.LayoutInflater
import android.view.ViewGroup
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.util.MusicUtil
import java.util.*
@ -12,8 +26,8 @@ class SimpleSongAdapter(
context: FragmentActivity,
songs: ArrayList<Song>,
layoutRes: Int,
cabHolder: CabHolder?
) : SongAdapter(context, songs, layoutRes, cabHolder) {
ICabHolder: ICabHolder?
) : SongAdapter(context, songs, layoutRes, ICabHolder) {
override fun swapDataSet(dataSet: List<Song>) {
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
import android.content.res.ColorStateList
@ -7,10 +21,9 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity
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.R
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.menu.SongMenuHelper
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.util.MusicUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
import com.afollestad.materialcab.MaterialCab
import com.bumptech.glide.Glide
import me.zhanghai.android.fastscroll.PopupTextProvider
/**
@ -38,11 +53,11 @@ open class SongAdapter(
protected val activity: FragmentActivity,
var dataSet: MutableList<Song>,
protected var itemLayoutRes: Int,
cabHolder: CabHolder?,
ICabHolder: ICabHolder?,
showSectionName: Boolean = true
) : AbsMultiSelectAdapter<SongAdapter.ViewHolder, Song>(
activity,
cabHolder,
ICabHolder,
R.menu.menu_media_selection
), MaterialCab.Callback, PopupTextProvider {
@ -59,7 +74,7 @@ open class SongAdapter(
}
override fun getItemId(position: Int): Long {
return dataSet[position].id.toLong()
return dataSet[position].id
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -87,6 +102,7 @@ open class SongAdapter(
}
holder.title?.text = getSongTitle(song)
holder.text?.text = getSongText(song)
holder.text2?.text = getSongText(song)
loadAlbumCover(song, holder)
}
@ -121,6 +137,10 @@ open class SongAdapter(
return song.artistName
}
private fun getSongText2(song: Song): String? {
return song.albumName
}
override fun getItemCount(): Int {
return dataSet.size
}
@ -157,7 +177,6 @@ open class SongAdapter(
get() = dataSet[layoutPosition]
init {
setImageTransitionName(activity.getString(R.string.transition_album_art))
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
override val song: Song
get() = this@ViewHolder.song
@ -172,7 +191,7 @@ open class SongAdapter(
}
protected open fun onSongMenuItemClick(item: MenuItem): Boolean {
if (image != null && image!!.visibility == View.VISIBLE) {
if (image != null && image!!.isVisible) {
when (item.itemId) {
R.id.action_go_to_album -> {
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
*
* 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 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.appshortcuts
import android.content.Context
@ -60,7 +60,10 @@ object AppShortcutIconGenerator {
}
private fun generateThemedIcon(
context: Context, iconId: Int, foregroundColor: Int, backgroundColor: Int
context: Context,
iconId: Int,
foregroundColor: Int,
backgroundColor: Int
): Icon {
// Get and tint foreground and background drawables
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
*
* 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 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.appshortcuts
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.ShuffleAllShortcutType
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.smartplaylist.LastAddedPlaylist
import io.github.muntashirakon.music.model.smartplaylist.ShuffleAllPlaylist
@ -31,16 +32,7 @@ class AppShortcutLauncherActivity : Activity() {
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
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) {
when (extraNotNull(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE).value) {
SHORTCUT_TYPE_SHUFFLE_ALL -> {
startServiceWithPlaylist(
SHUFFLE_MODE_SHUFFLE, ShuffleAllPlaylist()
@ -78,9 +70,9 @@ class AppShortcutLauncherActivity : Activity() {
companion object {
const val KEY_SHORTCUT_TYPE = "io.github.muntashirakon.Music.appshortcuts.ShortcutType"
const val SHORTCUT_TYPE_SHUFFLE_ALL = 0
const val SHORTCUT_TYPE_TOP_TRACKS = 1
const val SHORTCUT_TYPE_LAST_ADDED = 2
const val SHORTCUT_TYPE_NONE = 4
const val SHORTCUT_TYPE_SHUFFLE_ALL = 0L
const val SHORTCUT_TYPE_TOP_TRACKS = 1L
const val SHORTCUT_TYPE_LAST_ADDED = 2L
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
*
* 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 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.appshortcuts
import android.annotation.TargetApi
@ -32,16 +32,16 @@ class DynamicShortcutManager(private val context: Context) {
this.context.getSystemService(ShortcutManager::class.java)
private val defaultShortcuts: List<ShortcutInfo>
get() = Arrays.asList(
get() = listOf(
ShuffleAllShortcutType(context).shortcutInfo,
TopTracksShortcutType(context).shortcutInfo,
LastAddedShortcutType(context).shortcutInfo
)
fun initDynamicShortcuts() {
//if (shortcutManager.dynamicShortcuts.size == 0) {
// if (shortcutManager.dynamicShortcuts.size == 0) {
shortcutManager.dynamicShortcuts = defaultShortcuts
//}
// }
}
fun updateDynamicShortcuts() {
@ -58,8 +58,12 @@ class DynamicShortcutManager(private val context: Context) {
icon: Icon,
intent: Intent
): ShortcutInfo {
return ShortcutInfo.Builder(context, id).setShortLabel(shortLabel)
.setLongLabel(longLabel).setIcon(icon).setIntent(intent).build()
return ShortcutInfo.Builder(context, id)
.setShortLabel(shortLabel)
.setLongLabel(longLabel)
.setIcon(icon)
.setIntent(intent)
.build()
}
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
*
* 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 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.appshortcuts.shortcuttype
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.)
* @return
*/
internal fun getPlaySongsIntent(shortcutType: Int): Intent {
internal fun getPlaySongsIntent(shortcutType: Long): Intent {
val intent = Intent(context, AppShortcutLauncherActivity::class.java)
intent.action = Intent.ACTION_VIEW
val b = Bundle()
b.putInt(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType)
b.putLong(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType)
intent.putExtras(b)
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
*
* 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 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.appshortcuts.shortcuttype
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
*
* 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 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.appshortcuts.shortcuttype
import android.annotation.TargetApi
@ -26,20 +26,16 @@ import io.github.muntashirakon.music.appshortcuts.AppShortcutLauncherActivity
class ShuffleAllShortcutType(context: Context) : BaseShortcutType(context) {
override val shortcutInfo: ShortcutInfo
get() = ShortcutInfo.Builder(
context, id
).setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short)).setLongLabel(
context.getString(R.string.app_shortcut_shuffle_all_long)
).setIcon(
AppShortcutIconGenerator.generateThemedIcon(
context, R.drawable.ic_app_shortcut_shuffle_all
)
).setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL))
get() = ShortcutInfo.Builder(context, id)
.setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short))
.setLongLabel(context.getString(R.string.app_shortcut_shuffle_all_long))
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_shuffle_all))
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL))
.build()
companion object {
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
*
* 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 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.appshortcuts.shortcuttype
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
*
* 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 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.appwidgets
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.service.MusicService
import io.github.muntashirakon.music.service.MusicService.*
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.request.animation.GlideAnimation
@ -193,8 +194,11 @@ class AppWidgetBig : BaseAppWidget() {
* Link up various button actions using [PendingIntent].
*/
private fun linkButtons(context: Context, views: RemoteViews) {
val action =
Intent(context, MainActivity::class.java).putExtra(MainActivity.EXPAND_PANEL, true)
val action = Intent(context, MainActivity::class.java)
.putExtra(
MainActivity.EXPAND_PANEL,
PreferenceUtil.isExpandPanel
)
var pendingIntent: PendingIntent
val serviceName = ComponentName(context, MusicService::class.java)
@ -229,6 +233,5 @@ class AppWidgetBig : BaseAppWidget() {
}
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
*
* 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 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.appwidgets
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.util.ImageUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.request.animation.GlideAnimation
@ -217,7 +218,11 @@ class AppWidgetCard : BaseAppWidget() {
* Link up various button actions using [PendingIntent].
*/
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
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
*
* 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 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.appwidgets
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.util.ImageUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.request.animation.GlideAnimation
@ -49,7 +50,6 @@ class AppWidgetClassic : BaseAppWidget() {
override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) {
val appWidgetView = RemoteViews(context.packageName, R.layout.app_widget_classic)
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE)
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_audio_art)
appWidgetView.setImageViewBitmap(
@ -208,7 +208,11 @@ class AppWidgetClassic : BaseAppWidget() {
* Link up various button actions using [PendingIntent].
*/
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
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
*
* 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 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.appwidgets
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.service.MusicService
import io.github.muntashirakon.music.service.MusicService.*
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.request.animation.GlideAnimation
@ -192,7 +193,11 @@ class AppWidgetSmall : BaseAppWidget() {
* Link up various button actions using [PendingIntent].
*/
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
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
*
* 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 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.appwidgets
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.service.MusicService
import io.github.muntashirakon.music.service.MusicService.*
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil
class AppWidgetText : BaseAppWidget() {
@ -77,7 +78,11 @@ class AppWidgetText : BaseAppWidget() {
* Link up various button actions using [PendingIntent].
*/
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
val serviceName = ComponentName(context, MusicService::class.java)
@ -153,10 +158,7 @@ class AppWidgetText : BaseAppWidget() {
)
)
pushUpdate(service.applicationContext, appWidgetIds, appWidgetView)
}
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
*
* 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 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.appwidgets
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
*
* 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 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.appwidgets.base
import android.app.PendingIntent
@ -40,7 +40,9 @@ abstract class BaseAppWidget : AppWidgetProvider() {
* {@inheritDoc}
*/
override fun onUpdate(
context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
defaultAppWidget(context, appWidgetIds)
val updateIntent = Intent(APP_WIDGET_UPDATE)
@ -62,7 +64,9 @@ abstract class BaseAppWidget : AppWidgetProvider() {
}
protected fun pushUpdate(
context: Context, appWidgetIds: IntArray?, views: RemoteViews
context: Context,
appWidgetIds: IntArray?,
views: RemoteViews
) {
val appWidgetManager = AppWidgetManager.getInstance(context)
if (appWidgetIds != null) {
@ -86,7 +90,9 @@ abstract class BaseAppWidget : AppWidgetProvider() {
}
protected fun buildPendingIntent(
context: Context, action: String, serviceName: ComponentName
context: Context,
action: String,
serviceName: ComponentName
): PendingIntent {
val intent = Intent(action)
intent.component = serviceName
@ -169,7 +175,11 @@ abstract class BaseAppWidget : AppWidgetProvider() {
}
protected fun composeRoundedRectPath(
rect: RectF, tl: Float, tr: Float, bl: Float, br: Float
rect: RectF,
tl: Float,
tr: Float,
bl: Float,
br: Float
): Path {
val path = Path()
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
import androidx.room.*
@ -18,4 +32,4 @@ interface BlackListStoreDao {
@Query("SELECT * FROM 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
import androidx.room.Entity
@ -7,4 +21,4 @@ import androidx.room.PrimaryKey
class BlackListStoreEntity(
@PrimaryKey
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
import androidx.lifecycle.LiveData
@ -23,4 +37,4 @@ interface HistoryDao {
@Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC LIMIT $HISTORY_LIMIT")
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
import androidx.room.ColumnInfo
@ -29,4 +43,4 @@ class HistoryEntity(
val albumArtist: String?,
@ColumnInfo(name = "time_played")
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
import androidx.room.*
@ -15,4 +29,4 @@ interface LyricsDao {
@Update
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
import androidx.room.Entity
@ -7,4 +21,4 @@ import androidx.room.PrimaryKey
class LyricsEntity(
@PrimaryKey val songId: Int,
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
import androidx.room.*
@ -24,4 +38,4 @@ interface PlayCountDao {
@Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id")
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
import androidx.room.ColumnInfo
@ -31,4 +45,4 @@ class PlayCountEntity(
val timePlayed: Long,
@ColumnInfo(name = "play_count")
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
import androidx.lifecycle.LiveData
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
interface PlaylistDao {
@ -48,12 +59,9 @@ interface PlaylistDao {
@Delete
suspend fun deletePlaylistSongs(songs: List<SongEntity>)
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
fun favoritesSongsLiveData(playlistId: Long): LiveData<List<SongEntity>>
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
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
import android.os.Parcelable
@ -14,4 +28,4 @@ class PlaylistEntity(
val playListId: Long = 0,
@ColumnInfo(name = "playlist_name")
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
import android.os.Parcelable
@ -14,4 +28,3 @@ data class PlaylistWithSongs(
)
val songs: List<SongEntity>
) : 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
import androidx.room.Database
@ -14,4 +28,4 @@ abstract class RetroDatabase : RoomDatabase() {
abstract fun playCountDao(): PlayCountDao
abstract fun historyDao(): HistoryDao
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
import android.os.Parcelable
@ -36,4 +50,3 @@ class SongEntity(
@ColumnInfo(name = "album_artist")
val albumArtist: String?
) : 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
import io.github.muntashirakon.music.model.Song
fun List<HistoryEntity>.fromHistoryToSongs(): List<Song> {
return map {
it.toSong()
}
}
fun List<SongEntity>.toSongs(): List<Song> {
return map {
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
import android.app.Dialog
import android.os.Bundle
import android.widget.ArrayAdapter
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
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.R
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.extensions.colorButtons
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 {
val playlistEntities: List<PlaylistEntity> =
extraNotNull<List<PlaylistEntity>>(EXTRA_PLAYLISTS).value
val songs: List<Song> = extraNotNull<List<Song>>(EXTRA_SONG).value
val playlistNames: MutableList<String> = mutableListOf()
val playlistEntities = extraNotNull<List<PlaylistEntity>>(EXTRA_PLAYLISTS).value
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
val playlistNames = mutableListOf<String>()
playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist))
for (entity: PlaylistEntity in playlistEntities) {
playlistNames.add(entity.playlistName)
}
return materialDialog(R.string.add_playlist_title)
.setItems(playlistNames.toTypedArray()) { _, which ->
.setAdapter(
playlistAdapter(playlistNames)
) { dialog, which ->
if (which == 0) {
CreatePlaylistDialog.create(songs)
.show(requireActivity().supportFragmentManager, "Dialog")
showCreateDialog(songs)
} else {
lifecycleScope.launch(Dispatchers.IO) {
val songEntities: List<SongEntity> =
songs.toSongsEntity(playlistEntities[which - 1])
val songEntities = songs.toSongsEntity(playlistEntities[which - 1])
libraryViewModel.insertSongs(songEntities)
libraryViewModel.forceReload(Playlists)
}
}
dismiss()
dialog.dismiss()
}
.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.Environment;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.DialogFragment;
import code.name.monkey.retromusic.R;
import com.afollestad.materialdialogs.MaterialDialog;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
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();
private File parentFolder;
private File[] parentContents;
private boolean canGoUp = false;
private FolderCallback callback;
public static BlacklistFolderChooserDialog create() {
return new BlacklistFolderChooserDialog();
}
public static BlacklistFolderChooserDialog create() {
return new BlacklistFolderChooserDialog();
private String[] getContentsArray() {
if (parentContents == null) {
if (canGoUp) {
return new String[] {".."};
}
return new String[] {};
}
private String[] getContentsArray() {
if (parentContents == null) {
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;
String[] results = new String[parentContents.length + (canGoUp ? 1 : 0)];
if (canGoUp) {
results[0] = "..";
}
private File[] listFiles() {
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;
for (int i = 0; i < parentContents.length; i++) {
results[canGoUp ? i + 1 : i] = parentContents[i].getName();
}
return results;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ActivityCompat.checkSelfPermission(
private File[] listFiles() {
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;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ActivityCompat.checkSelfPermission(
requireActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
return new MaterialDialog.Builder(requireActivity())
.title(R.string.md_error_label)
.content(R.string.md_storage_perm_error)
.positiveText(android.R.string.ok)
.build();
}
if (savedInstanceState == null) {
savedInstanceState = new Bundle();
}
if (!savedInstanceState.containsKey("current_path")) {
savedInstanceState.putString("current_path", initialPath);
}
parentFolder = new File(savedInstanceState.getString("current_path", File.pathSeparator));
checkIfCanGoUp();
parentContents = listFiles();
MaterialDialog.Builder builder = new MaterialDialog.Builder(requireContext())
.title(parentFolder.getAbsolutePath())
.items((CharSequence[]) getContentsArray())
.itemsCallback(this)
.autoDismiss(false)
.onPositive((dialog, which) -> {
callback.onFolderSelection(BlacklistFolderChooserDialog.this, parentFolder);
dismiss();
!= PackageManager.PERMISSION_GRANTED) {
return new MaterialDialog.Builder(requireActivity())
.title(R.string.md_error_label)
.content(R.string.md_storage_perm_error)
.positiveText(android.R.string.ok)
.build();
}
if (savedInstanceState == null) {
savedInstanceState = new Bundle();
}
if (!savedInstanceState.containsKey("current_path")) {
savedInstanceState.putString("current_path", initialPath);
}
parentFolder = new File(savedInstanceState.getString("current_path", File.pathSeparator));
checkIfCanGoUp();
parentContents = listFiles();
MaterialDialog.Builder builder =
new MaterialDialog.Builder(requireContext())
.title(parentFolder.getAbsolutePath())
.items((CharSequence[]) getContentsArray())
.itemsCallback(this)
.autoDismiss(false)
.onPositive(
(dialog, which) -> {
callback.onFolderSelection(BlacklistFolderChooserDialog.this, parentFolder);
dismiss();
})
.onNegative((materialDialog, dialogAction) -> dismiss())
.positiveText(R.string.add_action)
.negativeText(android.R.string.cancel);
return builder.build();
.onNegative((materialDialog, dialogAction) -> dismiss())
.positiveText(R.string.add_action)
.negativeText(android.R.string.cancel);
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
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();
public int compare(File lhs, File rhs) {
return lhs.getName().compareTo(rhs.getName());
}
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
import android.app.Dialog
@ -26,7 +40,7 @@ import kotlinx.coroutines.launch
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class CreatePlaylistDialog : DialogFragment() {
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
private val io.github.muntashirakon.music by sharedViewModel<LibraryViewModel>()
companion object {
fun create(song: Song): CreatePlaylistDialog {
@ -54,17 +68,8 @@ class CreatePlaylistDialog : DialogFragment() {
) { _, _ ->
val playlistName = playlistView.text.toString()
if (!TextUtils.isEmpty(playlistName)) {
lifecycleScope.launch(Dispatchers.IO) {
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()
}
}
io.github.muntashirakon.music.addToPlaylist(playlistName, songs)
} else {
playlistContainer.error = "Playlist is can't be empty"
}
@ -72,4 +77,4 @@ class CreatePlaylistDialog : DialogFragment() {
.create()
.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
import android.app.Dialog
@ -65,5 +79,4 @@ class DeletePlaylistDialog : DialogFragment() {
.create()
.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
import android.app.Dialog
@ -67,4 +81,4 @@ class DeleteSongsDialog : DialogFragment() {
.create()
.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
import android.app.Dialog
@ -21,4 +35,4 @@ class ImportPlaylistDialog : DialogFragment() {
.create()
.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
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.materialDialog
import io.github.muntashirakon.music.fragments.LibraryViewModel
import io.github.muntashirakon.music.fragments.ReloadType.Playlists
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class RemoveSongFromPlaylistDialog : DialogFragment() {
@ -60,10 +73,9 @@ class RemoveSongFromPlaylistDialog : DialogFragment() {
.setMessage(pair.second)
.setPositiveButton(R.string.remove_action) { _, _ ->
libraryViewModel.deleteSongsInPlaylist(songs)
libraryViewModel.forceReload(Playlists)
}
.setNegativeButton(android.R.string.cancel, null)
.create()
.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
import android.app.Dialog
@ -54,4 +68,4 @@ class RenamePlaylistDialog : DialogFragment() {
.create()
.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
import android.app.Dialog
import android.media.MediaScannerConnection
import android.os.Bundle
import android.widget.Toast
import androidx.core.os.bundleOf
@ -18,7 +33,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class SavePlaylistDialog : DialogFragment() {
companion object {
fun create(playlistWithSongs: PlaylistWithSongs): SavePlaylistDialog {
@ -33,9 +47,14 @@ class SavePlaylistDialog : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch(Dispatchers.IO) {
val playlistWithSongs: PlaylistWithSongs =
extraNotNull<PlaylistWithSongs>(EXTRA_PLAYLIST).value
val file = PlaylistsUtil.savePlaylistWithSongs(requireContext(), playlistWithSongs)
val playlistWithSongs = extraNotNull<PlaylistWithSongs>(EXTRA_PLAYLIST).value
val file = PlaylistsUtil.savePlaylistWithSongs(playlistWithSongs)
MediaScannerConnection.scanFile(
requireActivity(),
arrayOf<String>(file.path),
null
) { _, _ ->
}
withContext(Dispatchers.Main) {
Toast.makeText(
requireContext(),
@ -52,4 +71,4 @@ class SavePlaylistDialog : DialogFragment() {
.setView(R.layout.loading)
.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
*
* 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 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
import android.annotation.SuppressLint
@ -130,7 +130,6 @@ class SleepTimerDialog : DialogFragment() {
}
.create()
.colorButtons()
}
private fun updateTimeDisplayTime() {
@ -173,4 +172,4 @@ class SleepTimerDialog : DialogFragment() {
updateCancelButton()
}
}
}
}

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