From fe890632fd3dce7df4bc98b27a4441951aa10144 Mon Sep 17 00:00:00 2001 From: h4h13 Date: Fri, 27 Jul 2018 18:37:33 +0530 Subject: [PATCH] Initial commit retro music app --- .idea/RetroMusicPlayer.iml | 9 + .idea/codeStyles/Project.xml | 29 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + RetroMusicPlayer.iml | 19 + app/app.iml | 226 +++ app/build.gradle | 145 ++ app/libs/jaudiotagger-android-2.2.3.jar | Bin 0 -> 967450 bytes app/libs/jsoup-1.11.2.jar | Bin 0 -> 392350 bytes app/libs/juniversalchardet-1.0.3.jar | Bin 0 -> 206373 bytes app/proguard-rules.pro | 75 + app/src/main/AndroidManifest.xml | 244 +++ .../main/assets/fonts/circular_std_black.otf | Bin 0 -> 74500 bytes .../main/assets/fonts/circular_std_book.otf | Bin 0 -> 68940 bytes .../main/assets/fonts/product_sans_bold.ttf | Bin 0 -> 55548 bytes .../assets/fonts/product_sans_regular.ttf | Bin 0 -> 41116 bytes app/src/main/assets/index.html | 57 + app/src/main/ic_launcher-web.png | Bin 0 -> 60177 bytes .../name/monkey/retromusic/Constants.java | 48 + .../name/monkey/retromusic/Injection.java | 23 + .../monkey/retromusic/RetroApplication.java | 77 + .../AppShortcutIconGenerator.java | 71 + .../AppShortcutLauncherActivity.java | 77 + .../appshortcuts/DynamicShortcutManager.java | 63 + .../shortcuttype/BaseShortcutType.java | 50 + .../shortcuttype/LastAddedShortcutType.java | 34 + .../shortcuttype/ShuffleAllShortcutType.java | 35 + .../shortcuttype/TopTracksShortcutType.java | 35 + .../retromusic/appwidgets/AppWidgetBig.java | 171 ++ .../retromusic/appwidgets/AppWidgetCard.java | 194 +++ .../appwidgets/AppWidgetClassic.java | 181 +++ .../retromusic/appwidgets/AppWidgetSmall.java | 186 +++ .../retromusic/appwidgets/BootReceiver.java | 32 + .../appwidgets/base/BaseAppWidget.java | 162 ++ .../dialogs/AddToPlaylistDialog.java | 94 ++ .../dialogs/BlacklistFolderChooserDialog.java | 159 ++ .../dialogs/ClearSmartPlaylistDialog.java | 52 + .../dialogs/CreatePlaylistDialog.java | 103 ++ .../dialogs/DeletePlaylistDialog.java | 89 + .../retromusic/dialogs/DeleteSongsDialog.java | 112 ++ .../retromusic/dialogs/HomeOptionDialog.java | 125 ++ .../dialogs/RemoveFromPlaylistDialog.java | 87 + .../dialogs/RenamePlaylistDialog.java | 79 + .../dialogs/ScanMediaFolderChooserDialog.java | 1 + .../retromusic/dialogs/SleepTimerDialog.java | 173 ++ .../retromusic/dialogs/SongDetailDialog.java | 117 ++ .../retromusic/dialogs/SongShareDialog.java | 71 + .../retromusic/glide/ArtistGlideRequest.java | 140 ++ .../retromusic/glide/BlurTransformation.java | 147 ++ .../glide/RetroMusicColoredTarget.java | 53 + .../glide/RetroMusicGlideModule.java | 27 + .../retromusic/glide/SongGlideRequest.java | 124 ++ .../glide/artistimage/ArtistImage.java | 12 + .../glide/artistimage/ArtistImageFetcher.java | 83 + .../glide/artistimage/ArtistImageLoader.java | 68 + .../glide/audiocover/AudioFileCover.java | 10 + .../audiocover/AudioFileCoverFetcher.java | 95 ++ .../audiocover/AudioFileCoverLoader.java | 32 + .../glide/palette/BitmapPaletteResource.java | 34 + .../glide/palette/BitmapPaletteTarget.java | 17 + .../palette/BitmapPaletteTranscoder.java | 34 + .../glide/palette/BitmapPaletteWrapper.java | 22 + .../retromusic/helper/EqualizerHelper.java | 171 ++ .../helper/HorizontalAdapterHelper.java | 36 + .../retromusic/helper/M3UConstants.java | 8 + .../monkey/retromusic/helper/M3UWriter.java | 58 + .../retromusic/helper/MusicPlayerRemote.java | 480 ++++++ .../helper/MusicProgressViewUpdateHelper.java | 71 + .../helper/PlayPauseButtonOnClickHandler.java | 15 + .../retromusic/helper/SearchQueryHelper.java | 91 ++ .../retromusic/helper/ShuffleHelper.java | 25 + .../monkey/retromusic/helper/SortOrder.java | 173 ++ .../monkey/retromusic/helper/StackBlur.java | 333 ++++ .../monkey/retromusic/helper/StopWatch.java | 82 + .../helper/menu/GenreMenuHelper.java | 50 + .../helper/menu/PlaylistMenuHelper.java | 91 ++ .../helper/menu/SongMenuHelper.java | 93 ++ .../helper/menu/SongsMenuHelper.java | 35 + .../retromusic/interfaces/CabHolder.java | 12 + .../interfaces/EqualizerInterface.java | 49 + .../retromusic/interfaces/LoaderIds.java | 6 + .../MainActivityFragmentCallbacks.java | 13 + .../interfaces/MusicServiceEventListener.java | 20 + .../interfaces/PaletteColorHolder.java | 12 + .../retromusic/loaders/AlbumLoader.java | 104 ++ .../retromusic/loaders/ArtistLoader.java | 119 ++ .../retromusic/loaders/ArtistSongLoader.java | 37 + .../retromusic/loaders/GenreLoader.java | 133 ++ .../retromusic/loaders/GenreSongsLoader.java | 78 + .../monkey/retromusic/loaders/HomeLoader.java | 60 + .../loaders/LastAddedSongsLoader.java | 47 + .../retromusic/loaders/PlaylistLoader.java | 118 ++ .../loaders/PlaylistSongsLoader.java | 95 ++ .../retromusic/loaders/SearchLoader.java | 44 + .../monkey/retromusic/loaders/SongLoader.java | 191 +++ .../retromusic/loaders/SortedCursor.java | 169 ++ .../retromusic/loaders/SortedLongCursor.java | 169 ++ .../TopAndRecentlyPlayedTracksLoader.java | 158 ++ .../retromusic/lyrics/KogouLyricsFetcher.java | 69 + .../retromusic/lyrics/LyricsEngine.java | 6 + .../retromusic/lyrics/LyricsWikiEngine.java | 143 ++ .../monkey/retromusic/lyrics/ParseLyrics.java | 38 + .../monkey/retromusic/lyrics/QueryResult.java | 23 + .../misc/AppBarStateChangeListener.java | 41 + .../misc/CustomFragmentStatePagerAdapter.java | 237 +++ .../retromusic/misc/DialogAsyncTask.java | 90 + .../monkey/retromusic/misc/LagTracker.java | 62 + .../misc/ScrollAwareFABBehavior.java | 110 ++ .../misc/SimpleAnimatorListener.java | 26 + .../misc/SimpleOnSeekbarChangeListener.java | 21 + ...teToastMediaScannerCompletionListener.java | 50 + .../retromusic/misc/WeakContextAsyncTask.java | 1 + .../misc/WrappedAsyncTaskLoader.java | 72 + .../retromusic/model/AbsCustomPlaylist.java | 28 + .../name/monkey/retromusic/model/Album.java | 103 ++ .../name/monkey/retromusic/model/Artist.java | 110 ++ .../monkey/retromusic/model/CategoryInfo.java | 56 + .../name/monkey/retromusic/model/Genre.java | 86 + .../name/monkey/retromusic/model/Home.java | 50 + .../monkey/retromusic/model/Playlist.java | 72 + .../monkey/retromusic/model/PlaylistSong.java | 76 + .../name/monkey/retromusic/model/Song.java | 135 ++ .../model/lyrics/AbsSynchronizedLyrics.java | 55 + .../retromusic/model/lyrics/Lyrics.java | 70 + .../model/lyrics/SynchronizedLyricsLRC.java | 72 + .../model/smartplaylist/AbsSmartPlaylist.java | 63 + .../model/smartplaylist/HistoryPlaylist.java | 57 + .../smartplaylist/LastAddedPlaylist.java | 57 + .../smartplaylist/MyTopTracksPlaylist.java | 59 + .../smartplaylist/ShuffleAllPlaylist.java | 57 + .../monkey/retromusic/mvp/BasePresenter.java | 12 + .../name/monkey/retromusic/mvp/BaseView.java | 15 + .../name/monkey/retromusic/mvp/Presenter.java | 27 + .../mvp/contract/AlbumContract.java | 19 + .../mvp/contract/AlbumDetailsContract.java | 18 + .../mvp/contract/ArtistContract.java | 23 + .../mvp/contract/ArtistDetailContract.java | 21 + .../mvp/contract/GenreContract.java | 21 + .../mvp/contract/GenreDetailsContract.java | 20 + .../retromusic/mvp/contract/HomeContract.java | 44 + .../mvp/contract/PlaylistContract.java | 21 + .../mvp/contract/PlaylistSongsContract.java | 23 + .../mvp/contract/SearchContract.java | 21 + .../retromusic/mvp/contract/SongContract.java | 24 + .../mvp/presenter/AlbumDetailsPresenter.java | 54 + .../mvp/presenter/AlbumPresenter.java | 49 + .../mvp/presenter/ArtistDetailsPresenter.java | 54 + .../mvp/presenter/ArtistPresenter.java | 47 + .../mvp/presenter/GenreDetailsPresenter.java | 56 + .../mvp/presenter/GenrePresenter.java | 53 + .../mvp/presenter/HomePresenter.java | 128 ++ .../mvp/presenter/PlaylistPresenter.java | 54 + .../mvp/presenter/PlaylistSongsPresenter.java | 48 + .../mvp/presenter/SearchPresenter.java | 52 + .../mvp/presenter/SongPresenter.java | 53 + .../preferences/BlacklistPreference.java | 25 + .../BlacklistPreferenceDialog.java | 124 ++ .../NowPlayingScreenPreference.java | 25 + .../NowPlayingScreenPreferenceDialog.java | 165 ++ .../retromusic/providers/BlacklistStore.java | 155 ++ .../retromusic/providers/HistoryStore.java | 152 ++ .../providers/MusicPlaybackQueueStore.java | 203 +++ .../retromusic/providers/RepositoryImpl.java | 169 ++ .../providers/SongPlayCountStore.java | 404 +++++ .../providers/interfaces/Repository.java | 60 + .../monkey/retromusic/rest/KogouClient.java | 76 + .../retromusic/rest/LastFMRestClient.java | 66 + .../retromusic/rest/model/KuGouRawLyric.java | 41 + .../rest/model/KuGouSearchLyricResult.java | 90 + .../retromusic/rest/model/LastFmAlbum.java | 111 ++ .../retromusic/rest/model/LastFmArtist.java | 80 + .../retromusic/rest/model/LastFmTrack.java | 174 ++ .../rest/service/KuGouApiService.java | 21 + .../rest/service/LastFMService.java | 33 + .../service/MediaButtonIntentReceiver.java | 211 +++ .../retromusic/service/MultiPlayer.java | 334 ++++ .../retromusic/service/MusicService.java | 1447 +++++++++++++++++ .../service/WearBrowserService.java | 316 ++++ .../service/daydream/RetroMusicAlbums.java | 186 +++ .../notification/PlayingNotification.java | 80 + .../notification/PlayingNotificationImpl.java | 225 +++ .../PlayingNotificationImpl24.java | 146 ++ .../notification/PlayingNotificationOreo.java | 244 +++ .../retromusic/service/playback/Playback.java | 43 + .../retromusic/swipebtn/DimentionUtils.java | 13 + .../retromusic/swipebtn/OnActiveListener.java | 5 + .../swipebtn/OnStateChangeListener.java | 5 + .../retromusic/swipebtn/SwipeButton.java | 486 ++++++ .../retromusic/swipebtn/TouchUtils.java | 13 + .../transform/CustPagerTransformer.java | 45 + .../transform/NormalPageTransformer.java | 47 + .../transform/ParallaxPagerTransformer.java | 56 + .../ui/activities/AboutActivity.java | 167 ++ .../ui/activities/AlbumDetailsActivity.java | 414 +++++ .../ui/activities/ArtistDetailActivity.java | 429 +++++ .../ui/activities/EqualizerActivity.java | 223 +++ .../ui/activities/GenreDetailsActivity.java | 272 ++++ .../ui/activities/LicenseActivity.java | 52 + .../ui/activities/LockScreenActivity.java | 86 + .../ui/activities/LyricsActivity.java | 392 +++++ .../ui/activities/MainActivity.java | 336 ++++ .../ui/activities/PlayingQueueActivity.java | 68 + .../ui/activities/PlaylistDetailActivity.java | 353 ++++ .../ui/activities/ProVersionActivity.java | 203 +++ .../ui/activities/SearchActivity.java | 267 +++ .../ui/activities/SettingsActivity.java | 150 ++ .../SupportDevelopmentActivity.java | 318 ++++ .../ui/activities/UserInfoActivity.java | 33 + .../ui/activities/base/AbsBaseActivity.java | 156 ++ .../base/AbsMusicServiceActivity.java | 222 +++ .../base/AbsSlidingMusicPanelActivity.java | 434 +++++ .../ui/activities/base/AbsThemeActivity.java | 213 +++ .../tageditor/AbsTagEditorActivity.java | 367 +++++ .../tageditor/AlbumTagEditorActivity.java | 281 ++++ .../tageditor/SongTagEditorActivity.java | 167 ++ .../tageditor/WriteTagsAsyncTask.java | 163 ++ .../ui/adapter/CollageSongAdapter.java | 96 ++ .../retromusic/ui/adapter/GenreAdapter.java | 93 ++ .../retromusic/ui/adapter/SearchAdapter.java | 163 ++ .../ui/adapter/SongFileAdapter.java | 214 +++ .../ui/adapter/album/AlbumAdapter.java | 258 +++ .../adapter/album/AlbumCoverPagerAdapter.java | 208 +++ .../adapter/album/AlbumFullWithAdapter.java | 147 ++ .../adapter/album/HorizontalAlbumAdapter.java | 83 + .../ui/adapter/artist/ArtistAdapter.java | 188 +++ .../adapter/base/AbsMultiSelectAdapter.java | 121 ++ .../ui/adapter/base/MediaEntryViewHolder.java | 98 ++ .../ui/adapter/home/HomeAdapter.java | 169 ++ .../ui/adapter/playlist/PlaylistAdapter.java | 300 ++++ .../ui/adapter/song/AbsOffsetSongAdapter.java | 110 ++ .../song/OrderablePlaylistSongAdapter.java | 145 ++ .../ui/adapter/song/PlayingQueueAdapter.java | 209 +++ .../ui/adapter/song/PlaylistSongAdapter.java | 93 ++ .../song/ShuffleButtonSongAdapter.java | 78 + .../ui/adapter/song/SimpleSongAdapter.java | 69 + .../ui/adapter/song/SongAdapter.java | 294 ++++ .../ui/fragments/MiniPlayerFragment.java | 176 ++ .../ui/fragments/NowPlayingScreen.java | 34 + .../ui/fragments/PlayingQueueFragment.java | 143 ++ .../ui/fragments/VolumeFragment.java | 158 ++ .../base/AbsLibraryPagerFragment.java | 20 + ...gerRecyclerViewCustomGridSizeFragment.java | 169 ++ .../AbsLibraryPagerRecyclerViewFragment.java | 162 ++ .../base/AbsMainActivityFragment.java | 52 + .../base/AbsMusicServiceFragment.java | 89 + .../base/AbsPlayerControlsFragment.java | 23 + .../ui/fragments/base/AbsPlayerFragment.java | 282 ++++ .../ui/fragments/intro/NameFragment.java | 275 ++++ .../mainactivity/AlbumsFragment.java | 168 ++ .../mainactivity/ArtistsFragment.java | 173 ++ .../fragments/mainactivity/GenreFragment.java | 112 ++ .../mainactivity/LibraryFragment.java | 458 ++++++ .../mainactivity/PlaylistsFragment.java | 120 ++ .../fragments/mainactivity/SongsFragment.java | 178 ++ .../mainactivity/folders/FoldersFragment.java | 697 ++++++++ .../mainactivity/home/HomeFragment.java | 413 +++++ .../player/PlayerAlbumCoverFragment.java | 154 ++ .../player/adaptive/AdaptiveFragment.java | 165 ++ .../AdaptivePlaybackControlsFragment.java | 313 ++++ .../blur/BlurPlaybackControlsFragment.java | 301 ++++ .../player/blur/BlurPlayerFragment.java | 315 ++++ .../fragments/player/card/CardFragment.java | 283 ++++ .../card/CardPlaybackControlsFragment.java | 358 ++++ .../player/cardblur/CardBlurFragment.java | 192 +++ .../CardBlurPlaybackControlsFragment.java | 335 ++++ .../fragments/player/color/ColorFragment.java | 305 ++++ .../color/ColorPlaybackControlsFragment.java | 348 ++++ .../flat/FlatPlaybackControlsFragment.java | 300 ++++ .../player/flat/FlatPlayerFragment.java | 174 ++ .../full/FullPlaybackControlsFragment.java | 301 ++++ .../player/full/FullPlayerFragment.java | 123 ++ .../hmm/HmmPlaybackControlsFragment.java | 144 ++ .../player/hmm/HmmPlayerFragment.java | 220 +++ .../LockScreenPlayerControlsFragment.java | 294 ++++ .../material/MaterialControlsFragment.java | 273 ++++ .../player/material/MaterialFragment.java | 153 ++ .../player/normal/PlayerFragment.java | 181 +++ .../PlayerPlaybackControlsFragment.java | 345 ++++ .../plain/PlainPlaybackControlsFragment.java | 324 ++++ .../player/plain/PlainPlayerFragment.java | 158 ++ .../SimplePlaybackControlsFragment.java | 319 ++++ .../player/simple/SimplePlayerFragment.java | 132 ++ .../settings/AbsSettingsFragment.java | 89 + .../ui/fragments/settings/AudioSettings.java | 49 + .../settings/ImageSettingFragment.java | 28 + .../settings/MainSettingsFragment.java | 85 + .../NotificationSettingsFragment.java | 43 + .../settings/NowPlayingSettingsFragment.java | 92 ++ .../settings/OtherSettingsFragment.java | 23 + .../settings/ThemeSettingsFragment.java | 143 ++ .../monkey/retromusic/util/AnimationUtil.java | 23 + .../retromusic/util/ArtistSignatureUtil.java | 41 + .../monkey/retromusic/util/CalendarUtil.java | 117 ++ .../monkey/retromusic/util/ColorUtils.java | 64 + .../monkey/retromusic/util/Compressor.java | 90 + .../util/CustomArtistImageUtil.java | 137 ++ .../monkey/retromusic/util/DensityUtil.java | 54 + .../name/monkey/retromusic/util/FileUtil.java | 251 +++ .../monkey/retromusic/util/ImageUtil.java | 222 +++ .../monkey/retromusic/util/LastFMUtil.java | 69 + .../monkey/retromusic/util/LyricUtil.java | 103 ++ .../monkey/retromusic/util/MusicUtil.java | 410 +++++ .../retromusic/util/NavigationUtil.java | 120 ++ .../monkey/retromusic/util/PlaylistsUtil.java | 250 +++ .../retromusic/util/PreferenceUtil.java | 705 ++++++++ .../retromusic/util/RetroColorUtil.java | 189 +++ .../monkey/retromusic/util/RetroUtil.java | 314 ++++ .../retromusic/util/SwipeAndDragHelper.java | 55 + .../monkey/retromusic/util/TempUtils.java | 68 + .../name/monkey/retromusic/util/ViewUtil.java | 58 + .../util/color/ImageGradientColorizer.java | 93 ++ .../color/MediaNotificationProcessor.java | 506 ++++++ .../util/color/NotificationColorUtil.java | 134 ++ .../schedulers/BaseSchedulerProvider.java | 20 + .../util/schedulers/ImmediateScheduler.java | 30 + .../util/schedulers/SchedulerProvider.java | 44 + .../retromusic/views/AutofitRecyclerView.java | 51 + .../views/BottomNavigationViewEx.java | 1050 ++++++++++++ .../retromusic/views/BottomSheetListView.java | 41 + .../retromusic/views/BreadCrumbLayout.java | 417 +++++ .../retromusic/views/CircularImageView.java | 310 ++++ .../retromusic/views/DrawableGradient.java | 22 + .../views/HeightFitSquareLayout.java | 39 + .../retromusic/views/IconImageView.java | 33 + .../monkey/retromusic/views/LyricView.java | 876 ++++++++++ .../views/MetalRecyclerViewPager.java | 122 ++ .../retromusic/views/NetworkImageView.java | 41 + .../retromusic/views/PlayPauseDrawable.java | 213 +++ .../views/RoundCornerFrameLayout.java | 70 + .../RoundedBottomSheetDialogFragment.java | 30 + .../SansFontCollapsingToolbarLayout.java | 41 + .../retromusic/views/VerticalTextView.java | 44 + .../views/WidthFitSquareLayout.java | 39 + .../volume/AudioVolumeContentObserver.java | 46 + .../volume/AudioVolumeObserver.java | 45 + .../volume/OnAudioVolumeChangedListener.java | 6 + app/src/main/res/anim/bounce.xml | 10 + .../grid_layout_animation_from_bottom.xml | 9 + app/src/main/res/anim/item_animation_fade.xml | 7 + .../res/anim/item_animation_fall_down.xml | 23 + .../res/anim/item_animation_from_right.xml | 17 + .../anim/item_animation_slide_from_bottom.xml | 15 + .../main/res/anim/layout_animation_fade.xml | 4 + .../res/anim/layout_animation_fall_down.xml | 5 + .../layout_animation_slide_from_bottom.xml | 5 + .../res/anim/layout_animation_slide_right.xml | 5 + app/src/main/res/animator/slide_down.xml | 9 + app/src/main/res/animator/slide_up.xml | 9 + .../res/drawable-hdpi/default_album_art.webp | Bin 0 -> 1610 bytes .../res/drawable-hdpi/default_artist_art.webp | Bin 0 -> 2092 bytes .../res/drawable-hdpi/ic_notification.png | Bin 0 -> 352 bytes .../res/drawable-mdpi/default_album_art.webp | Bin 0 -> 1040 bytes .../res/drawable-mdpi/default_artist_art.webp | Bin 0 -> 1444 bytes .../res/drawable-mdpi/ic_notification.png | Bin 0 -> 240 bytes .../drawable-v21/notification_selector.xml | 3 + .../main/res/drawable-v21/rect_selector.xml | 15 + .../res/drawable-v21/rect_selector_dark.xml | 15 + .../res/drawable-v21/rect_selector_strong.xml | 15 + .../rect_selector_strong_dark.xml | 15 + .../main/res/drawable-v21/round_selector.xml | 8 + .../res/drawable-v21/round_selector_dark.xml | 8 + .../res/drawable-v21/round_selector_mask.xml | 5 + .../main/res/drawable-v21/widget_selector.xml | 3 + .../drawable-v21/widget_selector_light.xml | 3 + .../drawable-v24/ic_launcher_background.xml | 24 + .../res/drawable-xhdpi/default_album_art.webp | Bin 0 -> 3094 bytes .../drawable-xhdpi/default_artist_art.webp | Bin 0 -> 4148 bytes .../res/drawable-xhdpi/ic_notification.png | Bin 0 -> 475 bytes .../drawable-xxhdpi/default_album_art.webp | Bin 0 -> 5064 bytes .../drawable-xxhdpi/default_artist_art.webp | Bin 0 -> 6310 bytes .../res/drawable-xxhdpi/ic_notification.png | Bin 0 -> 757 bytes .../drawable-xxxhdpi/default_album_art.webp | Bin 0 -> 12538 bytes .../drawable-xxxhdpi/default_artist_art.webp | Bin 0 -> 14792 bytes .../res/drawable-xxxhdpi/np_adaptive.webp | Bin 0 -> 5440 bytes .../main/res/drawable-xxxhdpi/np_blur.webp | Bin 0 -> 5120 bytes .../res/drawable-xxxhdpi/np_blur_card.webp | Bin 0 -> 4236 bytes .../main/res/drawable-xxxhdpi/np_card.webp | Bin 0 -> 4886 bytes .../res/drawable-xxxhdpi/np_card_blur.webp | Bin 0 -> 14152 bytes .../main/res/drawable-xxxhdpi/np_color.webp | Bin 0 -> 5294 bytes .../main/res/drawable-xxxhdpi/np_flat.webp | Bin 0 -> 4644 bytes .../main/res/drawable-xxxhdpi/np_full.webp | Bin 0 -> 5502 bytes .../main/res/drawable-xxxhdpi/np_holiday.webp | Bin 0 -> 16800 bytes .../main/res/drawable-xxxhdpi/np_normal.webp | Bin 0 -> 5214 bytes .../main/res/drawable-xxxhdpi/np_plain.webp | Bin 0 -> 5188 bytes .../main/res/drawable-xxxhdpi/np_simple.webp | Bin 0 -> 5296 bytes .../main/res/drawable-xxxhdpi/np_tiny.webp | Bin 0 -> 5080 bytes .../res/drawable/abs_history_playlist.xml | 6 + .../res/drawable/abs_last_added_playlist.xml | 6 + app/src/main/res/drawable/abs_shuffle.xml | 5 + app/src/main/res/drawable/abs_timer.xml | 5 + .../res/drawable/abs_top_tracks_playlist.xml | 6 + .../main/res/drawable/background_image.xml | 12 + .../bg_bottom_sheet_dialog_fragment.xml | 11 + app/src/main/res/drawable/black_overlay.xml | 5 + app/src/main/res/drawable/card.xml | 44 + app/src/main/res/drawable/circler_corners.xml | 9 + .../res/drawable/color_circle_gradient.xml | 5 + app/src/main/res/drawable/color_gradient.xml | 8 + .../main/res/drawable/color_progress_seek.xml | 26 + app/src/main/res/drawable/gradient.xml | 7 + app/src/main/res/drawable/gradient_1.xml | 7 + app/src/main/res/drawable/gradient_2.xml | 7 + app/src/main/res/drawable/gradient_3.xml | 8 + app/src/main/res/drawable/gradient_4.xml | 7 + app/src/main/res/drawable/gradient_5.xml | 7 + app/src/main/res/drawable/gradient_6.xml | 7 + app/src/main/res/drawable/gradient_7.xml | 7 + app/src/main/res/drawable/gradient_8.xml | 7 + app/src/main/res/drawable/hemanth_s.webp | Bin 0 -> 15332 bytes .../main/res/drawable/holiday_background.xml | 7 + .../drawable/ic_access_time_white_24dp.xml | 15 + .../main/res/drawable/ic_album_white_24dp.xml | 12 + .../res/drawable/ic_app_icon_with_shadow.xml | 9 + .../drawable/ic_app_shortcut_background.xml | 18 + .../drawable/ic_app_shortcut_last_added.xml | 20 + .../drawable/ic_app_shortcut_shuffle_all.xml | 20 + .../drawable/ic_app_shortcut_top_tracks.xml | 20 + .../drawable/ic_arrow_forward_white_24dp.xml | 12 + .../res/drawable/ic_artist_white_24dp.xml | 9 + .../main/res/drawable/ic_audio_tag_square.xml | 16 + .../res/drawable/ic_audiotrack_black_24dp.xml | 12 + .../main/res/drawable/ic_beer_white_24dp.xml | 24 + .../drawable/ic_bookmark_music_white_24dp.xml | 10 + .../drawable/ic_card_giftcard_white_24dp.xml | 9 + .../main/res/drawable/ic_close_white_24dp.xml | 9 + .../res/drawable/ic_cookie_white_24dp.xml | 9 + .../res/drawable/ic_delete_white_24dp.xml | 9 + .../res/drawable/ic_discord_white_24dp.xml | 9 + .../drawable/ic_drag_vertical_white_24dp.xml | 24 + .../main/res/drawable/ic_edit_white_24dp.xml | 9 + app/src/main/res/drawable/ic_facebook.xml | 8 + .../drawable/ic_fast_food_meal_white_24dp.xml | 30 + .../ic_favorite_border_white_24dp.xml | 9 + .../res/drawable/ic_favorite_white_24dp.xml | 9 + .../res/drawable/ic_file_music_white_24dp.xml | 9 + .../main/res/drawable/ic_flag_white_24dp.xml | 9 + .../res/drawable/ic_folder_white_24dp.xml | 9 + .../res/drawable/ic_format_color_fill.xml | 13 + .../drawable/ic_github_circle_white_24dp.xml | 10 + ..._google_circles_communities_white_24dp.xml | 10 + .../drawable/ic_google_plus_white_24dp.xml | 10 + .../res/drawable/ic_hdr_strong_white_24dp.xml | 9 + .../main/res/drawable/ic_help_white_24dp.xml | 9 + .../main/res/drawable/ic_home_white_24dp.xml | 9 + .../main/res/drawable/ic_image_white_24dp.xml | 9 + app/src/main/res/drawable/ic_instagram.xml | 8 + .../ic_keyboard_arrow_down_black_24dp.xml | 12 + .../ic_keyboard_arrow_right_white_24dp.xml | 12 + .../drawable/ic_keyboard_arrow_up_24dp.xml | 13 + .../ic_keyboard_backspace_black_24dp.xml | 12 + .../res/drawable/ic_launcher_background.xml | 8 + .../res/drawable/ic_launcher_foreground.xml | 14 + .../drawable/ic_library_add_white_24dp.xml | 9 + .../drawable/ic_library_music_white_24dp.xml | 9 + .../main/res/drawable/ic_menu_white_24dp.xml | 12 + .../main/res/drawable/ic_mic_white_24dp.xml | 12 + .../res/drawable/ic_more_vert_white_24dp.xml | 9 + .../ic_notifications_active_white_24dp.xml | 18 + app/src/main/res/drawable/ic_patreon.xml | 8 + .../main/res/drawable/ic_pause_white_24dp.xml | 12 + .../main/res/drawable/ic_pause_white_big.xml | 12 + app/src/main/res/drawable/ic_person_flat.xml | 42 + .../res/drawable/ic_person_white_24dp.xml | 9 + .../res/drawable/ic_play_arrow_white_24dp.xml | 12 + .../res/drawable/ic_play_arrow_white_big.xml | 12 + .../ic_play_circle_filled_white_24dp.xml | 9 + .../drawable/ic_playlist_add_white_24dp.xml | 12 + .../drawable/ic_playlist_play_white_24dp.xml | 21 + .../res/drawable/ic_popcorn_white_24dp.xml | 5 + .../drawable/ic_queue_music_white_24dp.xml | 9 + .../drawable/ic_recent_actors_white_24dp.xml | 9 + .../main/res/drawable/ic_redo_white_24dp.xml | 12 + .../res/drawable/ic_repeat_one_white_24dp.xml | 12 + .../res/drawable/ic_repeat_white_24dp.xml | 13 + .../main/res/drawable/ic_rounded_corner.xml | 10 + .../main/res/drawable/ic_save_white_24dp.xml | 12 + .../res/drawable/ic_scanner_white_24dp.xml | 9 + .../res/drawable/ic_search_white_24dp.xml | 9 + .../res/drawable/ic_select_all_white_24dp.xml | 1 + .../res/drawable/ic_settings_white_24dp.xml | 9 + .../main/res/drawable/ic_share_white_24dp.xml | 9 + .../res/drawable/ic_shuffle_white_24dp.xml | 12 + .../res/drawable/ic_skip_next_white_24dp.xml | 12 + .../drawable/ic_skip_previous_white_24dp.xml | 12 + .../main/res/drawable/ic_sort_white_24dp.xml | 12 + .../main/res/drawable/ic_star_white_24dp.xml | 9 + .../ic_take_away_coffe_white_24dp.xml | 12 + .../res/drawable/ic_take_away_white_24dp.xml | 9 + .../main/res/drawable/ic_telegram_white.xml | 9 + .../drawable/ic_theme_palette_white_24dp.xml | 9 + .../main/res/drawable/ic_timer_white_24dp.xml | 9 + .../drawable/ic_trending_up_white_24dp.xml | 12 + .../res/drawable/ic_twitter_white_24dp.xml | 9 + .../drawable/ic_unfold_more_black_24dp.xml | 12 + .../main/res/drawable/ic_vector_square.xml | 9 + .../drawable/ic_view_carousel_black_24dp.xml | 12 + .../drawable/ic_volume_down_white_24dp.xml | 12 + .../res/drawable/ic_volume_off_white_24dp.xml | 21 + .../res/drawable/ic_volume_up_white_24dp.xml | 12 + .../drawable/ic_water_bottle_white_24dp.xml | 9 + app/src/main/res/drawable/line_button.xml | 9 + .../main/res/drawable/lockscreen_gradient.xml | 8 + app/src/main/res/drawable/luis_gmzz.webp | Bin 0 -> 5022 bytes .../res/drawable/material_design_default.webp | Bin 0 -> 24958 bytes app/src/main/res/drawable/material_icons.xml | 19 + .../mini_player_progress_drawable.xml | 11 + .../res/drawable/notification_selector.xml | 9 + .../drawable/progress_drawable_vertical.xml | 19 + app/src/main/res/drawable/rect_selector.xml | 9 + .../main/res/drawable/rect_selector_dark.xml | 9 + .../res/drawable/rect_selector_strong.xml | 9 + .../drawable/rect_selector_strong_dark.xml | 9 + app/src/main/res/drawable/round_selected.xml | 5 + .../main/res/drawable/round_selected_dark.xml | 5 + app/src/main/res/drawable/round_selector.xml | 7 + .../main/res/drawable/round_selector_dark.xml | 7 + app/src/main/res/drawable/round_window.xml | 5 + app/src/main/res/drawable/search_gradient.xml | 6 + app/src/main/res/drawable/shadow.xml | 8 + app/src/main/res/drawable/shadow_down.xml | 9 + .../main/res/drawable/shadow_down_edited.xml | 8 + .../main/res/drawable/shadow_down_strong.xml | 9 + .../res/drawable/shadow_left_to_right.xml | 6 + app/src/main/res/drawable/shadow_up.xml | 9 + .../main/res/drawable/shadow_up_details.xml | 8 + .../main/res/drawable/shadow_up_edited.xml | 8 + .../res/drawable/shadow_up_full_theme.xml | 8 + app/src/main/res/drawable/shadow_up_home.xml | 8 + .../main/res/drawable/shadow_up_strong.xml | 9 + .../main/res/drawable/shape_button_edit.xml | 9 + .../main/res/drawable/shape_rounded_edit.xml | 9 + .../res/drawable/shuffle_line_background.xml | 8 + app/src/main/res/drawable/slider_thumb.xml | 8 + .../main/res/drawable/square_play_button.xml | 18 + .../drawable/square_play_button_design.xml | 17 + app/src/main/res/drawable/square_window.xml | 4 + .../res/drawable/switch_thumb_material.xml | 5 + app/src/main/res/drawable/thumb_material.xml | 8 + .../res/drawable/toggle_outline_buttons.xml | 24 + app/src/main/res/drawable/top_corners.xml | 7 + app/src/main/res/drawable/widget_selector.xml | 9 + .../res/drawable/widget_selector_dark.xml | 9 + .../res/drawable/widget_selector_light.xml | 9 + .../main/res/layout-land/activity_album.xml | 157 ++ .../layout-land/activity_album_tag_editor.xml | 165 ++ .../layout-land/activity_artist_details.xml | 179 ++ .../activity_main_drawer_layout.xml | 14 + .../res/layout-land/activity_settings.xml | 67 + .../main/res/layout-land/fragment_blur.xml | 92 ++ .../layout-land/fragment_card_blur_player.xml | 117 ++ .../res/layout-land/fragment_card_player.xml | 80 + .../res/layout-land/fragment_color_player.xml | 126 ++ .../res/layout-land/fragment_flat_player.xml | 78 + .../layout-land/fragment_holiday_player.xml | 80 + .../main/res/layout-land/fragment_home.xml | 109 ++ .../res/layout-land/fragment_plain_player.xml | 116 ++ .../main/res/layout-land/fragment_player.xml | 78 + .../layout-land/fragment_simple_player.xml | 80 + .../activity_album_tag_editor.xml | 164 ++ .../layout-sw600dp/activity_about_content.xml | 39 + .../activity_album_tag_editor.xml | 162 ++ .../layout_notification_collapsed.xml | 151 ++ .../layout_notification_expanded.xml | 143 ++ .../res/layout-xlarge-land/activity_album.xml | 181 +++ .../activity_artist_details.xml | 179 ++ .../activity_artist_details_blur.xml | 213 +++ .../res/layout-xlarge-land/fragment_blur.xml | 123 ++ .../fragment_card_blur_player.xml | 117 ++ .../res/layout-xlarge-land/fragment_home.xml | 106 ++ .../layout-xlarge-land/fragment_player.xml | 70 + .../main/res/layout-xlarge/activity_album.xml | 180 ++ .../layout-xlarge/activity_artist_details.xml | 181 +++ .../res/layout-xlarge/activity_settings.xml | 53 + .../activity_song_tag_editor.xml | 234 +++ .../fragment_album_card_cover.xml | 32 + .../main/res/layout-xlarge/fragment_blur.xml | 81 + .../fragment_card_blur_player.xml | 114 ++ .../main/res/layout-xlarge/fragment_home.xml | 107 ++ .../res/layout-xlarge/fragment_library.xml | 73 + .../fragment_main_activity_recycler_view.xml | 26 + .../layout-xlarge/fragment_mini_player.xml | 63 + .../main/res/layout-xlarge/fragment_name.xml | 120 ++ .../res/layout-xlarge/fragment_player.xml | 72 + .../main/res/layout-xlarge/item_artist.xml | 32 + app/src/main/res/layout-xlarge/item_image.xml | 40 + app/src/main/res/layout-xlarge/pager_item.xml | 60 + app/src/main/res/layout/abs_playlists.xml | 135 ++ app/src/main/res/layout/activity_about.xml | 56 + .../res/layout/activity_about_content.xml | 17 + app/src/main/res/layout/activity_album.xml | 164 ++ .../res/layout/activity_album_style_2.xml | 240 +++ .../res/layout/activity_album_tag_editor.xml | 162 ++ .../res/layout/activity_artist_details.xml | 174 ++ .../layout/activity_artist_details_blur.xml | 219 +++ app/src/main/res/layout/activity_donation.xml | 143 ++ .../main/res/layout/activity_equalizer.xml | 151 ++ .../res/layout/activity_genre_details.xml | 83 + app/src/main/res/layout/activity_license.xml | 45 + .../main/res/layout/activity_lock_screen.xml | 67 + .../layout/activity_lock_screen_old_style.xml | 57 + app/src/main/res/layout/activity_lyrics.xml | 164 ++ .../main/res/layout/activity_main_content.xml | 5 + .../layout/activity_main_drawer_layout.xml | 14 + .../res/layout/activity_playing_queue.xml | 55 + .../res/layout/activity_playlist_detail.xml | 81 + .../main/res/layout/activity_pro_version.xml | 72 + .../layout/activity_pro_version_content.xml | 185 +++ app/src/main/res/layout/activity_search.xml | 124 ++ app/src/main/res/layout/activity_settings.xml | 54 + .../res/layout/activity_song_tag_editor.xml | 235 +++ .../main/res/layout/activity_user_info.xml | 11 + app/src/main/res/layout/app_widget_big.xml | 101 ++ app/src/main/res/layout/app_widget_card.xml | 129 ++ .../main/res/layout/app_widget_classic.xml | 94 ++ app/src/main/res/layout/app_widget_small.xml | 112 ++ app/src/main/res/layout/artist_sub_header.xml | 12 + app/src/main/res/layout/bread_crumb.xml | 36 + app/src/main/res/layout/card_credit.xml | 185 +++ app/src/main/res/layout/card_donate.xml | 93 ++ app/src/main/res/layout/card_luis_gomez.xml | 100 ++ app/src/main/res/layout/card_other.xml | 126 ++ app/src/main/res/layout/card_retro_info.xml | 248 +++ app/src/main/res/layout/card_social.xml | 260 +++ .../res/layout/dialog_add_to_playlist.xml | 27 + .../res/layout/dialog_create_playlist.xml | 52 + .../res/layout/dialog_delete_playlist.xml | 34 + .../main/res/layout/dialog_delete_songs.xml | 35 + .../main/res/layout/dialog_file_details.xml | 82 + app/src/main/res/layout/dialog_file_share.xml | 36 + .../res/layout/dialog_playlist_rename.xml | 52 + .../res/layout/dialog_promotional_offer.xml | 59 + .../layout/dialog_remove_from_playlist.xml | 35 + .../main/res/layout/dialog_sleep_timer.xml | 65 + app/src/main/res/layout/donate_layout.xml | 40 + app/src/main/res/layout/dream_service.xml | 55 + .../res/layout/fragment_adaptive_cover.xml | 28 + .../res/layout/fragment_adaptive_player.xml | 72 + ...ment_adaptive_player_playback_controls.xml | 156 ++ .../res/layout/fragment_album_card_cover.xml | 32 + .../layout/fragment_album_circle_cover.xml | 24 + .../main/res/layout/fragment_album_cover.xml | 31 + .../res/layout/fragment_album_flat_cover.xml | 31 + .../res/layout/fragment_album_full_cover.xml | 14 + .../layout/fragment_album_material_cover.xml | 29 + app/src/main/res/layout/fragment_blur.xml | 82 + .../fragment_blur_playback_controls.xml | 192 +++ .../res/layout/fragment_card_blur_player.xml | 84 + ...ent_card_blur_player_playback_controls.xml | 194 +++ .../main/res/layout/fragment_card_player.xml | 83 + ...fragment_card_player_playback_controls.xml | 155 ++ .../layout/fragment_carousal_album_cover.xml | 29 + .../layout/fragment_cast_mini_controller.xml | 10 + .../main/res/layout/fragment_color_player.xml | 121 ++ ...ragment_color_player_playback_controls.xml | 190 +++ .../main/res/layout/fragment_flat_player.xml | 70 + ...fragment_flat_player_playback_controls.xml | 168 ++ app/src/main/res/layout/fragment_folder.xml | 92 ++ app/src/main/res/layout/fragment_full.xml | 64 + .../layout/fragment_full_player_controls.xml | 165 ++ .../layout/fragment_hmm_controls_fragment.xml | 31 + .../main/res/layout/fragment_hmm_player.xml | 127 ++ .../fragment_holiday_controls_fragment.xml | 173 ++ .../res/layout/fragment_holiday_player.xml | 75 + app/src/main/res/layout/fragment_home.xml | 102 ++ app/src/main/res/layout/fragment_library.xml | 69 + ...fragment_lock_screen_playback_controls.xml | 158 ++ .../fragment_main_activity_recycler_view.xml | 24 + .../res/layout/fragment_main_settings.xml | 269 +++ app/src/main/res/layout/fragment_material.xml | 65 + .../fragment_material_playback_controls.xml | 190 +++ .../main/res/layout/fragment_mini_player.xml | 63 + app/src/main/res/layout/fragment_name.xml | 122 ++ .../fragment_plain_controls_fragment.xml | 148 ++ .../main/res/layout/fragment_plain_player.xml | 99 ++ app/src/main/res/layout/fragment_player.xml | 71 + .../layout/fragment_player_album_cover.xml | 11 + .../fragment_player_playback_controls.xml | 193 +++ app/src/main/res/layout/fragment_playlist.xml | 46 + .../main/res/layout/fragment_queue_player.xml | 70 + ...ragment_queue_player_playback_controls.xml | 186 +++ .../fragment_simple_controls_fragment.xml | 157 ++ .../res/layout/fragment_simple_player.xml | 69 + app/src/main/res/layout/fragment_volume.xml | 33 + .../main/res/layout/home_section_content.xml | 155 ++ app/src/main/res/layout/home_shortcuts.xml | 143 ++ .../main/res/layout/horizontal_progress.xml | 10 + app/src/main/res/layout/image.xml | 19 + app/src/main/res/layout/item_artist.xml | 33 + app/src/main/res/layout/item_card.xml | 60 + app/src/main/res/layout/item_card_color.xml | 60 + app/src/main/res/layout/item_collage.xml | 209 +++ app/src/main/res/layout/item_color.xml | 60 + app/src/main/res/layout/item_contributors.xml | 16 + .../main/res/layout/item_donation_option.xml | 61 + app/src/main/res/layout/item_grid.xml | 68 + app/src/main/res/layout/item_grid_circle.xml | 69 + app/src/main/res/layout/item_image.xml | 40 + app/src/main/res/layout/item_list.xml | 122 ++ .../main/res/layout/item_list_single_row.xml | 95 ++ app/src/main/res/layout/item_playlist.xml | 70 + app/src/main/res/layout/item_song.xml | 79 + .../layout/layout_notification_collapsed.xml | 146 ++ .../layout/layout_notification_expanded.xml | 130 ++ app/src/main/res/layout/notification.xml | 143 ++ app/src/main/res/layout/notification_big.xml | 161 ++ app/src/main/res/layout/pager_item.xml | 63 + .../main/res/layout/pager_recycler_view.xml | 45 + .../preference_dialog_library_categories.xml | 11 + ...nce_dialog_library_categories_listitem.xml | 55 + .../preference_dialog_now_playing_screen.xml | 16 + .../preference_now_playing_screen_item.xml | 28 + app/src/main/res/layout/recycler_view_sec.xml | 32 + app/src/main/res/layout/retro_seekbar.xml | 46 + .../res/layout/shadow_statusbar_toolbar.xml | 28 + app/src/main/res/layout/simple_list_item.xml | 10 + .../res/layout/sliding_music_panel_layout.xml | 62 + app/src/main/res/layout/status_bar.xml | 9 + app/src/main/res/layout/sub_header.xml | 12 + .../main/res/layout/user_action_details.xml | 188 +++ .../main/res/menu/bottom_navigation_main.xml | 28 + app/src/main/res/menu/menu_album_detail.xml | 59 + app/src/main/res/menu/menu_artist_detail.xml | 29 + ..._single_songs_playlist_songs_selection.xml | 27 + app/src/main/res/menu/menu_cast.xml | 12 + .../res/menu/menu_expanded_controller.xml | 11 + app/src/main/res/menu/menu_folders.xml | 17 + app/src/main/res/menu/menu_genre_detail.xml | 18 + app/src/main/res/menu/menu_home.xml | 19 + ...nnot_delete_single_songs_playlist_song.xml | 44 + app/src/main/res/menu/menu_item_directory.xml | 28 + app/src/main/res/menu/menu_item_file.xml | 48 + .../res/menu/menu_item_playing_queue_song.xml | 44 + app/src/main/res/menu/menu_item_playlist.xml | 26 + .../main/res/menu/menu_item_playlist_song.xml | 48 + .../res/menu/menu_item_smart_playlist.xml | 27 + app/src/main/res/menu/menu_item_song.xml | 44 + app/src/main/res/menu/menu_main.xml | 72 + .../main/res/menu/menu_media_selection.xml | 34 + app/src/main/res/menu/menu_player.xml | 70 + .../main/res/menu/menu_playlist_detail.xml | 36 + .../res/menu/menu_playlists_selection.xml | 41 + .../menu/menu_playlists_songs_selection.xml | 29 + app/src/main/res/menu/menu_search.xml | 10 + .../res/menu/menu_smart_playlist_detail.xml | 30 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 4460 bytes .../mipmap-hdpi/ic_launcher_background.png | Bin 0 -> 3447 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 182 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4460 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2755 bytes .../mipmap-mdpi/ic_launcher_background.png | Bin 0 -> 2154 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 125 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2755 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../mipmap-xhdpi/ic_launcher_background.png | Bin 0 -> 5334 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 261 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6387 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 10319 bytes .../mipmap-xxhdpi/ic_launcher_background.png | Bin 0 -> 9570 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 487 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10319 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 15329 bytes .../mipmap-xxxhdpi/ic_launcher_background.png | Bin 0 -> 15665 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 803 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15329 bytes .../res/transition/default_window_fade.xml | 8 + app/src/main/res/values-ar/strings.xml | 344 ++++ app/src/main/res/values-cs/strings.xml | 243 +++ app/src/main/res/values-de-rDE/strings.xml | 430 +++++ app/src/main/res/values-de/strings.xml | 300 ++++ app/src/main/res/values-el/strings.xml | 348 ++++ app/src/main/res/values-es-rES/strings.xml | 409 +++++ app/src/main/res/values-es-rUS/strings.xml | 430 +++++ app/src/main/res/values-es/strings.xml | 430 +++++ app/src/main/res/values-eu-rES/strings.xml | 430 +++++ app/src/main/res/values-fr/strings.xml | 420 +++++ app/src/main/res/values-hdpi/dimens.xml | 4 + app/src/main/res/values-hi-rIN/strings.xml | 82 + app/src/main/res/values-hi/strings.xml | 4 + app/src/main/res/values-hr/strings.xml | 423 +++++ app/src/main/res/values-hu/strings.xml | 430 +++++ app/src/main/res/values-id/strings.xml | 417 +++++ app/src/main/res/values-in/strings.xml | 288 ++++ app/src/main/res/values-it/strings.xml | 430 +++++ app/src/main/res/values-ja/strings.xml | 387 +++++ app/src/main/res/values-ko/strings.xml | 430 +++++ app/src/main/res/values-ldpi/dimens.xml | 4 + app/src/main/res/values-mdpi/dimens.xml | 4 + app/src/main/res/values-ms/strings.xml | 373 +++++ app/src/main/res/values-nl/strings.xml | 323 ++++ app/src/main/res/values-pl/strings.xml | 423 +++++ app/src/main/res/values-pt-rBR/strings.xml | 431 +++++ app/src/main/res/values-ro/strings.xml | 430 +++++ app/src/main/res/values-ru/strings.xml | 431 +++++ app/src/main/res/values-sr/strings.xml | 340 ++++ .../main/res/values-sw600dp-land/dimens.xml | 4 + app/src/main/res/values-sw600dp/dimens.xml | 3 + app/src/main/res/values-sw600dp/integers.xml | 11 + app/src/main/res/values-tr/strings.xml | 424 +++++ app/src/main/res/values-v19/dimens.xml | 5 + app/src/main/res/values-v21/dimens.xml | 5 + app/src/main/res/values-v21/fonts.xml | 7 + app/src/main/res/values-v21/integers.xml | 4 + app/src/main/res/values-v21/styles.xml | 39 + app/src/main/res/values-v23/dimens.xml | 4 + app/src/main/res/values-xhdpi/dimens.xml | 4 + app/src/main/res/values-xxhdpi/dimens.xml | 4 + app/src/main/res/values-xxxhdpi/dimens.xml | 4 + app/src/main/res/values-zh-rCN/strings.xml | 430 +++++ app/src/main/res/values-zh-rHK/strings.xml | 431 +++++ app/src/main/res/values-zh-rTW/strings.xml | 242 +++ app/src/main/res/values/arrays.xml | 150 ++ app/src/main/res/values/attrs.xml | 30 + .../res/values/circular_image_view_attrs.xml | 11 + app/src/main/res/values/colors.xml | 8 + app/src/main/res/values/dimens.xml | 93 ++ app/src/main/res/values/donottranslate.xml | 48 + .../res/values/ic_launcher_background.xml | 4 + app/src/main/res/values/ids.xml | 21 + app/src/main/res/values/integers.xml | 17 + app/src/main/res/values/lyric_view_attrs.xml | 18 + app/src/main/res/values/md_colors.xml | 279 ++++ .../res/values/metal_recycler_view_attrs.xml | 6 + app/src/main/res/values/strings.xml | 680 ++++++++ app/src/main/res/values/styles.xml | 135 ++ app/src/main/res/values/styles_parents.xml | 159 ++ .../main/res/values/swipe_button_attrs.xml | 31 + app/src/main/res/values/values.xml | 8 + app/src/main/res/xml/app_widget_big_info.xml | 12 + app/src/main/res/xml/app_widget_card_info.xml | 12 + .../main/res/xml/app_widget_classic_info.xml | 12 + .../main/res/xml/app_widget_small_info.xml | 12 + app/src/main/res/xml/automotive_app_desc.xml | 4 + app/src/main/res/xml/pref_advanced.xml | 48 + app/src/main/res/xml/pref_audio.xml | 26 + app/src/main/res/xml/pref_blacklist.xml | 12 + app/src/main/res/xml/pref_general.xml | 47 + app/src/main/res/xml/pref_images.xml | 16 + app/src/main/res/xml/pref_lockscreen.xml | 21 + app/src/main/res/xml/pref_notification.xml | 15 + .../main/res/xml/pref_now_playing_screen.xml | 19 + app/src/main/res/xml/pref_others.xml | 22 + app/src/main/res/xml/pref_playlists.xml | 16 + app/src/main/res/xml/pref_ui.xml | 20 + app/src/main/res/xml/pref_window.xml | 15 + app/src/main/res/xml/provider_paths.xml | 4 + .../PersonaliseSettingsFragmentTest.java | 10 + appthemehelper/.gitignore | 1 + appthemehelper/appthemehelper.iml | 136 ++ appthemehelper/build.gradle | 34 + appthemehelper/proguard-rules.pro | 21 + .../ExampleInstrumentedTest.java | 26 + appthemehelper/src/main/AndroidManifest.xml | 1 + .../code/name/monkey/appthemehelper/ATH.java | 122 ++ .../monkey/appthemehelper/ATHActivity.java | 49 + .../monkey/appthemehelper/ThemeStore.java | 325 ++++ .../appthemehelper/ThemeStoreInterface.java | 94 ++ .../appthemehelper/ThemeStorePrefKeys.java | 29 + .../common/ATHActionBarActivity.java | 13 + .../common/ATHToolbarActivity.java | 46 + .../common/prefs/ATECheckBoxPreference.java | 91 ++ .../common/prefs/ATEColorPreference.java | 66 + .../common/prefs/ATEDialogPreference.java | 38 + .../common/prefs/ATEEditTextPreference.java | 36 + .../common/prefs/ATEListPreference.java | 39 + .../prefs/ATEMultiSelectPreference.java | 37 + .../common/prefs/ATEPreference.java | 40 + .../common/prefs/ATEPreferenceCategory.java | 38 + .../common/prefs/ATESwitchPreference.java | 114 ++ .../common/prefs/BorderCircleView.java | 112 ++ .../supportv7/ATECheckBoxPreference.java | 41 + .../prefs/supportv7/ATEColorPreference.java | 68 + .../prefs/supportv7/ATEDialogPreference.java | 37 + .../supportv7/ATEEditTextPreference.java | 37 + .../prefs/supportv7/ATEListPreference.java | 39 + .../common/prefs/supportv7/ATEPreference.java | 40 + .../supportv7/ATEPreferenceCategory.java | 47 + .../ATEPreferenceFragmentCompat.java | 50 + .../prefs/supportv7/ATESwitchPreference.java | 41 + ...ditTextPreferenceDialogFragmentCompat.java | 50 + ...ATEListPreferenceDialogFragmentCompat.java | 72 + .../dialogs/ATEPreferenceDialogFragment.java | 93 ++ .../common/views/ATECheckBox.java | 33 + .../common/views/ATEEditText.java | 42 + .../common/views/ATEPrimaryTextView.java | 31 + .../common/views/ATEProgressBar.java | 41 + .../common/views/ATERadioButton.java | 41 + .../common/views/ATESecondaryTextView.java | 34 + .../common/views/ATESeekBar.java | 32 + .../common/views/ATEStockSwitch.java | 39 + .../common/views/ATESwitch.java | 39 + .../monkey/appthemehelper/util/ATHUtil.java | 50 + .../monkey/appthemehelper/util/ColorUtil.java | 77 + .../appthemehelper/util/DrawableUtil.java | 26 + .../appthemehelper/util/EdgeGlowUtil.java | 334 ++++ .../util/MaterialDialogsUtil.java | 27 + .../util/MaterialValueHelper.java | 51 + .../appthemehelper/util/StatusBarUtil.java | 728 +++++++++ .../appthemehelper/util/TabLayoutUtil.java | 33 + .../util/TextInputLayoutUtil.java | 37 + .../appthemehelper/util/TintHelper.java | 399 +++++ .../util/ToolbarContentTintHelper.java | 551 +++++++ .../appthemehelper/util/TypefaceHelper.java | 49 + .../appthemehelper/util/VersionUtils.java | 59 + .../monkey/appthemehelper/util/ViewUtil.java | 53 + .../src/main/res/drawable/ate_check.xml | 9 + .../src/main/res/drawable/ate_switch.xml | 7 + .../main/res/drawable/ic_toggle_switch.xml | 10 + .../res/drawable/ic_toggle_switch_off.xml | 8 + .../res/layout/ate_preference_category.xml | 13 + .../res/layout/ate_preference_checkbox.xml | 9 + .../main/res/layout/ate_preference_color.xml | 6 + .../main/res/layout/ate_preference_custom.xml | 73 + .../layout/ate_preference_custom_support.xml | 73 + .../main/res/layout/ate_preference_switch.xml | 9 + .../layout/ate_preference_switch_support.xml | 8 + .../src/main/res/values-large/dimens.xml | 6 + appthemehelper/src/main/res/values/attrs.xml | 42 + appthemehelper/src/main/res/values/colors.xml | 52 + .../res/values/colors_material_design.xml | 338 ++++ appthemehelper/src/main/res/values/dimens.xml | 18 + appthemehelper/src/main/res/values/ids.xml | 5 + .../src/main/res/values/strings.xml | 3 + .../appthemehelper/ExampleUnitTest.java | 17 + build.gradle | 24 + gradle.properties | 19 + gradlew | 160 ++ gradlew.bat | 90 + local.properties | 10 + public.properties | 5 + settings.gradle | 1 + 932 files changed, 83126 insertions(+) create mode 100644 .idea/RetroMusicPlayer.iml create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 RetroMusicPlayer.iml create mode 100644 app/app.iml create mode 100644 app/build.gradle create mode 100644 app/libs/jaudiotagger-android-2.2.3.jar create mode 100644 app/libs/jsoup-1.11.2.jar create mode 100644 app/libs/juniversalchardet-1.0.3.jar create mode 100644 app/proguard-rules.pro create mode 100644 app/src/main/AndroidManifest.xml create mode 100755 app/src/main/assets/fonts/circular_std_black.otf create mode 100755 app/src/main/assets/fonts/circular_std_book.otf create mode 100755 app/src/main/assets/fonts/product_sans_bold.ttf create mode 100755 app/src/main/assets/fonts/product_sans_regular.ttf create mode 100644 app/src/main/assets/index.html create mode 100644 app/src/main/ic_launcher-web.png create mode 100644 app/src/main/java/code/name/monkey/retromusic/Constants.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/Injection.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/RetroApplication.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/BaseShortcutType.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/LastAddedShortcutType.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/ShuffleAllShortcutType.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/TopTracksShortcutType.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appwidgets/BootReceiver.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/ClearSmartPlaylistDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/HomeOptionDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/ScanMediaFolderChooserDialog.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/SongShareDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/ArtistGlideRequest.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/BlurTransformation.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicColoredTarget.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicGlideModule.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/SongGlideRequest.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImage.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageFetcher.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCover.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverFetcher.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteResource.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteTarget.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteTranscoder.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteWrapper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/EqualizerHelper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/HorizontalAdapterHelper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/M3UConstants.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/MusicProgressViewUpdateHelper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/PlayPauseButtonOnClickHandler.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/SearchQueryHelper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/ShuffleHelper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/SortOrder.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/StackBlur.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/StopWatch.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/interfaces/CabHolder.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/interfaces/EqualizerInterface.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/interfaces/LoaderIds.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/interfaces/MainActivityFragmentCallbacks.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/interfaces/MusicServiceEventListener.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/interfaces/PaletteColorHolder.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/AlbumLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/ArtistLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/ArtistSongLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/GenreLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/GenreSongsLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/HomeLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/LastAddedSongsLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/PlaylistLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/PlaylistSongsLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/SongLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/SortedCursor.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/SortedLongCursor.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/loaders/TopAndRecentlyPlayedTracksLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/lyrics/KogouLyricsFetcher.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/lyrics/LyricsEngine.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/lyrics/LyricsWikiEngine.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/lyrics/ParseLyrics.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/lyrics/QueryResult.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/misc/AppBarStateChangeListener.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/misc/CustomFragmentStatePagerAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/misc/DialogAsyncTask.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/misc/LagTracker.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/misc/ScrollAwareFABBehavior.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/misc/SimpleAnimatorListener.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/misc/SimpleOnSeekbarChangeListener.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/misc/UpdateToastMediaScannerCompletionListener.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/misc/WeakContextAsyncTask.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/misc/WrappedAsyncTaskLoader.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/AbsCustomPlaylist.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/Album.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/Artist.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/Genre.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/model/Home.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/Playlist.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/PlaylistSong.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/Song.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/lyrics/AbsSynchronizedLyrics.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/lyrics/Lyrics.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/lyrics/SynchronizedLyricsLRC.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/AbsSmartPlaylist.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/HistoryPlaylist.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/LastAddedPlaylist.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/MyTopTracksPlaylist.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/ShuffleAllPlaylist.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/BasePresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/BaseView.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/Presenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/AlbumContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/AlbumDetailsContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/ArtistContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/ArtistDetailContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/GenreContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/GenreDetailsContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/HomeContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/PlaylistContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/PlaylistSongsContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/SearchContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/contract/SongContract.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumDetailsPresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumPresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistDetailsPresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistPresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenreDetailsPresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenrePresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/HomePresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistPresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistSongsPresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SongPresenter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreference.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreference.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/providers/BlacklistStore.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/providers/HistoryStore.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/providers/MusicPlaybackQueueStore.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/providers/SongPlayCountStore.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/rest/KogouClient.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/rest/LastFMRestClient.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/rest/model/KuGouRawLyric.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/rest/model/KuGouSearchLyricResult.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmAlbum.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmArtist.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmTrack.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/rest/service/KuGouApiService.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/rest/service/LastFMService.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/service/MediaButtonIntentReceiver.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/service/MusicService.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/service/WearBrowserService.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/service/daydream/RetroMusicAlbums.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotification.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl24.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationOreo.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/swipebtn/DimentionUtils.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/swipebtn/OnActiveListener.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/swipebtn/OnStateChangeListener.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/swipebtn/SwipeButton.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/swipebtn/TouchUtils.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/transform/CustPagerTransformer.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/transform/NormalPageTransformer.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/transform/ParallaxPagerTransformer.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/AboutActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/AlbumDetailsActivity.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/ui/activities/ArtistDetailActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/EqualizerActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/GenreDetailsActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/LicenseActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/LockScreenActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/LyricsActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/MainActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/PlayingQueueActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/PlaylistDetailActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/SearchActivity.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/SupportDevelopmentActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/UserInfoActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsMusicServiceActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsSlidingMusicPanelActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsThemeActivity.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/AbsTagEditorActivity.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/AlbumTagEditorActivity.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/SongTagEditorActivity.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/WriteTagsAsyncTask.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/CollageSongAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/GenreAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/SearchAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/SongFileAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumCoverPagerAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumFullWithAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/HorizontalAlbumAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/artist/ArtistAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/AbsMultiSelectAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/MediaEntryViewHolder.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/home/HomeAdapter.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/ui/adapter/playlist/PlaylistAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/AbsOffsetSongAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/OrderablePlaylistSongAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/PlayingQueueAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/PlaylistSongAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/ShuffleButtonSongAdapter.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SimpleSongAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SongAdapter.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/MiniPlayerFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/PlayingQueueFragment.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/ui/fragments/VolumeFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsMainActivityFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsMusicServiceFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/intro/NameFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/AlbumsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/ArtistsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/GenreFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/LibraryFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/PlaylistsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/SongsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/folders/FoldersFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/home/HomeFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/PlayerAlbumCoverFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptiveFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptivePlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlayerFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/card/CardFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/card/CardPlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurPlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorPlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlayerFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/full/FullPlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/full/FullPlayerFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/hmm/HmmPlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/hmm/HmmPlayerFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/lockscreen/LockScreenPlayerControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerPlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/plain/PlainPlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/plain/PlainPlayerFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/simple/SimplePlaybackControlsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/simple/SimplePlayerFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/AbsSettingsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/AudioSettings.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ImageSettingFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NotificationSettingsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NowPlayingSettingsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/OtherSettingsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/AnimationUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/ArtistSignatureUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/CalendarUtil.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/util/ColorUtils.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/Compressor.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/DensityUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/FileUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/ImageUtil.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/util/LastFMUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/RetroColorUtil.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/SwipeAndDragHelper.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/TempUtils.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/ViewUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/color/ImageGradientColorizer.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/color/MediaNotificationProcessor.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/color/NotificationColorUtil.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/schedulers/BaseSchedulerProvider.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/schedulers/ImmediateScheduler.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/schedulers/SchedulerProvider.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/AutofitRecyclerView.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/BottomNavigationViewEx.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/BottomSheetListView.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/BreadCrumbLayout.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/CircularImageView.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/DrawableGradient.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/views/HeightFitSquareLayout.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/IconImageView.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/LyricView.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/MetalRecyclerViewPager.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/NetworkImageView.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/PlayPauseDrawable.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/RoundCornerFrameLayout.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/RoundedBottomSheetDialogFragment.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/SansFontCollapsingToolbarLayout.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/VerticalTextView.java create mode 100755 app/src/main/java/code/name/monkey/retromusic/views/WidthFitSquareLayout.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeContentObserver.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeObserver.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/volume/OnAudioVolumeChangedListener.java create mode 100644 app/src/main/res/anim/bounce.xml create mode 100644 app/src/main/res/anim/grid_layout_animation_from_bottom.xml create mode 100644 app/src/main/res/anim/item_animation_fade.xml create mode 100644 app/src/main/res/anim/item_animation_fall_down.xml create mode 100644 app/src/main/res/anim/item_animation_from_right.xml create mode 100644 app/src/main/res/anim/item_animation_slide_from_bottom.xml create mode 100644 app/src/main/res/anim/layout_animation_fade.xml create mode 100644 app/src/main/res/anim/layout_animation_fall_down.xml create mode 100644 app/src/main/res/anim/layout_animation_slide_from_bottom.xml create mode 100644 app/src/main/res/anim/layout_animation_slide_right.xml create mode 100644 app/src/main/res/animator/slide_down.xml create mode 100644 app/src/main/res/animator/slide_up.xml create mode 100644 app/src/main/res/drawable-hdpi/default_album_art.webp create mode 100644 app/src/main/res/drawable-hdpi/default_artist_art.webp create mode 100644 app/src/main/res/drawable-hdpi/ic_notification.png create mode 100644 app/src/main/res/drawable-mdpi/default_album_art.webp create mode 100644 app/src/main/res/drawable-mdpi/default_artist_art.webp create mode 100644 app/src/main/res/drawable-mdpi/ic_notification.png create mode 100644 app/src/main/res/drawable-v21/notification_selector.xml create mode 100644 app/src/main/res/drawable-v21/rect_selector.xml create mode 100644 app/src/main/res/drawable-v21/rect_selector_dark.xml create mode 100644 app/src/main/res/drawable-v21/rect_selector_strong.xml create mode 100644 app/src/main/res/drawable-v21/rect_selector_strong_dark.xml create mode 100644 app/src/main/res/drawable-v21/round_selector.xml create mode 100644 app/src/main/res/drawable-v21/round_selector_dark.xml create mode 100644 app/src/main/res/drawable-v21/round_selector_mask.xml create mode 100644 app/src/main/res/drawable-v21/widget_selector.xml create mode 100644 app/src/main/res/drawable-v21/widget_selector_light.xml create mode 100644 app/src/main/res/drawable-v24/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable-xhdpi/default_album_art.webp create mode 100644 app/src/main/res/drawable-xhdpi/default_artist_art.webp create mode 100644 app/src/main/res/drawable-xhdpi/ic_notification.png create mode 100644 app/src/main/res/drawable-xxhdpi/default_album_art.webp create mode 100644 app/src/main/res/drawable-xxhdpi/default_artist_art.webp create mode 100644 app/src/main/res/drawable-xxhdpi/ic_notification.png create mode 100644 app/src/main/res/drawable-xxxhdpi/default_album_art.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/default_artist_art.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_adaptive.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_blur.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_blur_card.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_card.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_card_blur.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_color.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_flat.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_full.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_holiday.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_normal.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_plain.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_simple.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/np_tiny.webp create mode 100644 app/src/main/res/drawable/abs_history_playlist.xml create mode 100644 app/src/main/res/drawable/abs_last_added_playlist.xml create mode 100644 app/src/main/res/drawable/abs_shuffle.xml create mode 100644 app/src/main/res/drawable/abs_timer.xml create mode 100644 app/src/main/res/drawable/abs_top_tracks_playlist.xml create mode 100644 app/src/main/res/drawable/background_image.xml create mode 100644 app/src/main/res/drawable/bg_bottom_sheet_dialog_fragment.xml create mode 100644 app/src/main/res/drawable/black_overlay.xml create mode 100644 app/src/main/res/drawable/card.xml create mode 100644 app/src/main/res/drawable/circler_corners.xml create mode 100644 app/src/main/res/drawable/color_circle_gradient.xml create mode 100755 app/src/main/res/drawable/color_gradient.xml create mode 100755 app/src/main/res/drawable/color_progress_seek.xml create mode 100644 app/src/main/res/drawable/gradient.xml create mode 100644 app/src/main/res/drawable/gradient_1.xml create mode 100644 app/src/main/res/drawable/gradient_2.xml create mode 100644 app/src/main/res/drawable/gradient_3.xml create mode 100644 app/src/main/res/drawable/gradient_4.xml create mode 100644 app/src/main/res/drawable/gradient_5.xml create mode 100644 app/src/main/res/drawable/gradient_6.xml create mode 100644 app/src/main/res/drawable/gradient_7.xml create mode 100644 app/src/main/res/drawable/gradient_8.xml create mode 100644 app/src/main/res/drawable/hemanth_s.webp create mode 100644 app/src/main/res/drawable/holiday_background.xml create mode 100644 app/src/main/res/drawable/ic_access_time_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_album_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_with_shadow.xml create mode 100644 app/src/main/res/drawable/ic_app_shortcut_background.xml create mode 100644 app/src/main/res/drawable/ic_app_shortcut_last_added.xml create mode 100644 app/src/main/res/drawable/ic_app_shortcut_shuffle_all.xml create mode 100644 app/src/main/res/drawable/ic_app_shortcut_top_tracks.xml create mode 100644 app/src/main/res/drawable/ic_arrow_forward_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_artist_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_audio_tag_square.xml create mode 100644 app/src/main/res/drawable/ic_audiotrack_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_beer_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_bookmark_music_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_card_giftcard_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_close_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_cookie_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_delete_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_discord_white_24dp.xml create mode 100755 app/src/main/res/drawable/ic_drag_vertical_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_edit_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_facebook.xml create mode 100644 app/src/main/res/drawable/ic_fast_food_meal_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_favorite_border_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_favorite_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_file_music_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_flag_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_folder_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_format_color_fill.xml create mode 100644 app/src/main/res/drawable/ic_github_circle_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_google_circles_communities_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_google_plus_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_hdr_strong_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_help_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_home_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_image_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_instagram.xml create mode 100644 app/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_keyboard_arrow_right_white_24dp.xml create mode 100755 app/src/main/res/drawable/ic_keyboard_arrow_up_24dp.xml create mode 100644 app/src/main/res/drawable/ic_keyboard_backspace_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_library_add_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_library_music_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_menu_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_mic_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_more_vert_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_notifications_active_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_patreon.xml create mode 100644 app/src/main/res/drawable/ic_pause_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_pause_white_big.xml create mode 100644 app/src/main/res/drawable/ic_person_flat.xml create mode 100644 app/src/main/res/drawable/ic_person_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_play_arrow_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_play_arrow_white_big.xml create mode 100644 app/src/main/res/drawable/ic_play_circle_filled_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_playlist_add_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_playlist_play_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_popcorn_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_queue_music_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_recent_actors_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_redo_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_repeat_one_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_repeat_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_rounded_corner.xml create mode 100644 app/src/main/res/drawable/ic_save_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_scanner_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_search_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_select_all_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_settings_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_share_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_shuffle_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_skip_next_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_skip_previous_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_sort_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_star_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_take_away_coffe_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_take_away_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_telegram_white.xml create mode 100644 app/src/main/res/drawable/ic_theme_palette_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_timer_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_trending_up_white_24dp.xml create mode 100755 app/src/main/res/drawable/ic_twitter_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_unfold_more_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_vector_square.xml create mode 100644 app/src/main/res/drawable/ic_view_carousel_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_volume_down_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_volume_off_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_volume_up_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_water_bottle_white_24dp.xml create mode 100644 app/src/main/res/drawable/line_button.xml create mode 100644 app/src/main/res/drawable/lockscreen_gradient.xml create mode 100644 app/src/main/res/drawable/luis_gmzz.webp create mode 100644 app/src/main/res/drawable/material_design_default.webp create mode 100644 app/src/main/res/drawable/material_icons.xml create mode 100644 app/src/main/res/drawable/mini_player_progress_drawable.xml create mode 100644 app/src/main/res/drawable/notification_selector.xml create mode 100644 app/src/main/res/drawable/progress_drawable_vertical.xml create mode 100644 app/src/main/res/drawable/rect_selector.xml create mode 100644 app/src/main/res/drawable/rect_selector_dark.xml create mode 100644 app/src/main/res/drawable/rect_selector_strong.xml create mode 100644 app/src/main/res/drawable/rect_selector_strong_dark.xml create mode 100644 app/src/main/res/drawable/round_selected.xml create mode 100644 app/src/main/res/drawable/round_selected_dark.xml create mode 100644 app/src/main/res/drawable/round_selector.xml create mode 100644 app/src/main/res/drawable/round_selector_dark.xml create mode 100755 app/src/main/res/drawable/round_window.xml create mode 100644 app/src/main/res/drawable/search_gradient.xml create mode 100644 app/src/main/res/drawable/shadow.xml create mode 100755 app/src/main/res/drawable/shadow_down.xml create mode 100644 app/src/main/res/drawable/shadow_down_edited.xml create mode 100755 app/src/main/res/drawable/shadow_down_strong.xml create mode 100644 app/src/main/res/drawable/shadow_left_to_right.xml create mode 100755 app/src/main/res/drawable/shadow_up.xml create mode 100644 app/src/main/res/drawable/shadow_up_details.xml create mode 100644 app/src/main/res/drawable/shadow_up_edited.xml create mode 100644 app/src/main/res/drawable/shadow_up_full_theme.xml create mode 100644 app/src/main/res/drawable/shadow_up_home.xml create mode 100755 app/src/main/res/drawable/shadow_up_strong.xml create mode 100644 app/src/main/res/drawable/shape_button_edit.xml create mode 100644 app/src/main/res/drawable/shape_rounded_edit.xml create mode 100644 app/src/main/res/drawable/shuffle_line_background.xml create mode 100644 app/src/main/res/drawable/slider_thumb.xml create mode 100644 app/src/main/res/drawable/square_play_button.xml create mode 100644 app/src/main/res/drawable/square_play_button_design.xml create mode 100755 app/src/main/res/drawable/square_window.xml create mode 100755 app/src/main/res/drawable/switch_thumb_material.xml create mode 100644 app/src/main/res/drawable/thumb_material.xml create mode 100644 app/src/main/res/drawable/toggle_outline_buttons.xml create mode 100644 app/src/main/res/drawable/top_corners.xml create mode 100755 app/src/main/res/drawable/widget_selector.xml create mode 100644 app/src/main/res/drawable/widget_selector_dark.xml create mode 100644 app/src/main/res/drawable/widget_selector_light.xml create mode 100644 app/src/main/res/layout-land/activity_album.xml create mode 100644 app/src/main/res/layout-land/activity_album_tag_editor.xml create mode 100644 app/src/main/res/layout-land/activity_artist_details.xml create mode 100644 app/src/main/res/layout-land/activity_main_drawer_layout.xml create mode 100644 app/src/main/res/layout-land/activity_settings.xml create mode 100644 app/src/main/res/layout-land/fragment_blur.xml create mode 100644 app/src/main/res/layout-land/fragment_card_blur_player.xml create mode 100644 app/src/main/res/layout-land/fragment_card_player.xml create mode 100644 app/src/main/res/layout-land/fragment_color_player.xml create mode 100644 app/src/main/res/layout-land/fragment_flat_player.xml create mode 100644 app/src/main/res/layout-land/fragment_holiday_player.xml create mode 100644 app/src/main/res/layout-land/fragment_home.xml create mode 100644 app/src/main/res/layout-land/fragment_plain_player.xml create mode 100755 app/src/main/res/layout-land/fragment_player.xml create mode 100644 app/src/main/res/layout-land/fragment_simple_player.xml create mode 100644 app/src/main/res/layout-sw600dp-land/activity_album_tag_editor.xml create mode 100644 app/src/main/res/layout-sw600dp/activity_about_content.xml create mode 100644 app/src/main/res/layout-sw600dp/activity_album_tag_editor.xml create mode 100644 app/src/main/res/layout-v24/layout_notification_collapsed.xml create mode 100644 app/src/main/res/layout-v24/layout_notification_expanded.xml create mode 100644 app/src/main/res/layout-xlarge-land/activity_album.xml create mode 100644 app/src/main/res/layout-xlarge-land/activity_artist_details.xml create mode 100755 app/src/main/res/layout-xlarge-land/activity_artist_details_blur.xml create mode 100644 app/src/main/res/layout-xlarge-land/fragment_blur.xml create mode 100644 app/src/main/res/layout-xlarge-land/fragment_card_blur_player.xml create mode 100644 app/src/main/res/layout-xlarge-land/fragment_home.xml create mode 100644 app/src/main/res/layout-xlarge-land/fragment_player.xml create mode 100644 app/src/main/res/layout-xlarge/activity_album.xml create mode 100644 app/src/main/res/layout-xlarge/activity_artist_details.xml create mode 100644 app/src/main/res/layout-xlarge/activity_settings.xml create mode 100644 app/src/main/res/layout-xlarge/activity_song_tag_editor.xml create mode 100644 app/src/main/res/layout-xlarge/fragment_album_card_cover.xml create mode 100644 app/src/main/res/layout-xlarge/fragment_blur.xml create mode 100644 app/src/main/res/layout-xlarge/fragment_card_blur_player.xml create mode 100644 app/src/main/res/layout-xlarge/fragment_home.xml create mode 100644 app/src/main/res/layout-xlarge/fragment_library.xml create mode 100644 app/src/main/res/layout-xlarge/fragment_main_activity_recycler_view.xml create mode 100644 app/src/main/res/layout-xlarge/fragment_mini_player.xml create mode 100644 app/src/main/res/layout-xlarge/fragment_name.xml create mode 100644 app/src/main/res/layout-xlarge/fragment_player.xml create mode 100644 app/src/main/res/layout-xlarge/item_artist.xml create mode 100644 app/src/main/res/layout-xlarge/item_image.xml create mode 100644 app/src/main/res/layout-xlarge/pager_item.xml create mode 100644 app/src/main/res/layout/abs_playlists.xml create mode 100644 app/src/main/res/layout/activity_about.xml create mode 100644 app/src/main/res/layout/activity_about_content.xml create mode 100755 app/src/main/res/layout/activity_album.xml create mode 100644 app/src/main/res/layout/activity_album_style_2.xml create mode 100755 app/src/main/res/layout/activity_album_tag_editor.xml create mode 100755 app/src/main/res/layout/activity_artist_details.xml create mode 100755 app/src/main/res/layout/activity_artist_details_blur.xml create mode 100644 app/src/main/res/layout/activity_donation.xml create mode 100644 app/src/main/res/layout/activity_equalizer.xml create mode 100644 app/src/main/res/layout/activity_genre_details.xml create mode 100644 app/src/main/res/layout/activity_license.xml create mode 100644 app/src/main/res/layout/activity_lock_screen.xml create mode 100644 app/src/main/res/layout/activity_lock_screen_old_style.xml create mode 100644 app/src/main/res/layout/activity_lyrics.xml create mode 100644 app/src/main/res/layout/activity_main_content.xml create mode 100644 app/src/main/res/layout/activity_main_drawer_layout.xml create mode 100755 app/src/main/res/layout/activity_playing_queue.xml create mode 100644 app/src/main/res/layout/activity_playlist_detail.xml create mode 100644 app/src/main/res/layout/activity_pro_version.xml create mode 100644 app/src/main/res/layout/activity_pro_version_content.xml create mode 100755 app/src/main/res/layout/activity_search.xml create mode 100755 app/src/main/res/layout/activity_settings.xml create mode 100755 app/src/main/res/layout/activity_song_tag_editor.xml create mode 100644 app/src/main/res/layout/activity_user_info.xml create mode 100755 app/src/main/res/layout/app_widget_big.xml create mode 100755 app/src/main/res/layout/app_widget_card.xml create mode 100755 app/src/main/res/layout/app_widget_classic.xml create mode 100755 app/src/main/res/layout/app_widget_small.xml create mode 100644 app/src/main/res/layout/artist_sub_header.xml create mode 100644 app/src/main/res/layout/bread_crumb.xml create mode 100644 app/src/main/res/layout/card_credit.xml create mode 100644 app/src/main/res/layout/card_donate.xml create mode 100644 app/src/main/res/layout/card_luis_gomez.xml create mode 100644 app/src/main/res/layout/card_other.xml create mode 100644 app/src/main/res/layout/card_retro_info.xml create mode 100644 app/src/main/res/layout/card_social.xml create mode 100644 app/src/main/res/layout/dialog_add_to_playlist.xml create mode 100644 app/src/main/res/layout/dialog_create_playlist.xml create mode 100644 app/src/main/res/layout/dialog_delete_playlist.xml create mode 100644 app/src/main/res/layout/dialog_delete_songs.xml create mode 100644 app/src/main/res/layout/dialog_file_details.xml create mode 100644 app/src/main/res/layout/dialog_file_share.xml create mode 100644 app/src/main/res/layout/dialog_playlist_rename.xml create mode 100644 app/src/main/res/layout/dialog_promotional_offer.xml create mode 100644 app/src/main/res/layout/dialog_remove_from_playlist.xml create mode 100644 app/src/main/res/layout/dialog_sleep_timer.xml create mode 100644 app/src/main/res/layout/donate_layout.xml create mode 100644 app/src/main/res/layout/dream_service.xml create mode 100644 app/src/main/res/layout/fragment_adaptive_cover.xml create mode 100644 app/src/main/res/layout/fragment_adaptive_player.xml create mode 100644 app/src/main/res/layout/fragment_adaptive_player_playback_controls.xml create mode 100644 app/src/main/res/layout/fragment_album_card_cover.xml create mode 100644 app/src/main/res/layout/fragment_album_circle_cover.xml create mode 100644 app/src/main/res/layout/fragment_album_cover.xml create mode 100644 app/src/main/res/layout/fragment_album_flat_cover.xml create mode 100644 app/src/main/res/layout/fragment_album_full_cover.xml create mode 100644 app/src/main/res/layout/fragment_album_material_cover.xml create mode 100644 app/src/main/res/layout/fragment_blur.xml create mode 100644 app/src/main/res/layout/fragment_blur_playback_controls.xml create mode 100644 app/src/main/res/layout/fragment_card_blur_player.xml create mode 100644 app/src/main/res/layout/fragment_card_blur_player_playback_controls.xml create mode 100644 app/src/main/res/layout/fragment_card_player.xml create mode 100644 app/src/main/res/layout/fragment_card_player_playback_controls.xml create mode 100644 app/src/main/res/layout/fragment_carousal_album_cover.xml create mode 100644 app/src/main/res/layout/fragment_cast_mini_controller.xml create mode 100644 app/src/main/res/layout/fragment_color_player.xml create mode 100644 app/src/main/res/layout/fragment_color_player_playback_controls.xml create mode 100644 app/src/main/res/layout/fragment_flat_player.xml create mode 100644 app/src/main/res/layout/fragment_flat_player_playback_controls.xml create mode 100644 app/src/main/res/layout/fragment_folder.xml create mode 100644 app/src/main/res/layout/fragment_full.xml create mode 100644 app/src/main/res/layout/fragment_full_player_controls.xml create mode 100644 app/src/main/res/layout/fragment_hmm_controls_fragment.xml create mode 100644 app/src/main/res/layout/fragment_hmm_player.xml create mode 100644 app/src/main/res/layout/fragment_holiday_controls_fragment.xml create mode 100644 app/src/main/res/layout/fragment_holiday_player.xml create mode 100755 app/src/main/res/layout/fragment_home.xml create mode 100644 app/src/main/res/layout/fragment_library.xml create mode 100644 app/src/main/res/layout/fragment_lock_screen_playback_controls.xml create mode 100644 app/src/main/res/layout/fragment_main_activity_recycler_view.xml create mode 100644 app/src/main/res/layout/fragment_main_settings.xml create mode 100644 app/src/main/res/layout/fragment_material.xml create mode 100644 app/src/main/res/layout/fragment_material_playback_controls.xml create mode 100644 app/src/main/res/layout/fragment_mini_player.xml create mode 100644 app/src/main/res/layout/fragment_name.xml create mode 100644 app/src/main/res/layout/fragment_plain_controls_fragment.xml create mode 100644 app/src/main/res/layout/fragment_plain_player.xml create mode 100644 app/src/main/res/layout/fragment_player.xml create mode 100644 app/src/main/res/layout/fragment_player_album_cover.xml create mode 100755 app/src/main/res/layout/fragment_player_playback_controls.xml create mode 100644 app/src/main/res/layout/fragment_playlist.xml create mode 100644 app/src/main/res/layout/fragment_queue_player.xml create mode 100644 app/src/main/res/layout/fragment_queue_player_playback_controls.xml create mode 100644 app/src/main/res/layout/fragment_simple_controls_fragment.xml create mode 100644 app/src/main/res/layout/fragment_simple_player.xml create mode 100755 app/src/main/res/layout/fragment_volume.xml create mode 100644 app/src/main/res/layout/home_section_content.xml create mode 100644 app/src/main/res/layout/home_shortcuts.xml create mode 100644 app/src/main/res/layout/horizontal_progress.xml create mode 100644 app/src/main/res/layout/image.xml create mode 100644 app/src/main/res/layout/item_artist.xml create mode 100644 app/src/main/res/layout/item_card.xml create mode 100644 app/src/main/res/layout/item_card_color.xml create mode 100644 app/src/main/res/layout/item_collage.xml create mode 100644 app/src/main/res/layout/item_color.xml create mode 100644 app/src/main/res/layout/item_contributors.xml create mode 100644 app/src/main/res/layout/item_donation_option.xml create mode 100644 app/src/main/res/layout/item_grid.xml create mode 100644 app/src/main/res/layout/item_grid_circle.xml create mode 100644 app/src/main/res/layout/item_image.xml create mode 100755 app/src/main/res/layout/item_list.xml create mode 100644 app/src/main/res/layout/item_list_single_row.xml create mode 100644 app/src/main/res/layout/item_playlist.xml create mode 100755 app/src/main/res/layout/item_song.xml create mode 100644 app/src/main/res/layout/layout_notification_collapsed.xml create mode 100644 app/src/main/res/layout/layout_notification_expanded.xml create mode 100644 app/src/main/res/layout/notification.xml create mode 100644 app/src/main/res/layout/notification_big.xml create mode 100644 app/src/main/res/layout/pager_item.xml create mode 100644 app/src/main/res/layout/pager_recycler_view.xml create mode 100644 app/src/main/res/layout/preference_dialog_library_categories.xml create mode 100644 app/src/main/res/layout/preference_dialog_library_categories_listitem.xml create mode 100644 app/src/main/res/layout/preference_dialog_now_playing_screen.xml create mode 100644 app/src/main/res/layout/preference_now_playing_screen_item.xml create mode 100644 app/src/main/res/layout/recycler_view_sec.xml create mode 100644 app/src/main/res/layout/retro_seekbar.xml create mode 100755 app/src/main/res/layout/shadow_statusbar_toolbar.xml create mode 100644 app/src/main/res/layout/simple_list_item.xml create mode 100644 app/src/main/res/layout/sliding_music_panel_layout.xml create mode 100755 app/src/main/res/layout/status_bar.xml create mode 100644 app/src/main/res/layout/sub_header.xml create mode 100644 app/src/main/res/layout/user_action_details.xml create mode 100644 app/src/main/res/menu/bottom_navigation_main.xml create mode 100644 app/src/main/res/menu/menu_album_detail.xml create mode 100644 app/src/main/res/menu/menu_artist_detail.xml create mode 100644 app/src/main/res/menu/menu_cannot_delete_single_songs_playlist_songs_selection.xml create mode 100644 app/src/main/res/menu/menu_cast.xml create mode 100644 app/src/main/res/menu/menu_expanded_controller.xml create mode 100644 app/src/main/res/menu/menu_folders.xml create mode 100644 app/src/main/res/menu/menu_genre_detail.xml create mode 100644 app/src/main/res/menu/menu_home.xml create mode 100644 app/src/main/res/menu/menu_item_cannot_delete_single_songs_playlist_song.xml create mode 100644 app/src/main/res/menu/menu_item_directory.xml create mode 100644 app/src/main/res/menu/menu_item_file.xml create mode 100644 app/src/main/res/menu/menu_item_playing_queue_song.xml create mode 100644 app/src/main/res/menu/menu_item_playlist.xml create mode 100644 app/src/main/res/menu/menu_item_playlist_song.xml create mode 100644 app/src/main/res/menu/menu_item_smart_playlist.xml create mode 100644 app/src/main/res/menu/menu_item_song.xml create mode 100644 app/src/main/res/menu/menu_main.xml create mode 100644 app/src/main/res/menu/menu_media_selection.xml create mode 100755 app/src/main/res/menu/menu_player.xml create mode 100644 app/src/main/res/menu/menu_playlist_detail.xml create mode 100644 app/src/main/res/menu/menu_playlists_selection.xml create mode 100644 app/src/main/res/menu/menu_playlists_songs_selection.xml create mode 100644 app/src/main/res/menu/menu_search.xml create mode 100644 app/src/main/res/menu/menu_smart_playlist_detail.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/transition/default_window_fade.xml create mode 100644 app/src/main/res/values-ar/strings.xml create mode 100644 app/src/main/res/values-cs/strings.xml create mode 100644 app/src/main/res/values-de-rDE/strings.xml create mode 100644 app/src/main/res/values-de/strings.xml create mode 100644 app/src/main/res/values-el/strings.xml create mode 100644 app/src/main/res/values-es-rES/strings.xml create mode 100644 app/src/main/res/values-es-rUS/strings.xml create mode 100644 app/src/main/res/values-es/strings.xml create mode 100644 app/src/main/res/values-eu-rES/strings.xml create mode 100644 app/src/main/res/values-fr/strings.xml create mode 100644 app/src/main/res/values-hdpi/dimens.xml create mode 100644 app/src/main/res/values-hi-rIN/strings.xml create mode 100644 app/src/main/res/values-hi/strings.xml create mode 100644 app/src/main/res/values-hr/strings.xml create mode 100644 app/src/main/res/values-hu/strings.xml create mode 100644 app/src/main/res/values-id/strings.xml create mode 100644 app/src/main/res/values-in/strings.xml create mode 100644 app/src/main/res/values-it/strings.xml create mode 100644 app/src/main/res/values-ja/strings.xml create mode 100644 app/src/main/res/values-ko/strings.xml create mode 100644 app/src/main/res/values-ldpi/dimens.xml create mode 100644 app/src/main/res/values-mdpi/dimens.xml create mode 100644 app/src/main/res/values-ms/strings.xml create mode 100644 app/src/main/res/values-nl/strings.xml create mode 100644 app/src/main/res/values-pl/strings.xml create mode 100644 app/src/main/res/values-pt-rBR/strings.xml create mode 100644 app/src/main/res/values-ro/strings.xml create mode 100644 app/src/main/res/values-ru/strings.xml create mode 100644 app/src/main/res/values-sr/strings.xml create mode 100644 app/src/main/res/values-sw600dp-land/dimens.xml create mode 100644 app/src/main/res/values-sw600dp/dimens.xml create mode 100644 app/src/main/res/values-sw600dp/integers.xml create mode 100644 app/src/main/res/values-tr/strings.xml create mode 100644 app/src/main/res/values-v19/dimens.xml create mode 100644 app/src/main/res/values-v21/dimens.xml create mode 100644 app/src/main/res/values-v21/fonts.xml create mode 100644 app/src/main/res/values-v21/integers.xml create mode 100644 app/src/main/res/values-v21/styles.xml create mode 100644 app/src/main/res/values-v23/dimens.xml create mode 100644 app/src/main/res/values-xhdpi/dimens.xml create mode 100644 app/src/main/res/values-xxhdpi/dimens.xml create mode 100644 app/src/main/res/values-xxxhdpi/dimens.xml create mode 100644 app/src/main/res/values-zh-rCN/strings.xml create mode 100644 app/src/main/res/values-zh-rHK/strings.xml create mode 100644 app/src/main/res/values-zh-rTW/strings.xml create mode 100755 app/src/main/res/values/arrays.xml create mode 100644 app/src/main/res/values/attrs.xml create mode 100644 app/src/main/res/values/circular_image_view_attrs.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100755 app/src/main/res/values/donottranslate.xml create mode 100644 app/src/main/res/values/ic_launcher_background.xml create mode 100644 app/src/main/res/values/ids.xml create mode 100644 app/src/main/res/values/integers.xml create mode 100644 app/src/main/res/values/lyric_view_attrs.xml create mode 100644 app/src/main/res/values/md_colors.xml create mode 100644 app/src/main/res/values/metal_recycler_view_attrs.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/main/res/values/styles_parents.xml create mode 100644 app/src/main/res/values/swipe_button_attrs.xml create mode 100755 app/src/main/res/values/values.xml create mode 100755 app/src/main/res/xml/app_widget_big_info.xml create mode 100755 app/src/main/res/xml/app_widget_card_info.xml create mode 100755 app/src/main/res/xml/app_widget_classic_info.xml create mode 100644 app/src/main/res/xml/app_widget_small_info.xml create mode 100644 app/src/main/res/xml/automotive_app_desc.xml create mode 100755 app/src/main/res/xml/pref_advanced.xml create mode 100755 app/src/main/res/xml/pref_audio.xml create mode 100644 app/src/main/res/xml/pref_blacklist.xml create mode 100755 app/src/main/res/xml/pref_general.xml create mode 100755 app/src/main/res/xml/pref_images.xml create mode 100755 app/src/main/res/xml/pref_lockscreen.xml create mode 100755 app/src/main/res/xml/pref_notification.xml create mode 100644 app/src/main/res/xml/pref_now_playing_screen.xml create mode 100644 app/src/main/res/xml/pref_others.xml create mode 100644 app/src/main/res/xml/pref_playlists.xml create mode 100644 app/src/main/res/xml/pref_ui.xml create mode 100644 app/src/main/res/xml/pref_window.xml create mode 100644 app/src/main/res/xml/provider_paths.xml create mode 100644 app/src/test/java/code/name/monkey/retromusic/ui/fragments/settings/PersonaliseSettingsFragmentTest.java create mode 100644 appthemehelper/.gitignore create mode 100644 appthemehelper/appthemehelper.iml create mode 100644 appthemehelper/build.gradle create mode 100644 appthemehelper/proguard-rules.pro create mode 100644 appthemehelper/src/androidTest/java/code/name/monkey/appthemehelper/ExampleInstrumentedTest.java create mode 100644 appthemehelper/src/main/AndroidManifest.xml create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/ATH.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/ATHActivity.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/ThemeStore.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/ThemeStoreInterface.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/ThemeStorePrefKeys.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/ATHActionBarActivity.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/ATHToolbarActivity.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/ATECheckBoxPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/ATEColorPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/ATEDialogPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/ATEEditTextPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/ATEListPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/ATEMultiSelectPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/ATEPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/ATEPreferenceCategory.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/ATESwitchPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/BorderCircleView.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/ATECheckBoxPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/ATEColorPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/ATEDialogPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/ATEEditTextPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/ATEListPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/ATEPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/ATEPreferenceCategory.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/ATEPreferenceFragmentCompat.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/ATESwitchPreference.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/dialogs/ATEEditTextPreferenceDialogFragmentCompat.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/dialogs/ATEListPreferenceDialogFragmentCompat.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/prefs/supportv7/dialogs/ATEPreferenceDialogFragment.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/views/ATECheckBox.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/views/ATEEditText.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/views/ATEPrimaryTextView.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/views/ATEProgressBar.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/views/ATERadioButton.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/views/ATESecondaryTextView.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/views/ATESeekBar.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/views/ATEStockSwitch.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/common/views/ATESwitch.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/ATHUtil.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/ColorUtil.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/DrawableUtil.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/EdgeGlowUtil.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/MaterialDialogsUtil.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/MaterialValueHelper.java create mode 100644 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/StatusBarUtil.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TabLayoutUtil.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TextInputLayoutUtil.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TintHelper.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/ToolbarContentTintHelper.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TypefaceHelper.java create mode 100644 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/VersionUtils.java create mode 100755 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/ViewUtil.java create mode 100755 appthemehelper/src/main/res/drawable/ate_check.xml create mode 100644 appthemehelper/src/main/res/drawable/ate_switch.xml create mode 100644 appthemehelper/src/main/res/drawable/ic_toggle_switch.xml create mode 100644 appthemehelper/src/main/res/drawable/ic_toggle_switch_off.xml create mode 100755 appthemehelper/src/main/res/layout/ate_preference_category.xml create mode 100755 appthemehelper/src/main/res/layout/ate_preference_checkbox.xml create mode 100755 appthemehelper/src/main/res/layout/ate_preference_color.xml create mode 100755 appthemehelper/src/main/res/layout/ate_preference_custom.xml create mode 100755 appthemehelper/src/main/res/layout/ate_preference_custom_support.xml create mode 100755 appthemehelper/src/main/res/layout/ate_preference_switch.xml create mode 100755 appthemehelper/src/main/res/layout/ate_preference_switch_support.xml create mode 100755 appthemehelper/src/main/res/values-large/dimens.xml create mode 100755 appthemehelper/src/main/res/values/attrs.xml create mode 100755 appthemehelper/src/main/res/values/colors.xml create mode 100755 appthemehelper/src/main/res/values/colors_material_design.xml create mode 100755 appthemehelper/src/main/res/values/dimens.xml create mode 100644 appthemehelper/src/main/res/values/ids.xml create mode 100644 appthemehelper/src/main/res/values/strings.xml create mode 100644 appthemehelper/src/test/java/code/name/monkey/appthemehelper/ExampleUnitTest.java create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 local.properties create mode 100755 public.properties create mode 100644 settings.gradle diff --git a/.idea/RetroMusicPlayer.iml b/.idea/RetroMusicPlayer.iml new file mode 100644 index 00000000..d6ebd480 --- /dev/null +++ b/.idea/RetroMusicPlayer.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..30aa626c --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..2876f8fb --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/RetroMusicPlayer.iml b/RetroMusicPlayer.iml new file mode 100644 index 00000000..c5796822 --- /dev/null +++ b/RetroMusicPlayer.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 00000000..b23b9e1a --- /dev/null +++ b/app/app.iml @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 00000000..ed8fc97b --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,145 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + buildToolsVersion '28.0.1' + defaultConfig { + minSdkVersion 21 + targetSdkVersion 28 + + renderscriptTargetApi 28 //must match target sdk and build tools + vectorDrawables.useSupportLibrary = true + + applicationId "code.name.monkey.retromusic" + versionCode 203 + versionName 'R - 1.6.400' + + multiDexEnabled true + + buildConfigField("String", "LASTFM_API_KEY", "\"${getProperty(getProperties('../public.properties'), 'LASTFM_API_KEY')}\"") + buildConfigField("String", "GOOGLE_PLAY_LICENSE_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"") + } + + buildTypes { + release { + minifyEnabled true + shrinkResources true + zipAlignEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + + resValue "string", "cast_app_id", "D3C555E1" + } + debug { + applicationIdSuffix '.debug' + versionNameSuffix ' DEBUG' + + resValue "string", "cast_app_id", "D3C555E1" + } + } + flavorDimensions "default" + productFlavors { + normal { + versionCode defaultConfig.versionCode + 10000 + versionName defaultConfig.versionName + "_" + getDate() + dimension "default" + } + } + + packagingOptions { + exclude 'META-INF/LICENSE' + exclude 'META-INF/NOTICE' + exclude 'META-INF/rxjava.properties' + } + lintOptions { + disable 'MissingTranslation' + disable 'InvalidPackage' + abortOnError false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + configurations.all { + resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9' + } + + configurations.all { + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + def requested = details.requested + if (requested.group == 'com.android.support') { + if (!requested.name.startsWith("multidex")) { + details.useVersion '27.1.1' + } + } + } + } +} + +def getProperties(String fileName) { + final def Properties properties = new Properties() + def file = file(fileName) + if (file.exists()) { + file.withInputStream { stream -> properties.load(stream) } + } + return properties +} + +static def getProperty(Properties properties, String name) { + return properties.getProperty(name) ?: "$name missing" +} + +static def getDate() { + new Date().format('yyyyMMdd') +} + +ext { + supportLibVersion = "27.1.1" + firebase = "11.8.0" + retrofit = "2.3.0" + butterKnife = "8.8.1" + materialDialog = "0.9.6.0" +} +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'com.android.support:multidex:1.0.3' + implementation "com.android.support:appcompat-v7:$supportLibVersion" + implementation "com.android.support:recyclerview-v7:$supportLibVersion" + implementation "com.android.support:gridlayout-v7:$supportLibVersion" + implementation "com.android.support:cardview-v7:$supportLibVersion" + implementation "com.android.support:palette-v7:$supportLibVersion" + implementation "com.android.support:design:$supportLibVersion" + implementation "com.android.support:support-annotations:$supportLibVersion" + implementation "com.android.support:preference-v7:$supportLibVersion" + implementation "com.android.support:preference-v14:$supportLibVersion" + implementation "com.squareup.retrofit2:retrofit:$retrofit" + implementation "com.squareup.retrofit2:converter-gson:$retrofit" + implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit" + implementation "com.jakewharton:butterknife:$butterKnife" + annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnife" + implementation "com.afollestad.material-dialogs:core:$materialDialog" + implementation "com.afollestad.material-dialogs:commons:$materialDialog" + implementation 'com.afollestad:material-cab:0.1.12' + implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' + implementation 'io.reactivex.rxjava2:rxjava:2.1.9' + implementation 'com.github.bumptech.glide:glide:3.8.0' + implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' + implementation 'com.squareup.okhttp3:okhttp:3.10.0' + implementation 'com.github.bumptech.glide:okhttp3-integration:1.5.0' + implementation('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0@aar') { + transitive = true + } + implementation 'com.mpatric:mp3agic:0.8.3' + implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0' + implementation 'com.github.kabouzeid:RecyclerView-FastScroll:1.0.16-kmod' + implementation 'com.anjlab.android.iab.v3:library:1.0.44' + implementation 'jp.wasabeef:glide-transformations:2.0.2' + /*UI Library*/ + implementation 'com.github.jetradarmobile:android-snowfall:1.1.6' + implementation 'uk.co.chrisjenx:calligraphy:2.3.0' + implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2' + implementation 'com.r0adkll:slidableactivity:2.0.6' + /*Backend all*/ + implementation project(':appthemehelper') + implementation 'com.sothree.slidinguppanel:library:3.4.0' + implementation 'org.nanohttpd:nanohttpd:2.3.1' +} diff --git a/app/libs/jaudiotagger-android-2.2.3.jar b/app/libs/jaudiotagger-android-2.2.3.jar new file mode 100644 index 0000000000000000000000000000000000000000..11a46d34a9029c03391c13a8b55d48a64ccbb511 GIT binary patch literal 967450 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
rv+X88cBeXp;B>*?Qiq~br% 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ⅆjm`NWu`GsF@YcOIh7`^Yiy{{3 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
M^?;9 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

}{k9OACPhNZoUu8C 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

  • d2(Q)mtQ!Ih_M89Dw!5)4ot z-~fACvYhZFe5=itEd9Op&5RV-D{D7Mr*}8{+?EfSmxz-yx2h=8o(2=3xq)c9wAkQ5 zI?CJ>9tK+g%ZYUZ`zj$~>{S#&ZG{>rEgFjpxRIimux|6s-@p>go(=y{Gudd^ggG)T z)6O)Rmp5vyDdy5+LQgUG+Pe!_b!6>K#%PD+QX;RqpV1b>T2Ny0p1;dE){0&|6@ z;nz~6L{(%Jik{PTQc0$4Mf6Qvha1b1*k<50V(jwVBNb16-X!y`g!JI!Z>9Dpn187IO^Oy4{Lyb)o z2^qU5xt8GY)#hOA?2?bq3#ce7Z2&r>w5qfR22JaPL0NW6Zcc8dx==5Z$br(GC=xS9 zcsuTw8%|T2PCJqNhmG~dfzGJOqv$Z3Z^SIO1Alggo?Pr7!OZL#Nd8G4JMap~yj>R_ z78Aw*4c69dyNOjFH0M+2K58XWF>~l2%nWB?zt`u zsge{Jcppk3U6-dE+N!rrb($9v(`X^F%+R+lqU?UZmbM*`;9f@>5ENa&*`wvU6^RP@ zGjyD`AGAdR zn9vjjq-6hTJ6F{BE5P(40ho#`N4XmZSZhi)ju69&a0PwJINO+;=V`}$)#59_G^qgg zX%FG1dlZ)A2gi@sT--@Z5>#5|r>ODaX7|_h+RcN-%S*m*l7tunxG3P{xk*e6c)gly zq1!AMBG*}=8wg77!gRGG@00*e9_36KSkhckp=dS+EA8&C9G^m1Ug--duGYF8{TLUD z)-lA%vTG?zm1d10CBd`L8W%dRPgNW6_%2+G2T4D@oW1=dwi;FNllehdzMY@$k zrKM|$C*1Z85LO1^I>furXl~()5;HK)`NZz2S`D;PD+ZaBp}s0B4H)t9#59>&>e=Ci z<)4)^u<@DMlj85I5h1BQOVH?RIV!{mAQDt5d%7G%W+ql10?ICgyedv_DcipDT{ihf zg$*FlC5fXwnKr1(WmSjTM;6J0Q~ApWdv4f}c16ZIrIc)Q=&T@<#;YNaX))FyY6;MX zWvnwNggLeSrp~C=18EE!-4n!}m- znmHNsaZ0IpOv55}CngbKcRy*M0n2)Eq%ieehyB`}ajw>DH6kax!Y(M=aS5B%q2#F{ zWeGwN5(Cs3!Mar?$YOX4oz!MG zEVlRIV)&=z_?*AOb)trDUlP)}+GyVO`dYavXT%=W=`h;{&|Wh8rvc0yFfEYcYIhPW zL*(hRu0CHdmk5RLD>aDHAy|V09E+wFv^EuiAF~x zZdgNw=_YU-)4X#ZEEYg%N{)}2D~+%QLSWVG3(k@BS(b*Ax#ybS#awoA0ex#~OWQ9s zh~)5x%bh+QLm5bN7tq?&Dtn6xo^==!!m(QyjDBtP(HaV zVV#BCStN0IeD`S6lPS-h_455q!fm$@|9f0?Db@@AZQvpx^Uth<|Nn7;+5psUN_M=! zrsn4gbo|~0f68LNNDE`)LETP#-2-uz9cGjOC-3hMus%2&eD+M^WPW{}oc!~xWJyL3 z?7PyE(sn#_r2{4nID0|=T9I0-mr5SmXzy7Kztq{q*|-}vi14o7&Dl7-YxpKb?1 z0F49VnsR~SMoTPZ1Dpi5wS&Bi<^Z3&wWCK#O8Q=u%3ba}1_p_Gv6z(}FK|E`qcZPt z>Vgtw*{?<#Ul5J#ne*VTD#peL9ahr@s?KSiB&mYf(TFE(@y*lIB8IYN;yS$TfEpS! z3M15m`)JD-zbq1I1C}$h)rz7USWA*z-(r600G{599;B5^v)+@`AOVUzD)`=yzko}V z|9;Ur0>}o`=U>2O@&4G9RwvVRK4iktM8RT2e~fi`BkD14cIRSG6*D5C#TDk?z=irB zz(wH;xP)hz)-mOyi~Jk7U}00M7Sb}){{y%H)i7pB|M$31999U0Ox-O>%Bp#ds}70} zRbz{}1G?K;*nk{XTjFM#Cs~?kG6$Zm{^iw`a|VPjU*B_J(jGx)5t%ivYtiGW>h0nG z*SHu|eE0tv7lr>dF6ajZBn=fdDXtVr>k9@F)50!Y6z_Mw|L>DnfW^O$`{j+mLHmEF zwiN|r{^^e>SNU|pRYLo0Gn`#sm+Y{Z$up7Xr;=h%Z3q?9h@V?I&}g-YNg&VL6y#b? zH!oP9urxA~@C~_#`6J{LqAMgA0vTfbb4f77JBW~wnE3E1wDSt#=o(_O81;H1dDyUK z*<#j?hqL)|+~aY>Y4dQy>2j6*^YtzC+sbtZK`O(9pq_2qFe4Py_lVbQl4B8QiZ_O+ z1nnCUz_8fC+Fmax`MaRy!Q}U=v(T~E7y=v{nAqPXO*Y@Pmj}^aj%od-L<#>rOQ{4 z$K(5wH^loB5dKa-fw;43Pb4W1@pf6)3|&e^vIdyAZ#fBY#)ZBlTG82}y#s@tyCN$f zej3yU_=7DQuQ>?rue{Nn8>a;yfX zV(B$|ay~arroy@S>d1Xlw zPmKE={(~VdYunDho$J@t=x|tvicBxq;}kcJAHwjJat*g&-Z}MIgZU~WRdVx zatB+^&gWD!oJBgG+U6hLlsL;%NY3%tRDrX5uy7S5`_m+gbtab6F5~l3#g?@m%}nGU z5y+T@70+kOURl4-vR`o;xIX6@&1r2j<^k2u5oG1YuEs`l3YVZO9$`ZYjwhE_Bg zsjea{(Z_KqBs*}+F}Mdt-Wh#OjN=R?Gvb`A=^M7WgBD{Rf6d)Sz5DoA)=S$5L>tjA zzy{hDr_4T5;YW1V{S* zwhJ2NZx-zZxGyw<~iRIPp_I9n}V@BVo2yL$BKk_hLC&u2Jra;C={Gu9T z`a(RX3AJc|wl75E&=dzPLYjlZrEabod?+uUMa|a=T7sd->2n@xN+*P1RgYvP&NxGz zoHz2P=t(}`imoX*TmFyieGzs;X<)kV8W?z7FkbC^atobWR2l3N^MIQmv@%br+mVR^ zksobiM$2GMBbmqY$q)NRh~p@GBl>BP1ML3#&>?l`eNned|Kbxy)`K7CF&+?b_VKJg2JFYXbt?_m0q)dTFJ*NvMiT0Pd5D_ur(GCDhM&7w% zm2{UIq1Kr+cZI4~-BB%O&eYn`GySZAl0j6G1PN&P2S@>d>m93MSp_IEaf)M`*BRal zOaV}Ek=9zwPHi@q;@0Gl0)-&#P<8!pqsZbZH}nP4)-x`YoKzZ#D#S( z>G|}SRB6pWxWdBKGhR85zH2EORUVq-QN+>|2f!O52NSX8V}}&O>mwH=h!>$7{yy{z zEHl!Wnb%J@(ioUS-aZFpOERUJ-=kX>JNHa*3G7p<(4VpEN&(&4x5ul}e&;n}K9bep zptrkRKq|`-`5>q5Hgu2iY**yJvhz8rznlL>!m1btC?Lux7)G{7zMq9W3xHVEfoa-S z=YN82m>B~9af-Pl9z)y8GRGE9_KaRZk&ZOVpH8>0y0y%f0yVneIH(Ltb_XGvJ>W1) zIn3_pABQ@+6yKmak>pQruR$+<^y|A=?eY)o!&D2i6adAhx$hYMcU?yaM=nE>C83#C zlM5ngzIO!escW}(5M43tW5tOl`A~;gm=5H@Dg-x3bqOVN5|fQPMPu-pgaIt)$sP$m zD{7W`KEE1S^qa1h#Vt*CznkJI=Axk-rqB{*%Ep8FRsxal)gbhaU4~Xw`K7mcrxqru z=T3P73h1axMMSbCNL2&Kr??(>aBJc|ZQ&C(5FYDNrH@(YkJ(U#P<5}>;0RNdJIwYA z5Ku*d4E}*s>XBQN_++5?y>!k!Jw$?A@j1RRrWom+P`NCtBHW8#cB*=hsE6ItX4Q%vAq(O$BYSR_NIM1F8B^sd$>3I6@!JNfk)1s0G`}JTRN?*`9xV6 zt2M(m-+AYF&#+GE=Qr@}8}#jaHp@QlxQ0tz#K5#VKsM| z!(ENkNUQR2D*=ICmz%!8-r6VPv{LjvBhQjg53T$v_UqfwO}UGP3bH9{_)&Q2Tzc8e zep_e}0VOkZni}IV_9vfFZ4j)tHU}rmF_&8(1y|zQY0DgAg&>?-)!}Kaq|bQNoPq!% zT}Kn+6XIVh-b^{4S$6NSxGxyxAF0ZdC{+YIrtX5L1i1>bwTSskL~YHcOc-IVzhhy3 z^`ZI3Q)(jm!W2=cKN9RbKM#i4ZNTV9;ql-?&p}iS<+wOeTIVxA^ARIvo#N(&Yg8>@ zTY$3VrqQc%y5|4`$%VTjb)n^;)9G^h<{*{plCgyvnxm955Gw0+s)qUz#|h;82ox-Z z3GRIstwR;+8RR>_CA}clR`c-wHl#a`Wgoy1T#;k0ejc1I6d0?UjhvdVY^jteDUh5m)*zo41>s%008PcofN8_FruwH`w zo7exwTYy~#E{?xT6bZ=u>vbNh`BjR53fTNNWl1m(wn7io9$g^T*f37s7x~k*v#OU1 zZk=`Xr@B|XRSHB3>BrQ%JBoy5C*mC0SkN<}L)RcwQ{)yD)rB~tsi(Fx3sP?E1 zarS3NO9rCnFn@+X{t5ko6Pe2v0w($HzN_`8DxUm0 zNq;ujkSM1u^zRy~Snm|AhVzYhTd6)NkaU&|l!W0L5tOPnYe|$?%lPsF!j| z%(qIs+E7R0E%NOOFND#*->0JVuMF-M^tf(|<$%fWJ7)eDuJ7 zL;o+%QZ=8JnfhPQf6JR%=`YTbm{IDBvy6Z|&HevC|A7g_VUxe0Kk?E+kvZ&aweWvH zfB0-EJsC(hE{Io197ac!$l@2MeQYY3<5nR*y!&<>1jb}34}xBW=sOo(_u=cO3=yU8 zU*xm|2@6hLhzy1}|t)Tg}1&qoout*<393tDF;~PT1 zuUC!s=O;3CR9W%M6aW)hs$u<@Deo-hJkGmw7($9g%KZxBDL2fiAQd=Yig0|x?eQ)n zmiutx5_I+U8WxXN7D0Mik=SC#d;M{q;XhsXgH{ANpFio-zr6?Pa7 z39@-OstWx9GmJfZ5Nkk!cp}}-Ff{JDA{X$;Smn=wVHG@Hhh%xp z)!fPWk_7V7W3fMpg)mv9+VnARo9%hHHjHEp1)kS;{NOIzg`7HJ^i(O6tNJ5!YryU&@o7 zPaUIcV4N$BqLBVYqtB&T?ORe%q^nMYV#X;t6)8Mskhmgx7t&5XQ-Gd&Ugyv+xz^9i zn-grZR%l6>Xj1@}tFl0}+z6s?bVZop5hOClD^dSz2$whVnl!_WlZ}xv`fUSE z#G9{O_q|G(yPDGCbx^F%o*m%11oGMCv7~#qWzje` zrc_v}(qp@yUy~w-s51y&pc%X0$K%++14-;Vq_ep~O~9XOjcTWUoMH## zj>)U;7O%t%*<;wz1cmlH*NpXtp00{vRezrkUYh569=OzK8E6o@xg^qJji*W>%?)VcWu0(`)BVr6Nf^N(S2Sdq$qQ-i1E)6$rcHRaOu5*Kg5UDB`uA+YhEtm{0?^*FD%L ztQmwx<#I{%Dycr}XFAra(59!8a^4q;B0L)wmdM%9Tr9R1+qIi?0J+7|(|th4ecCAG z?O1n&$K@_RlOH4*B~;KxB#Q%nEFn;TB``1wU@ZZB@OTQSxfyiuWhiO7W=|!+UX??l)(q4Vgd z@0hdp_{uhX`43VhbZjExZx4AvNwt4c@c&meh|Um2SCUYw?e~&FI^ZJ3fUsO9Uxifb z>D!OE>#?d|AyHF^6KU@pn~}^$hF+h~&oDp1_F0s# zu*CxS);4`nEYL=OS3ltCSG4AAS9s-X!mD=gCengN4^`*-FgA>eSbB!o zzXtcH!1hxIMsi)!T6xO)Q1jJFwwu9%!IvJyW#V4(Z)I|}3j1(kiqTDaD^&{Vx=W?g z$lr-d+E4l@rl*T`nOw{k<`WC^W_Zz93oB_ zH<5xA-}A6hat1t{I|xYwgsZ3$GB%l02XhlQPz!VoinBnlC6T3&>Q!gSc^S$@Q5W$| zJnXZk%XjCXVe^w$&LffoOO=sR6Ey ztJ}u4w%Ds5VQ^4bP-;-Au-Rn>8XFJ*Z)84gNK0t-3bK*?57flPl+e5JVd8lg1Neggsyzv}dd_YO5 z@RKPht`b%NkK;(8eVR$eepJbgo76o-8%7;;b!Zy*IoUrQ(h=$K_d!##kt$|T>SVr* zg4vEu3a&SPppJuTJfptVbd8dUYlYT5y+*L*Mg=EnwMN~e?7V+Qe20`vs-XdvLHmX# zOYcH?9$!=z;>A-wbyF86X?2`#xQ_g^t59#G7}KuQERAx+Scy{?j2OmEFhXSpDY-la ze=HutNg(`}Zv;g#ivZ+dHsK1AydnxZL_;p6AHb2isEj`MLxWs`KNb5qk_A~Xp8}@9 z@&sAZ+PWx(60hWPz|Et^r)mv?Ck!W9t1nm?U&dY*$DSAWj#Iw5P%*a70o>DX@oipd zyD}U`TC|bzcY~As{R{26h_w%g{{%=))Z09AnFni+f@o*%1|Ym5!zjLo><}8DAD0qd z+-f~Ip#?>}ANd9fo|sK00I$=L2`b(2{qJjp%u>HI_LWTSN%D74h5SD);OVL`&WejR z8PUouDx*S>$&H}Mm{D!~kf7kS`e9mGV7xz(dumY9XwJpe+g8w8X?`wA@AQeCkxTjR z@|dqBaY)UPM}XL>hCxZ2;TAgJa9hmstQNRDBy$A6*5So^O|-YRs9ylrbjTbs8Xb&z z9gK}7w|?(<9;+2p9DQ`AlH{8?&V(rn^`sq_$$Ktl;fp;u?74!$dJj!ZIr@|T%pU%s zN%@&Q?d4i5yXQsqUYY08FVR`BX?&;geLR=IrTd{I@gwv@1N1{ACZGLgoa(k1b+H0%fzDEZH;uL>F=ysm0dM0HfOfIX4yl| z8H{6|#nJws-Um|IzYA}9zE5I|xVuVG!q{sa?F;!bjfDo(2nv(sG})tn-#3_vGx<$# zHp;3c*R^;np03i3+NOR8oles}*TW9Ul{ukQ1zb7ZyfSJQ&)Ous>puOM%>*E;_mJc4+(L1cXtml z;_mKl#E1v}cLwOyt5>gY|5tx|pX}3lG!N=}-l`g7+yy7BM`W0ZsQVpCp`gZu(3weY z0v8Jt9x|!o3&IzlBO@6br%;md@eZQ#s=Qp&hS9`2s&5G2@zU*11}6Jf3Rj`q&5&NU zt0oupcCf@k`I*i0+q5f;;$j8Gf2_ceZeY=C_%1Fo2eFpPtwkgC-SWLr5AG6;R0?i6 z#og0F3apQ0gQA%;aADwfNTN(3bxSK1WqCroa9s)))59KG{6p<%3X|LZJOtYeLpJ7P zb7K>f`Xkl2x9V7v0GsOOTZSlkMF>URng3f&eFdfuM8hVqLf*J~L=Ww%VRQHhLCAuT zgVtr3uzic9t}i!@11K-foamEB|dl`V>SFpAF#+nH!NVqn4seCRdS5B?A8*i)e}|*N_J_Y_5vd1HJqi@HyG~ z`eg_?%0{kP9yD6w6L3o+U52HDE6Zof(I00uPNw`*>oO&QpNfkb)=J2c>2twjLXKyw z0y}F2Au^xJt~P{723yE{^vz@r+4z`#B;%=bb(sfkO`*cWR^2g%%K>3@n!ChPYJ)uy z)GkXrYDo&=pHa5-Y2{tBS*CBLW$ES_z~#3VdDz?+s98(7JUDAtZguYPrx#EMh8q|Fy3VcS2cgDLfP zsC4xW6I!@&7&s)q&6~Q&B;FUFi1~d8=y!`{n?3dogmSwVOkYvr3d(F*RFbf1;99+Q z#!+bTd}VIrX2seI){aXMvyf*nSMzKtedFR4GA5I_oDYH+aulgFv`=?7`>-2a(1&if zhJjT}S7OLsCD~ zHRdt-SfQ8JVct9PXphQq=#J``;N|c}S{&2ua$acp9KW2eXX?qm@fuyG$ZE=I2nbzW zJ3t_PIa{yUkNtuE8aK0^TqxESa+3p6?DZI7Nk7(yTHe5fH3Ymq9jqit)Y6x;W0If3 zAigLK;=#SryO0d-Nh~fzkSP9?n4ub?z`x$)M~TcbK5!swbE#V&g$(m!W>HlS=0 z9|aQnVP^!3KE1Jd%QYCy1f;6L5K_+O+WivoXQ93?JGUTu_I%r+@uD)xQN^}0>d&$| zBi%CT9h4k;!6EP?G_+VJo^_>LjY~jyM5NN~8eno$WLfp?N>r{X;b?C}gK0D79^^*y z3s4(|O3;5iWDotke|fq8COtDRv!=#UKl^nkvCHJD4G*b}Q(U{#`O~hWt>kh|2&4)g zp>{h9nQZT#wCLlf%w`s-d-o{sO4rBoE{Cd|iatYRF<{X`9J3WK^a%zMYDww%Xl4aXJ)S+S!ikASTfwY!opt z_Dw}kocB4cXD9A&@0(OiP`V5=q@BOhS~d#Wz2h0;B912vR~L*cr4t|3k|g(y?xusrT6`V-gn6O_oMVbUTnYL zjen1E9>%tfpCkVXxW)5;K@OIlfsnn`TGiFMp3E3sq#kB^?%rTT{toM?`sI75BZl$O z%cy|qwHF5kfu<%;Ez)1ki*C)HY!Ex-%t!O^r77~d;pEB8!4S=oKt8~{n^GG$%CreQ zOSeH|8ush<8&!n~88A^b(bPUNHH#kW#8{*9!plIeJ;q`tBfo(`O%}IGD+|m*SarE% z;h~_nSeuB3<&bljN+fpSbe|GSRN7HHWS^oJs~S#8W9H${Nw_GQH?o9mp6_gPhMA+u=(SO-U)L2v9XX;~D~+ys^;rv08rw2oh^=^E2OQ?AvU1@#V}De(qQ5v zhAU3wR_x}P7~50jT(P&jDXKBqF}8BCNBj9Njs&th6-L_SL zD-yMx<^`puts+OH{we3^Vb=KQYD2( z_{N0DU3r2t1!^JLV)$k{#05VOKD$+U@&NPZM zK1^4})t*qB>Jt^YC0Dic==rpuYm+!rxs#X;j}NK%CS_YFd{BNR@RC-rx7defMuGkb z&9n5JC)M8QPe*mZGZ*K1;4{64iLNTJ)T|=g8a{Y(Bo~fX*$+sr6%Rf$LR~E$ezv1_ zn+U%%A`87Wnx=R7bc_A|oum@~{cHVaE-Uy$CA10IM>|kCR~r{{a1z6EdIXRpFSd(L6v&XkKJd ze)!Cod}+?NW-rTaY@7U{>ZrQ5rKEzCg95OJx69I6i-P!&KcJU0itCYTRm1FmaP^1d z>^~6-3d5P~le%zl)O!&PQEqpWf$pJd;+P3M^K*CbFdC7+%TYlS{9r3#lXZaF0VJSg=Y zLFLA(p|8w33bCnor#DQymXZ5|*~y2?$PF)x9*bDgf~@)pSCgx3yoDAe+?-o6$_pi4 zsUD33yP@akOv`}1XY)wml~~yv zp`f~>mdFLWCAsCCO`6(WpiHNdJ?Adl-?AsE!<1HTv^G$K#`wXbg`&71#AkVGk-&PJ zy&-HjLDKHD+w}UI;CE!q4w;5&wXkBFcx}~{YgVScyIi(%n9CXz^)=?X{^jZs4>K1zhF@=3-Z@gs`m&!__1CNM}Z!q0lH#v`^Y6BqHSGQspwz%1^9K zR!d3=6zs_}bH^vXEz5Pv%^i@TA_~UDJ~fp%{w7b=uftop`?|Vm?+K68dhhtv1RjPx zEzeM+Ec}tr#AQdqRn~PA>Nf>^34`H_uzmIKdsqKHA8)~9nEdmtyS(J@mFHi#?yl)H zt2k{+H_S}2G8bAqFJre%cRG7(1u3ONo`DY8F44`N{aem)X+ z>iqD_(>SDqR_5TG)tQT+L0W61lR%zGoE^;DpnGL;@fB!U)Wn;SDorX@Hx z5W9JfAZJyGW|@7XVsfUyIG?t1K=xZETlt8~NL<7^-z!}}IC@B23cc|&7XBXNQAia~ z*nMhb6}Hyma8;_$U&2VO5$ZI2w|IO)SAIYls}p{os9+sX4)^mDtMn)t-Sr##zn37hsG-E`e=Phciu_T6mJ=Z1$3jw*Uz~t@bljF))>@jG*m_F7 zAQuu-NR(XeYl^d8t+>Ued1h>$caf;($rCOVT}M4X7Gn8Aa>fnbAMTi8GoOFl--D-n zr@(EWYWksr#P#v6B9}jOA8sU=h7myb$%E?-=-q(}W=1-bX*nki!v;oW@lv#!=HUW# zScjBA|9iqlxEOU5$jgM8b0OlESF06LeQ2IjmOabtR>I$NJc=oS64cqyk6TM|IDgHZ zF^;KBljpeojk{^X&r2(=0t)QGP5BJg1*MiS4FzI5pI%J9?&KXR>?2j=bIGka5<~M0ACfAUKzUA9bHDK=*OOU1M$5uGaDQNsu0!1nEAozjU7lp`W^s5=i%X3g|xD6&P2JpQk-@O4n|w9kmz+(tRXX$TsnZwWJ?) zpRiSs?o-)1Y3!jf|LyQkx(|ry2OcFL{EuzjLejsMgfV|-?%2xGdfwvAL=n?1B}(gi z;i(hgfYoRg>sS5#(bkQ>8pe={`8x$fyW_!TXLxy)miGBcw4Asue3`*)+*$~nl>>%Z z?_Tc#$lA@OEjsB-) zU<|tGB+u1E^vh8sPvfT7h?44(Yl?$!wcnkEe$`CMV<=LXwoFb@#N@%Kb1Fc{87{Y& zOhUixWx1=}Ni3mzky_*_<9APK?yR*!;O8}E@H>x&g*=7as`eSd#bfs1G~HB8v62xL zqZVzNzPQLxV;y_QM@`>U)8S@D_Ieoz&~^F`2n?*fC3oewWe~QM!|#jbg=@T5%-30& zz09DNS$i$d5YM2m-^*}Fi<|MSf`Rh03JwQ>lr4sMT?(6k1^9rC(F+Ji)_bEI7mc?g zc|{f89=TJE91Ag0F_=*mqxvpHO|;3iN77+_YtA`Eb@nRuLnqHTTIA@9iNwAx;L^Ep zp|I{2@KZ&Zdcs}$L}DDvNshyyq-O+5^~*;QF7|+_lf1%x8k#RZO?u`>uY2zM(q);V z<1(9)u=kJvkbM{cXI?VThtw5{P^7c~r9MT4@)ofdk?<61x(rQPKGGb9 zW(?`^B2BA%dw8cnH3jD>K70af-8&acS?$udJc0fgGGwhXYtSSfshIEFIa=ci_ox0u zECE?Ncw8G-{&5~nNcFe1<9}2j<(GV&39?TewSSi)&!f!<>{_;)aR7pXpI?B@?sCJO zcQ`rW;bCWo_6chAglfATs-u!~Mu!A$Hw+9%5QjL&rTrmeHbM?rClSbIWH7pX8>+2p zB`V{NlUye>x_*R5F$drlS`_d^zu^R{UkhDgQo{3E4>9ssXXD$>pn8b~Q=}Bm!CyBR z-wo%u03O3i?vwfYR;qnK1yAyyV%rd~ysY0z9HI+P#ePVI{vxD$#nCDNBqJ4* zhzouuBlV`DT1~Y4JFx7V2=nJ)Vk~8z`-e0*z!k|=N!^5Ox0^Fe(Q>Stk$aStZG6xf zLd`gWqK(!nU}MjsD+{xqz<-WwLzt!WZtl{Ha%7d1fij+QQ?Zxv@HI}xLn%jba}b+7 zf8sh_bQ!0Oeyq^qpdnvVE;YQlSE=UTNQ@e=}JMniE-1 zhjsJhltw*OqoMP&l;!;A$`L@079ySlFUagdF(-zihV9uMpV+fH@>~<}pi$Wl4ub?6 zB+Cti5}5Firy`04rV3xip+2g4i>2BM&f=(ic^!bFeZZ8!;Wd?owEExMMlI z0Il7z+WIuAeDX!kawx&_-NYr+Em?^z*nC)QoKP73<3~~WH}UN6vo6(35En4xQ0kFVtjli- z>%f{Gqmk5qjz$8HVg%`bgmk-gu&A6VI!oco^qosORr&Zt){S+PnNGa~I>IJ38tV^Ll0i!t<{N1Op`njD}quNZ_>(pCr*H{>!Z*n zk)77g6CW8TW6LKweaJVLcGF_EEpA#qly<+oOi;$&H;-dcGL-D*kJ<`ze#d5UEEVRL z(KjDkvQJnetDB6G?#plPek`pkB85#Z#{S3gP_=OvI6tTfT zk79064*kn>U#HCiKnu_QlNQeZOA9ArN8}`kD$(YQs-%$Yfp~bTFbBq!ZTfL&!WC6x z9#0^t$CL1I#|%j6qUzQCE2YZ`O6lJHk4I*-a&gO7K)%zb0-@#sm#R-TKBB#qn=rEjg#-EhI zoaGU))q2ivNk?4VzzwnCuxsN#772CTv@Pc+(qx$<-K$Db-1v=~_2oV{1iZ^DEVvta zjGN1hg$qG)t(Bb!pl5vBUMh5qROY)}&{9%JsMIvPP{Qo5^cTO|(!crLsPg^)&F>~w z6!OdOmQ;fkHjP8Vtho0C4w?JUez%e+%16JOWV1HL=}*5KvbfP=;sJ9{x$$ALg?}tx zlNf6~7bMnnYigmSY>X9bODrq|4aFLhu(g7p5-J0wKBnPa;!!gN&JL`4fTIa{3X^|? zp=#@~H^y|?o4H~p{Y~X9%$Vto=QZJ$C5#yAxX%aY|mU_yPco2wvlRK3iSIE%zh z=Ha~}tZ>~SLLY~Re%^1pn-pMogZpWBqX+D6vG>bJGN!wo>~}A5?^1PHa_4b>yzjW5 z7WzIracAW0*>`tH8^5%3E0{du(TqP`XphTmbo>`#x-6^}+y@A7#r~53mzeCY!MjAo z#9q??)6>$B)QO=*Y=Fr^%E^?%B+@Y*MNNIooJOH?lGwt;uVZL%=%RKnh0QLH=}QhJ z<*W5lYRaN@Z&ei1Xi5~Pc8{l;e9=NLo^totaY26Bc{olUy_6(O6NP{eL)cpj9_gnH#f#DR4Y-D`3lv@bndchItapHnKeeSeYr@W>MTJDIQqsS_?y3hPt!%3?DsNjW`pOuuK=K zq?eg-owC?9%QLTQ{Y9P5I)+=xTeJASs_r1RO2{4DxpJ~p5A3?()Lee6xh#$uyJA)> ztHoX5mJ!Ie*%O9eyELC4r>hxoEKcnh=A&ZOMnKTW6kstxuwt^S{q)dR-ZV69raBfg zWbkrfh<|>#(U4Sc>*YQ1;RWW$jO2z1tifCnWV7sm;NV<4>A&)9W?#Rd3Z_hSN08u)Z!qvE;UD0PBZk z#G<;RsqV}~h|uDPOw2W|Sgy8%3y-kJp_<__-#$kRIG{R6V9}bu#jSX0+b@n7-JzYs z9i7^7a`GW&!Gtr{EC)RdOtwXKc_~XLG*7L)Cct9|qLPz3;5*vanad_aQ;|CM%-PO+ zebaF|#uPLPEa?($RRe`A0dO)BovZ`g#;EOWYK~r3R$H}UNA`wZ^xcVc<~T+XH`rs* z_8jVg#RC1Q(TkT>XgGSj$UfwL5zFmI%Kb-`=Wrs_8*7x6m-NnLi*+60u*GA_tb5rd zOZ*@7g@Odlty<0n^Iz4zRH1nJN@nAe3aV>>`@1T0x`+$Ok10qD>>_xtc@RhfQ;iGC&v|bYHaf!=6@=nf_A^L8)e~54O>deHh#`hqUZ}04(QL|3V`;<` z3y2Tfw$qJzNi!VnHae6uwuR~sw-J0Hx9NJWV#3Ow^>T~M{=T=Z)48iH>=YTy>Wfe& zUs-4x)-|T5^liT-m=)NZQ$La)8Rzh9jcyJD8Lg3VsDCQ51e5<-VBY{6?jlv972^r) z{dikh`IojbgKO+hSiPcO<+yS)9-fmMtlDhC-J^Y;ICTSi|0d6i7iK^0#Mevbkm-c@ zdvV6it}33~2M_Fg zs)cylw$i5vMjJH$<3)JfNhMPm#&uruiVqEzbkbo>!CLYL+c-zOlbvC|QZe-KxhqF# zm4W0rf)EW^XWa+uSJe}S@cGB8b&?L5L=EPR;gK=!?swM%hu^8-HDBEEmHio=Q*nG zHRh+z(qrwK`KEPD9?o9hgaEWkSG__Ly^Xszv2 z*;SiX^ZP7BB)X2T`(XJCT>b@1kaQMycK6xzU2d_c^bf9s8+qRs%USa+Ov2xKATb_0 zA5qMYtz#p}$4kg|vV@Uq3LBss0>sQfx$oNVLMKk8i@Tb7{aVEHV!E_M6=)6hyDp}@ zJ{Boeiy9x#!9-n3_Q=B#3Pm%`m?7QL<{qrd^o?>so08HQu?mS*qlG4oNue4ETapUR z6pF@rNkQ!0takXNfzd~hYFsl8Fpc3~+t z#tB0`ZS*lF*L57JH1r;ckH?xBOFsDMp2cr*HXI{2tDHZ+P)e>TG5t}2_^ab{7jkNp z)Imy-L&82Fzpn|8%x9GozaUz&FhI^S09j)24C;eyP#G)!t1Ym>*I@BZV3|^Dgxjpl zVLI)Cam#&hpMy=m>OnU&!5KMfFPgLU%6qD(Ozyjw6PNGur?p8W9!D6bHnZcI!i4F_ zA(gFcN->*<_Qb0P8yIGK-R+It*}xz~kG&Ur^S*V(Bf3gaE`2OjO(@y+g#)tPZaV`( zjaN7q`!RGwbQ8F}=PLHvqB%#}@;iAyAGVsnZkvL)UM}$~BK`R+ye9+hC>XMDX9_Kk zuvh0GkKt`yRcr`vxXp=Z?DTNsr9&45PTTK1_a(dbsH7gY!6)b@Mr!EDG2 zPvSkrolvoMlgV2JB%?*&L^QPpdm+)LjT%C&8r^qolcc7QTtkW&Ai;cF!}b}Ey= zHk$>$$YwZT@zCa9JfY(pu2W90zwU29WGk^5V1HxjY)qxt$c==-vJGq!g@;(auqHxQ z_1W9b*#IeqYY$vEII~nLi=J;eyD(pXq1nYFJE{HEVSV1;#Kb^^2z=9jCq&4;0~yE% z!kzvOC?xe0D0G%;t-hFq1KW8juVS@Ux|_I$Y44i#QdKB%xlTiS-W9_&Cpz^VrhB*jSykw8@%$rsKj5lBLB<&<`J?Mm02?9i-9cq71B`+1X;uUzk;lx zHY@6=_^D7fv*?thYiAl~>g$el@d)h8KIg}yCobv0^f~3R=l1{R57jK=6I_d4MRMgqTWM0^r%}^{^!YK$kXBeMtu|nyWC~|h zlGJ1mVwF_yhuHCKI)*{EE=5N`xj(oGyT+Xn@A|%`fGaMYCl<3<;{_8~#wzlHI=YRy z*!QuV2{sM=7uu@OvX-J1V3i1fSS43VL3F!GAhZ?tUj5rwLMr6a!<2&uL`!gxay^`= zt{})-dOrxV22%^ej(P?ML>YG7^AV`5m;$7GWq(1|09Hx;QXJCPUQm<)`FE6|+AJ$nquHnur>OXvC;=~IJQi2r6kH&VbQ^t=4a8&I(C|<$cm0>47q9z z@msINfK-j;QAl{QUkj0fROjO+@guNF%&mfS7M+4g%KOGqTg~lFAIwd1*z@No1M7cA z8OFzVenlCI{v*oprttyde^H5yzu(0Fj{Ezg5`W?T{@<&_3${*If#>%VtC>Stu?xo$ zkruwVbxzyD|6Ym52wX_wGgmJ96S}ZvrcOjx-gN?B`+1bqQYvF73a2ra)mfeP5MqYQ zO{TDSjz??UELRt#Fh91x?Jz|uX8IVanO21tG@dCVE< zdlVWos8hCeuL~0)t{kWCj=`4m3|J%{Jzok3EfNcq4{kw=#5~Dq%_wBJrPLGk(*Ivn zBC1`(L?p0DZ2u?8SqY&(0$xCJR_=xWihx<&B%!ygkSyPuIv_d={ux*$h8HVZ8H*C1 z>Mn3=Ap)yJH}STWO}}N;4L{yCe1l}W#)6vI?CibdxjC1#!QsK1Z+AU1Ph7ZU2*4E* ziW%4qV&SOCDk3}RloiU$4Ob()n!UWe9Q?atPy7}Q0~6*1{I3Vvw&1cz*3RpOqF@jQ zq;sSrPUU4C_5(n9Zj?_0h?(u-wBQ*=xSUcd&&N->@YL;9J7`pEM%mY5+PLd3qg9B@ znm^xJM(K1mH;b#}uft(hsd6|<;}#uXr#ie6SaZAeP(NdAI8XtLBZMo?@6Qgu_5JZ2 zPQj292y|1XO1w3nHsxBZMx|8RdyYYRw@nXspo`c=whvh)R_&&|g`Wd;@9zcgj}#`c zu+@sfoWX`{So;pw-x!C(VQrre2Wk72vA_>lg`4(JbG`lelBIwtU;#Ebw8S# zcc{|m2Z;j6!Bo;%GIUm}CRnh}-Q|vRHgx9jujUGv^mi4v-ci7JUYb2U8hUb8+8FG5 z0u~ITMOanVdnuzdFc3PEfY~|x#?56-We*o8E8*+Mass93?)hwBIVmq7tBlV?jd#M9*A%ih>Y0k=juZoh=AZ3@{NI342JzE>JJ6oC8J`sE4Yz znX@2<(F4zcs!jOJTp_n#YBN?HW1nPGOkvbll9P&%+$xeQS1lpXfJm6PtyhY+?!|#$ z%d4?k|DoCm4mvPa8;Lk$ZJ0U=4V}Ebd-Nuz3I1mEyTtN4bZsMRvX131-2JH}ywVZu zw<|sFidW*3U9-;X5|F8*8MZ2Sx+#}5+VqjzL?#SZ@ZC8?PX`>|+us~O$!F-jx>09-fteB~Il=+4P^n3*=HTyxpDF%?5f)`Qto4&vojlC)v-@!egGj^ch68o7V8t4N zcB5!BP0WNpSHZ?4p)tG;HBD||w1#|&beuCtaz}JnXQWcYM_<&brdZ`WWlekv{*H}0 z(Q$NrM3zUsMlDXjJZ9du2Fm+)I`Mfad&*KxOmEJLPfT0gc`TGtSR?v}8dJqIShAe1 z?=%tCkT#Quec5hzxsk!6+=MS#v~qU!?UzNF+C0ONI{;#4N;<35^8pNE+GWX(7yf(E zA0nQVizP6yCdQk+vX3YiPh=LturLIFz84bNgJMRlod7ifIr-Tpln~ zjV9TN`>E(9^WvB11`>zFDLWN*QSgGVb?tnY8lJf!UV$BgHDYHfd%Jd=#J9@Op-#5E zV4~;3cv$upQOX~kZnZA*n23kY{;F8gHY!8;6@@!*_W_LN3^n3}m4scu!(0F!JU`Er zGQ*2T?L%oQ_Z|Mf&uN)za((|;XqWs~+Wdd$NlM2Jk;miz%=1VSFB5G(dFoESkznA1 zLXbg_%zkInif=SL`28_#4%2T^yjla(MAghafvA((1CsyNMM38 zj9DG#HGnyd-LYfjGr)qVA^q4L+b1tKAj1Gcd*VIeEnJK+fFSl`v=(}WJF<}h2Uqp8h2HJ>oom zlKk*~A&7sH{5-hQl>n08YT!?t2LZjrBhKR|$uHnPNq&$ZoX4L?ejv*Sh~)S2C&>@M zc{Dz`d#*w6h%HlaiwWR7M)sNnd~mN?@E>s=X>A~!hpBsC-}PHzrLw=`JPxh|ul}(G zQ%c|u3+AtjqH#m0J1=k%z0(6>>=9+FZcd)@^OF%v61Zg!;Zzs2!oyE?^nE^Q&N|I)gnS=d=C}w+k^6~&Qh-ymv{&mh#&}YxCA0h zQHQ~B2G||AJ@s8^e<2l!b-S;X6qyiKj-q|Q;=pOxh4`BTVeS^G=_v z%?f&iP+#QRDN~Vqc_x9c^BfZ~Qc4>NL)`k#M$0W!sj>%fMY%_BPk8D$xK2tMgY;K> zKJP@=%jfY?ftur5yeMK1*dNSv#YqCp;TZ<+sC2I8Es$_IuwpDipZmvr+3mERD zgX*|Wh>p=dOiCEwf3q0OAd8;H@n;2DFvs9%$c9RToFyL2ay&TsIJ2|p1@1!Rj;`kt zk&}|sM>xmLtltCvx2WI#H*AQX+=B)YkpE3Y1@ONWefjNwlfax6!g6yKRkAehAjFfK z{?G%x8lOC$L=g)Sk4+YxpNE6298l_;Uc{wDZAe2x4M}nPMA#;a>y0VSWojZ%S2?=C z0+gXPCe>*m#KRb}t=S>g*23)g_LDuEVyW4AltYeG(ph-($UDp_6ZzB$r{Md}hN~!& z+_QwQM9!qKi`WMeA=7oZO>e*dC2Wo+N%oB!=otPHkX=eh@PC}pmLT?(l1RVQ_L1)X z34=XbIOAG2)9M2v9R0K&8CoE{gaQahVdoG3a=}%kbmOEJmX~%gqNX0uZU16nXXr%{ z)R1uzTwww%Y+pXNJe4Um+Ax_`NF0ogDWuy|xMOg{PWoVv*&2ZJY zg`VUbHFD8C8a@`hJi3!w?R4;pipAA7rpDG@cf#s9s>}krtJo0Jqsik1!=6jcs@Gs^ z4QpR9`$o1RX3lT{$A{9t=%$L?Ye`eEeMK#fNsvvk{5eS#ZRJe0p*lR~wXc^axZ;I! zv(C}pQ~7;$a4@H*uGdsYxXLz$1?{eEJhBfwX^l_ykPrYEb{zo2p7{fY?XeD3(kcGA z8QFH%m+6bnY^uXLoST9wLZTMtEX@tbd(>PDc#mM*W=%<0MzrS}^clJnsmrXKd?(76 zK!l^*MptAI;VA6!N#p_uM_OQ@C($dF5=1zHd?Xw}fSyErtYw{u%E59dR-0gD@Lu5$ z9)*fE1-d35y2#hSTzLF_w{(;QW#=sVReSq|s9_&r*amtZHpvf>6L!I+LPzwL{=|g_5T^u~0j<_~#S>5G{ z6^E6YatDbz?4}LH3k(*O86=yLC8>Mh5>1g|^*P}&oWq877}Gi5s}^Az(g+AC5`tVa z`jw`r2gpJ#;tj6e+FwZQj8dy(xnRV13=pH|S(9b_V33xPSxVcBVwBN~4^JeC_a~uJ z2`!zJAX!=#w`-Hl*wV)Miq&({_JxPORqk9ZF%p3`__je$)ljPKb!S%PaW?ak{in!w zo9=95*6|GFB1`mdM4c(-B4KeZ^?`K4HuDMfZ#JgMF$%j&=u_s2p(^eAhZW+@i2*X0ib~!T6`M7xmvhQE%%?xvH96?}9;9^nHPF zuWM%^H< z0R5$VQ{N!S$Vp#|ea)c$#daLWh26nA%6KvkM!XcY#)E9+G}AZDQe*=5p>CrtelvI} z?A~~7&*nVOL@z=Jw~;i?{C8jxJ*>PSHC0+I%v+~t*DWX4|KdGiItZ5f#|t?bzCSvS zzY{64mSDcYj6bg~NqQ0D^&=flYK zKKh-3o4z--o#o3fQqOIy#~i)Utgb}GSnmfCB+W>#C)w={TO2F@Yt7xW(v5Ym))bY5Go5bF6?;XOs(yXF*eCR3mH2d|+ zHWsq!${S6ih->_Qz`?2M6}xt@9;l2L01G*?d{vkja}j`YGsxjTRsOU21zGzzhgB%t z%gXf9bcP(V4LDO#v@+N*iCBxm^g%Au9YNpD)`}w!rPL0KY(+XH5FBhag_Hll!$p+? zj{VVPibD;!O!uF~syESsEl2z)X0jSMxV2|SD-S4%B|3kZ+i6Csm)my+m`o4RoU-(E z@@ee9Z661fVy5!tu~Pag5$}04f#-$>tYdM7r;g#lKnmz}slV(MPcm{2OD)l4;g zo9ac1o@JALAOarxkM26YvrKCrxUBdA%8e<%EO37Vc<3cn(bfTs^}Vuc5@$vwEVF*;GCPAm=?$i7vGuyR%9%z+39D0s+bez#wD|o!=OZlEDvNdJu592$N@~I-+lts zwR+4UTJ2L#t`uLr_R*``nEOj5HjXnMsCeZAmAIxt<0oEA1l->MsEVeu<_ewwZz))^ zCl2?NIXrb?redUgJFuX zPv?zOy`*)2g5U3KI9p7^|Lm_T0fx&7)eZ^FS_5a2PBYx@mp{Gtj`oKP*$9517|0{t zfB6Q%NYw%=>^+8NwaaMb0s#Ml|Eza4eE6n!M|83S^ekF}p2Y<)k?V{<8sH``kM@OD zI{^NroK^g-;f6W0ip_@zL&_;P<-{ZI=W7z|djdi50Il zfRDK;BK)Z{^HO(?0m{~gGE^}_R zDvlt_!M67D2sEtSgt~M?)?Pe2X6s-zq0iBxZ{p!aw-{+gw3K@66OGRCWQT{JC7HU)W1@8p7HfQo+Z+GKlhPQ5gnwMd5v(kgU%A!HsNW7 zfFJ4<#q>7&?yUy(#hX+v5_}bF`jWB>6yk5ztPC)Tp>|S60{5|={9I0fCb4bMa_Zw6 z+85%-`&htoiurYi#bSoi({bcBB&EW6!B#qc^Td-NuC4HL_R_=`ijHv%Xq61ev3_hG zPq;rT;Slh^7e($#{rOouUgLTEKp*`2Ky&Mqu+KuyCTiE6h8NN(=JXA}_c*b>Yp? zbbX}UgMCui-afzVCuc*4sz8Hwvw$Xvl;kH-niR+Cli1WUWzLl3A(grLun8{j(hIqn z6?ySVkzZTR507bLVZx*F&VFP!?fs8i>^25RNzHcT8u!vzTDI2YHWi#A(&>|$k5}cE z>)2e(5nclo8JCC8ZTp?0Hs+qE+BxIUVw767P}Vn$TiV#M9&n#iZfRMWIg!Ot(9?zK zm=eJ(j3aKFhB29sJ-rc-H(MVxcLQ=Um4Q67z$=|N4 zePEMa;ohou$F0VUJ(pXwzr2^`4$NLL51P#wg5EdDL%OpPWG=+#ND{XdD@2jtEP|uD z+gMRw;W z)hgR8K?Fa11)~1(vIotRE9Q_%h0r)07k_L=)-QB{I9IYTbrZ&c&Ql6chfLqKTU+Gg zc4miaA$VqN$2Zh5SI~l)a)@|kviM!>6Grn9$zrG+`RVw^Z{;J;bQz{Mc?SIu>0j)C ztS^nFsTpMC!Vni+ifiRsM3;{Bg@I-wQ{GZEOSZ%0k_Bu03R%Ip+b&mqLep9$%b!4A zCCiuSTy+8?C~G=tQ+dMenVy@EQ5Z|&f48ISJa^Gvm<-*BFq(q zZSsU({KI!FvGaJ(fyOb)w$8VmAqfMYuiBB-Ng&iME;JqzYSnN4qL1M3+F||k#$4r( z#{9qNBj1D*Nrg13pbJRDUAfB#9(m{d>VMKlbgF8hpnd;x>gXr$oWXqHMBM)`ymMSA z8Q%anu`KKE^p-M9$~ zxE2~!>J3~AB@JJu{oB6$m5``0l+mzf^4FdO#;TuufKT!;ML-ZS^;Zy4=&cA4MeJz} z1@qsGI1#cR45vE-pu7QqRRbG-?R>;1_?J|div&n@3CJ)vKqmG==mN7pQRFDsY@zdk5grJ#Yiy z4)DUvPmj_cKS?C9HvME~!=msgLKYZwYXu z@#ncv1HIUg=fJtp@)llxU9`(oNhR3ELzwK`UkrbpGB&CrKL8QC8yGy!JY5~&SEsaPw zNF$AOOLw;*^4ts5?f%5~I%l8fr?viodChyi=N#iTE<#pS%J-cij$ISuqULd&k@AmAYdwcdruJ1+Y-e2$V(6(j`bMaX;=s)w{9{HBG%LuaU z;?2I4UBj6Z5{6a)0tQ?`^Zuljyh;JF&L}`|tpcE_w7SoK12mPHqj!t5*@H(8tZ}6> zRpvq_4V494MojBKaP8))->h9@PuX*P2FEi@@a9bW6|gz;R(cO?&Y^t*O>RRn2ha5tDMma*{b$LU7p;iIs1D>3pJAyXNk&|pO|_kVm}}tslRk!)H1*Q;^c)0Bk&Ln;1GM3p4~DF7Qd+5NO< z|Noa<%Rvu_DlhlDTU}=#Yc$T2lF!0&H9GeS{5`pL1xn;$lzSRp67YR4NScpGZ`f<8 z1Kx-Lsr*Xu;{>)g-lVe-0d=Y#Kq@!6+u`z5PyzC_F9$eV+Mnyc!U6W|gq+{7K*TZ)(0l{#ZMhn&12< zH9r-g=BoqL{It*gS;gPBTt0OjcGcG1&x-AZ=`WzVce%W6*aSPEbZ*j67IHX{W-|Yt z=S|AGm}#a3H?-}{rL9;&PCbu{fM~(IgB_<-@%YDGTO`n_Zu;mGz$ep9*#7PSZuSha z^@XOLov@xV(U$O3_{;*F3iu1nqn6fcWoQU|p?e}srqW*UUwb;rPXFYm^s=XNw6{XW zWh=`FN^5+t7-`(gKpPoXZF%{nFlW$7PrEB7BC&1 zQfTu^@b&Zy#cl}tD;6`WHSB63^e#m?e2EI+r(o;YaW`)iZg=YZCF{B)`KWU&)&b&P zB;>PZ(eJ~tuLuT1t85p0%L8>pzk7Pp59WYHf7{tLq{LXCMF4ByF`3PR4nR>a3Qrjf$ zogX*6B#pQ%wcN1uqaBLx^S03`CCuH*ew-KhT=ezE@0t6mlM4EWq7~v=MO}xUW{{4Bw{XBQ&nPXc zeU=}diuI{CwE#)Ka8-JxAy!o(q*PPo8oFdDdJa0P@tzx0FXXf~FVv=G7@}T-Cw^x* zXsfI)hUYlDo!_o%MZ5nEQNuc>3U@rw@|B86c`Ih!YkDQP+w!W?lIS(2klb89wTA@45VVt5L4NqJB%lj0DqB!tL3 zr(VGvecAaCEoPnB_&R0Unt9gBxWSj<;pvC@EM}Q7nu#2RUJ{y92^5{4OI+t$M|*B~ z)hQkbcOqv8SdLRz;&#_QwpgD5vEya479M`uaGXm9KHugHLsMDhyy#pEd+{DTNC$f5 z157-82a!wLl%%|)nEp!!CU?mi4q^80I`)0O85}!aPt5N4uTz;KxD!jKwr>|oalYtU z79(SlXFS7^SDC5}j)mko_Z!FvXx%R7VuO&I&Bu5`K8KQ>H7gBYG9j!qcAUn@?yTQw zUifvulLDvtXs!7Hb+xiIa&m5Yf4}0e>eN2VoImb`gRpYqhE4MM6BoC6nofOP{z;dn zr@E)N8~dr9%2$u3K@^tVNLRSxuXKGA45O4yh9z-JIhFh)#05z%%B-R33j8h~e5s>W zH#?%?vEgS3w_5+IFo69E(Ra$vQ#4Y@>G^Pg*6GlpbHk+o`n2FJT|qPTdnK|U4P-q6 zBzr&U?mi*i8N!i=VX;nS;;RIixAZj=QjS&oh08$^`XZuX@?{2!3mh_4oe)Rzj(QAf z8;>32ETGT_qLAvvq^SLu90H!rYx(0xojvS{j&Y27E^|~&1=HC#vuCtNfqHRr-eCK- z5_afK1TF2GxQSwI#_^iEchygQvGN;(o2vyGyhV2j*Wm>5Tjh?uydA1%1y0>jy5}A_ z+sAo}lKcpUS!e_FeDqzdIH`b;sRX%4IM~2V6TCs@EmYKD`Kix=DCuUQLP~~%f z(t1cNN(kBXOv?|7od^KPRXNV~dJBG2}!y#7Cq5TMiUq7CoYX$N8gYN#4o~hARV;g@qcYUcYwnu#X zem*Ih$z>)!^Yb}V?vLwVEHXLSS#_~NGkzlPKfu-J3XyV4Kx1)AP?>8w@oeQ=dFv(9 z%6s{0h0ru59OJ4tTTV8)VM8m*P5zVK36#SCIZ44fb-l{rE@yY85k2up|8y^HQJwzx zxZ6Od?}DS>O^7;qteYuP*6rRILluQCxUk@@4`2PEg9m>MlqufCFaoN!f0QUCEB{MG z6g~SdU_pMW;R()4VYq-`<=AaPGKr<9sApbiHvP&4p(#>h$BM5pf)EJb2JrWDDVqua zyN18BEqkYWba5FRTngGjNXZn{xq68JFeZVL>HUS_)A5%Ay}jv7*a4Z(u#JnDo)Fb< zJVqIJ&6W}`!DVy3juDa9d6t#g{281m1sLGE8qyFkE<91DV=T9nc9lDZgh)^6_t3OB z6~}o!f7JFJcGY{TaA!{7VAAEeb-B-3pS09iP)B(a-KHrm^Ao@f43qu|x3qjb_6k&O zU*I=tRV7%tW3HIXh>nff1;8!4+9y`;;g*+KQ~=!a5jar_M~89}%{z*&fb--&QEDnQ zX<4xAjx0C>kOeOsrY7{H1IR(4K>*y6y6Jc);T~?OQUfR}7apr4;SyjR<=(+9eU(K; zRvzuC2sH`4ZYld>p)40^pX`4(}+yaLb)va7zL(+)}N+P!@n&o`SQ_{Bhpl z^tMnSS^}4kX>Yg+msbGXlH#o=0Jp4{-8C?ek$s;gFR6-Oi|SKir&yN28egjU9)Mf= z$I25G$W3XOyJ5AbJ+>4`2y&(E0HX!N0l1|E7%f=jiJd(q&_)Qzp;l~tv|6d_(q*k8 zj$@iFR*CwXQfV1uCEgIVjh3DM=)IC}Kl{*KvhlBHc?!tJ9x3upE&*XjTbP!^KpifbF1iS0DQ~FF+JMMjO_gE_XZ-}^a9(j zF8K+W$U@twe9tLfYl6n>59g6@PU7&`T#F>cs|hPzFJc1tdBTOHyij;R;ykcCCm|OE zD5CqW)}|x+@OkD={9gOjkQ*c1azJMM$%+X;bn8`}!*I-Z067A)@eu@j!`wwb2+{vQ z=#$BNcjE9Hr^N^$QR=t(txNO_;Cjc8R9&Tp;oS+%^?}?-^S|XrVp&~)R|cbH-KEQQ zBTkw+@4{rkiBc0H^(d$9)$Sx&dOEY`X@3&kz-!c-YOefU5incO7P~iCI%P>0sZXxx znZQCESm7{x@X&#Ey;S7q8kGjTMm>jVq)DN;SpIX3>J2Cy?nh%Nu)^VPjT)nle>WOy z{IN#Ohpn*<07R8x5MYG^0Cam2Bz6aMQzcRgg`;kezzJ5Z`;{m)g+sy#=Ps2CPP`EOMqGFJs_*q=qHw)X+BAbHubc zJWhsJeD6w3N{Z*#)rF%ySXP_ys+-mVOKnxHzl^e!vOK|tEWE}L8-7NQx>Po*EJGJz zA+C(lK&*=#=RnkyqZrF!C(!RzrG+^E&1=RYF;nSnXsbq+_=%91q`_$NC|cvO?=j|^ z-}kY1J|NUnWj<45u{%<$iWv`%OX@QdP9e1AnZ-+I9OIZkAQR>dQsb9B4xAcnin z3g0KkF4yAMaG>NYqR&5SRR7%hj81@IwZrZ62&7y)7Tw3_}i{YQi zm9mi7eeUjlIf*!JlCM?C_i)K7ulA#dDc`Xb=wxBb`=khCG0!ySU?Jp&IFqxW zqzWq2s9uE(a=r6$Znl1}% zINK*Dh1MN3JcfY(h^LVVI7IS?TAwW3x&*YYek>O)zkKdTjM#S>2<6cq=Zoqzwi=JU zrM0<*hQXK!t3>8!QA^nN3>#@l0rB%CtsfpX?2>(oE}vfWVim)*Q?wQPv=f4k*rxUi zXm=I@g#msK$q>2y`gCVj^>l;kYk#oN5VfgX zp1urI(D7Foo1~Josb46X3^0M8hxlTR#_V8{B@mnK9ltdK+A^NHXiJ27 z;aQ^V-?>0TzZMygbp2xu?SYn;K}MIM>H#@=EydqD#W(g6xJM7#xx-V$1#78Q1`z21nWgXGxrVV=scD8r{OZUpsyHatByWY;KN5SDEZ^bO&ru{XQu z-I#t@!`#BUPJF2#o@jzJ!Vp85z$y)Mdd{ER)W@f5g=`kp^6rHy=L|uHNkhA%0>-2k zjZ0g=u3S`ipry|y0aj-9)Klwxr`^sI5^txg$!UoN{K_FX^CuWxTZhQ??$E^P`7314 zD7UHFJk$h3rzx$+kl4*(&gH~*{3c}7-xkBJV z4btM%J^kB8jtb~q1Et$Nqygq1NW4LrvCl3w|qX4Fs$DSk^Q&R zV5o;ln!`qxhfEs9x)ZBR617h~kplI7X|u^GfU9EMCbs95XIo-mX{Z9K;RM9L+)y-={APhy{U%9 zfzO}HWfa$B$1gn;KRj=&vi_R$Op&X-aBXa`soBK25un2}Vd`bP84~xR3U60ljc#kf zXQdF^#{6NSt6BpxrzDxJi<;Z2n&mF3g^xA+X-#Tyo2tJAWaad%z*_H8g(|DmLO(!{ zcyZ*+l~PE9aNz;SE6N7TH`^)9Pr+bEOB4eqRrL062Uhb81!r)JRY( zrlcG5Cf|sLeE`#5qJCUSZ%m>*0#qrHV!xiZK8Q*7tvAWOLM%a2X&_7t#-bi12U*^6 zEEAI_E7*-laT4kEPTl_Z0`MO?7I4GsjOE zLY=F+fr|m{zC3|=s@{A)``})t)wv}A)FD}I&hr|Ay^zPhPHp)cnj6nxe8XGq6RNf6 z@Ls*%KvcfN3ry^Z+zCe7BID%mcW7>|=G|HyXyotBVLTv=Aq;>*>*HLvx*F0}`Eq1H z_leUSTFHOWWNw$1fBbp;#R9LE@#C_cbo`t|z^i4tPk6)Q3GF57AG+3|C9fwXyA-3> zkoO3k)vK|H5Zb?Js@Sam#nTbK8a}7elWNrvT`Kpe4 zn`T&sls@m1^A*HhQcJ-pDem0uXJAWG&H?6Qr@0I3UzVg8pb{^mfYkM(f7b`I$t-#N zA4>7}HsSxNh?(~@MIX8LCYUhWEK$Q8xl(i!TJ}d?1bQKD^8fZB2Z%Ba?|I0ffGBhP zZ=y`AU!u&&d}tlR^vsb%k8bW2C=E9VXZ)q)%7l@UB(3!H;A#_{q$27bDtz z_!mGote3M%IU;6vpL6UtUX+-Gdo%QKnS{gXMVb^mR8i3%w_h5b3NM_%tBhF;uL1eL zDluSyZ4Hce`t0EG1w{vHs}78Iq6veg)u{E}6$jhn%mB30Ld!uQ8V(YGF}VQjaqPeC zaqjD|A8N++jCfZ89x{M2(RNrygt1o*o4IM(NL>W0gX^@y0d??s>A1P2c1z`(PD4pn zwf%^T_w&or9<+!e_F7Ge4OteTXLr%SIA(5Nt=|>^(ZKvNO6rO7Kcj(ze?=T|{UL{2@^tqfJBAg+)PH@Ke=A}% zBGq%=SXxynf1n?B!V6>{VWFByk_u$>K5c9GS&WbVEJj2;OB7VxHck`X=987(>7QGL zHm^q~E}88T1WpbvMk{CB_;{{((0D?i(@ex10L{($jrq}z)+z$1GYPS?dqGH{6wAWmU623Udlz??2_K%gc5Cg%XeV0^((bS=`4Y4>n6>SkZHr@}T( z`-i=(#tL1l2RkSjc2B}i@wlH1od}&Eyi|r zaaBV3Q;6NRuKfoEw!mJi5PPa3)9PVGSqKJmmeiZmz&YFo;cpbxwVZER!vLsL0M(Qu zw{$7q6xjt@A)S2M$h~7YiaghD3vdk2h^7OfEv)Kat8IC15&k-~fk#8Qx*LywtWZ~w z`K^TcVvWj&4!ZS@wTe_167N*DDjJ7|pMBdE%qCSoLy`QX=`E0%@e6eKM^Higub_gB z?|<Y~sQ7@kBToh zuT}J|&Z*;Yu(sju=G&;pN}rl(aGuh_o=mdr{So*uAE>85rw)_*d#ja8MXh4~V1AAs zQigjtTxsoR0ss^kxXOW>ZyGEjp8XECvQmZA{mnO3%efJJ^VJcF)f>3*+jH|?)S?IE zfgC_m0W-cJ!9hxq-q#r?r8twwl!;)(ZFI$YkQjxtPkAf|1E`qp$G?? z$i~f#9vWxCF=Tbi7QkehXmfa~Jd9j%wC~aIcDG9F0n`W6mzpnhT}W&VZv!WSugrLIlpZoSXHBX^JD=K}Y0WEA9n_+Bbi26u=iJ-vn~{|3g>&9VGO(84>7;*CIs- z=+zLRSXN067Ri?Ur;sDp{{LY}M8tcK0eqJeD~L9(ZGYF|($i3KpcZ9-T5KE#w*A1a zKfBmKN5r4lk<0^yfSD|G8QRwgw>AY(O?&(>dp*9c*JpMi+Qa4(Hrnu-|7U2%OMwq4 zerc{-h?*#ZVH-!o?>o`0=XXJa7&b8bp|14IKz_@~$rf?D`^pdc@ys!tW6*f5!%wV? zaONS;nLEYuEyt&EY)Pdx%10H7QMAw-~LG$ zEXyiHr1?v$iqolf&;LBM2P|Y3vr2#xM&MovBda@=4Ai25r>cA2{c{C>&UqP81VL4L z=7!RN>kHVqbKU>}cJ3&AP~W!1VjIts?2?S$LrzV5tq}&6Wkvg!EX;wai%56;Pw;yM zM)&@`k_x<6M(+5Z+*tts(*^ReTJhbK$Y>@DhA!rct0hy%iipmUul7`wz<#@vsw(s* z{8nXEmhti*(_02eHo#Z&fbpMqs_73aI6x_SPs~mo0~RtZOaIbw&Z&*5z_Mf)zHtVs zNzv)712$Hc{RY%uR2lKB=d8`Eh8_+79wcNbJXG<2=!&wxM#O*biZk>?du)r{Ldg{K z;14wGe=&LEz{>mifdB!2pDWStBq5{Sywbo)YRiJs4{c#^7AUT0&}c$vW= zZrJZrxt*BWoz|V-M{EQasyuU<0?OU?MmL~9H4}SU^?BS5~=Z`ts}_sW;@Rrz@AH_Vvi^5*c)=9-OMzfBuf_N4% zwNqgLlQ&1&PyK%5TQQq4$he5Ci#;T8l2G5NVkVFzGz@di*8>S;T77}HY;QqQrj$T_ z_nHV95D4}^c`XRMSJWua%btr-M&-SSv+yk>zSF8E#S)Zjl7VlaXYxcrVpA`enkGvJ z_@-fv^<#g$-MS04YFjr22uIeZdXoACZE1jjzxC=#gZEvil`lBd>U}HH)dB$$W2BfD zQERk%VOS^wBkorTt+VYv;?=;j;&boXe;#V3AoE{Ctu(*_{^>`j{Ie`u)MUv|-2ePS zd*0=%!5n6Wn1CMtEXD3`UMZZ+*LM+<)Etrq&>sz_qL-==Z5*&^z}ae)TT_4vIf4tb zIZzrKAj_oiU1I}Xu?gskuCJ&6=!!3#|LTf4;I6pzXIC5tx*|Ey6|2J-#{lt>TwX;kUk=?0w!uq};Fz|Ke( zuyhE9ZE3gJ&FqV0jt2cuGh3+s`gqfvRxjOrT>d}Frc>yD%BIr4(o0k7m zHhm8q_$ixy2*{@4lzM0GWz(`0;RUc@*w)jE0I;#PlNRp|EMxJ;Z_DBO;4@_kZ3N<$r&mwPbLCXUkV_x*~K7i7#>HMK`kX$XZZ0wZjRuiqSyS zAN&yz^|yyTXBFpf`bNoJXavZL`;ngu)S?hP+`qO(4E)?OKVVS&TuRfPhGYPD&wVo@ zxJE26SPI?*zgy_BE7ce6z~}gHc|Vkb1EliC$;ma4XQVIM;QT$pgy^nF+z?~k0Pb7P zsI$-$&ff}tG%l4!j9T{fI>1bl6gpHz3Ybae@605{c*-{;I2^{4fSCm4&PVAERkeO12O9l; zALNn$^flcbHAnKV$@L}>kqt9EPMwC2;ION#h(dl z?7aeHd3pyur+lr|B1Q%YVXOcbx%`=n_&6%SMP{q6Yd6T z-V`EK-pi(i%qrj*0bdjHZu$R^H*k+2L~LMcjQm#wp-3Cr5+j%u&umKMF{`I)13&bQ zrE!;oFWLF(y(~h&7!*P9yh?HqSwB2#RlL8=zqEXGCuh#R0f!y^ zFNfXkAUJlCs}TR^6M7ARU%ak-yY`+L7HZ+~EzlO@CQr7^X?5=$b^wM2?+(Kv+{m!Y z<_xYxwO^I^7F>x%V22$HxDo;Q#ht^>7p$6g|0NAcE$@F1dvWwu8SJn#xOdov{8UY| zJp()J05i#74!em3>>jfzcd*0GL>_S10jPMuVb^AG=di0O%h_YBG~1=p8(If<#Ww4e z`>wdg2}Z?7H(zAmMg1`XU2%xLD?X(ALSCuq>R&3+qwwUP+nN*Y=D)e*#=trovk1jnx9rRjO3Tnl_O)!_D1{rz~Ud(HDOL2cWObXctovH2}XSz#vq8 zb(i%gq6QWziMo(*8w0y-iAQ^5&K&J_S}x!1Z|ggKbLY3CqCQ+(HMpC>@V^wv!n_kH z%_D1`^zOfCL$;b+1IJFL6i&nKS}Yu=YMk&JvjSaF_#|SfiSg6jGDj&}`BOPe^>h`_ zq@|ztp(gNbS!G|Un>+`j-=uz7>>3&60rXqdY{cYMDiSghU66PUP>M$S1npTryP{C; zNixtC0kh{8VD_|gHRYT`5W4G%l0a8Hyyi>Rfo0uwpIwMv!{HYE)fGP!kX8;B`u2L? zXZ@A(9(3S@8JDJ1y6NfGw1Z*sYmOfExXe>ZMdMT40b7ezSJkxtrMwxA*=yIfI)bHYa>28tj7y8fgDOz^|&R z`t#kQ@=XV?8{@X5bvLWn783Lb&vLgT=t)`ZjPwp>_rUf88=o+7NGP7qBy`6!`a&u+ z`uH_lsqdXfn78Int!Fwy5v=EG_vdpj=0D}8Hz#U!z{0`vnmRYzEb!PYXf$1YjkkHg z0lIzo`q={c3M2GE+)>(th2RV5*9Z$A7op%^<}V&SNNb5^dih>AhK{%Y;mbBcA|nr? z=p$R4blF360hx;KXb2C~bp0aWpNXLd+gojqu*h^hpP_2BZzoL6Pg=Y@7~e81^@S|a zFg4@05TE}@3fVC9&}vKTa8V8yW=cv+N&CXY$&);4fXdZ9h!-qeYdF>Udcu*mfrD00 zrP5MGv)$=gi2S(X;bS=WosMpjm7pY4=&v!upGec&LEqfBK%sP_-yjSVq;rmOGw%vl}nI= zOVG18GJ+yuuQG)MoG;PYN0MCG&w}=-PmCM`rhlOHjFYIwWxO-V*A?P-=Sss7GeSKI z@ewO`=`E+bsPv0lTzpuEN{1y0*U(KnE2+F;BK6FqKTcBl)mo!m(sTS^z4WQ=vw0>`sGF~SW}~y-Kek84 z@tkE#JUzE!l1UuUeLmvy2A3*C$#EdqdTuZtK``>E(54@}G5LWiLWxqf+F+nJHN$4l ztTHFQn%#h?qxB#liOeN^u0blgY27Qb@tI&yJ$@6PEY)ur>x804F49(tU!>E)AZuw~ z*FOBkyB+L{hcL-b2+N}gxqIsNnD&+%q+x4OM*_{-U-<@XLvj?ywesu9%yCcVL|^2% zvSvZu2Bb?GX_3Am)}y_2tWMT1pnq>XlFaiAXUMQ>$MLYD^F z-27=R0?49P0>PL=I2fNUA2hBxU+2$W94$0KgN4`!7mUi}RlIDZsd9wY$SaTh%Uegh*71f>jH5Brn8(TEXbP^Rsttcx{f)m) z-{s?z?HX#Y02QV0gl{5V->$nB30Y%uH}sen#4x7W2yPd#U34uwAUkV*J~9Iq1?O&L?X45J`4soxZ^tG)aj7r z;TMT+QNmq&E_-#+CJJ}rV>|Ya`-j%p$7CURG)T;asl{^VowL-pS>xb!J;rkwou?jO zY3=%;WdFr(+$lB3abhrzU?@PD&3_B>M2d$eg3yGByWx9gGQN!9G7g*CH&4T87M&7h z&7$Ye`Gxek5EN!s*c9!s*t9o+f@&eoOBL#s*hD&2(ll8~+;pgwu#P=GTH@;v!kfNE+lNhdM zp<{1ks#=oA8r2%el{JuMVH7vI8TQ}n)hFL$u#1zkH6V!uC|X@hhl9uPY&_mkP$A?m#(2bk`9v}et)1R)q>I{2hk1N4b9E(qS!*c z#0)tB$4j{w02>a+!N)~u z4gteY6TzQKM>kn&k7Jc7U8k^g;Pj)p&HtAX9?Zdp#xPCcSH_??6xAxS8AYDt%BG^hZSBf06|a<~=0Kdg0w~Ul__1M~bQdl& zo_&_A!Q9ivFVQ`Sq|uO9%n=@c$S{y{eygxSMXxbDt~@#}Tu*rJnAluG-8m|L;KiHf zS@mT9h=gN=%nVD+Feu6iZr%mmv$lW0pIeC4{svt;@>zL0B%+i=Z-3uI;O|Chvv3S%BycKZ3aJM}KFY zPme#;ra*RE8Nrxi%(oO)5u&tsH6#55xdP{@RbTBHg|&NG?#IvrZqhN?3}u1wBoL`4 z>F~&OmG&toUu6!3xK3yDrV($XhE#pki~eVX`!QPd4;a zYiWA|>Cknz3qf&DWs|8%kkv^k@TF$(OG%g}K@fwjnOTJVwdr2-baVGJ0hKRr2(I(E zH26QzaFm94R}dCB7b@fya@7iRvW!nl$GpHc+Izy~I!KMfv#VjEVWM$|eIwue2vJz(_PIp+p+WrfgHK=I zJa}J9V*n{JM=PNUClFgoy}~Nb)D?-e5*otVxVCXn>&mbsfW3ptgj$ZuhRv_mSKTND zdW*`d3v2xX)bm`f((*)Nr&hn-sA(iavT{@Ltjl{}{d-M1qTAPE3W37STE{a{8=Sb6 zt+V>A!d1mS(IQqAUN)LA+mii5(d>MWgs(%-i>cb3;XvHH9`4p}G%AsMVrv-tDbsBiO3~%0$9HEm$y3d{)0!*hGN( zQm7P~&c|xiH0--1|4Sc&4$gQ^>vbH=N6VOYTce8V+|tod!z<5=k&2i=yL9T+)KWv^ zMGHnWU+AV-1IV0$&j|~YhAT#D3Uo({X|szb8-k6e>SIq~P|@26J}E+DVf&KBm8%#e zC{}8JIW&mscNslBrxr0Df3fKQ9$_uF+>I$!-FEUdUd9{zGGYSz=7hY-sfXD6UuNkA z(;UQ{qP%i?n2()NtxD6;Lv-I2OA@LIKcPv;r5vGZLnMsYc!2ErR;qBdDpRmLG;#-) zYFiA!FHt%+yd@i3NK%*QxC{y9i4vnU1meVKrb-R#I5HC@shQUs` z9;@g@+gr^wA!(3I9Y2`ba9L_^?toPKl*J*MD0D>~c-`WNU^&Ab&Y#j7VOpNRpfFA}kLuLkJ zJ3T8SeH%kp24V0&e&C;yu-GqdxRR9uo)WqjJ=|{jBh&U|)A4F?JV+xNh7WWY60ntW z@Uagg)?&3k$lM`skc@cLS#QR8`r-Ag z`kA><9~E|IA-Pk2e8_h0((9vryp?@=o9B`r#!}xko48PXY!J@T=j7sXu$JC2>dsf| zte+l>@1zxACiWg1$fXa9g7*i2(vEDasUfd7i-~691k8>tfB2fLN%lFpCL$zyjnvN!I$ zGN;{k83V1ARJ}(Men`5SAKQ|X-pD@qa4gZhb518nJv6UNu*LJ?+4i2?3*>GCp+?E3*-cr;6bbR8@s*5$K+mVA zrd$tkXB_8muIsf=a2pjJ5UoEYkr9G+ezYwuEs@#6W?Q>esViLc&ZW#bS}1`OSK~OZ zTk`EHbQOK1^%C9`{Ro#1v<%b!!dsrdb|dVM`9+9WqOS(}LnR-8bX!!Tb(H2A6aE3c zRM%M8M~z}^*DDOi$v!nnEbk@_Gey)YeNm~GWX0aK^Eqt^*OMRg#oL*Ye+71-{aUw{ zKRp-89Jd9L5L*%H4d;n$AqB6l#rX>uX!`B<$B;Yu{Zgrd(D28Y9;Wp#=^yZTw;SSTTQgcKRfFY*gfvlNc|E?CjFP)`M{D2y;9}6;J9m zOybS*v6FnZn;2o{n<68eDe3blBUx4H)AQc;??L99CNqoi!xY(kb0;I$!M6~9|K`(S zW9YL3%_;_HRy_aPW@T;f`1-Ytor96#{ii=wS<7Zt5!*}p<#w0E%;3NbM%UD(szP3W zwiZsd)}*l-u||C;xfD*r64}eg^k(?@c_f-7Prg5}20g5q+l3@EC69PAcbxoWnWs9w zzB8jR(&KyDqN}dPl(7g*I#Z7TSG_kvN zl5=Cl$$X<3p%c~6I8G{~AC6Gj^Q|{$E{Gs%-MoGO^kA|^sNE<5K7TgO3jL~t^0d0z zuR`@0X#xiRnCBQ@px2;SH9ac6SWviz*DNs1VtTK{=Nd6F_q9YOwUIq@q$4WPg-ek; znMiYdF!O=J&F{jyqlOxL%hwO}su){?@Eb()pjF&*1 zlvd@2j%7jA6kB1{l+J$l803F@A*5_RZtJ2mkw=|EP(=4aj!RylG_lLQmjA{RF+h1o zYjWvvjbh5zR6LjN=gx>4L+jgOA?q^w=uQk+W{T#cs%plu>@Wkp&-wS3*hL1?>$U<5 zLN=vvW7Z5F8#=)Aye-QX97}e}m-AiPsZ;Jd+@=~I`_@T`bvqhsf+RZ^u+>dEY_?o$ zwoEeLl7|uivNhzxicEp1A6AMoqc-IgYQQ_qg=nSnB$Axe=Oz6?YGvROHi5zfgBg*r zu4MaoNFXfA8GqvtvS~=*2ian9rFaXBAzt>y6huZEuU{bwVJUvbLI}V`$HSqke)71j`jFO(~ZMVfkqEvujYV z?jtU>busA(<2b_lSsz`*a9q)C^cG~Ocf>N&$W?MoZ;g+g5JNs?j7BLB-FlC)i*}{2 zzY#Il;vX2PfH{K`Hj0zx@s7GA47ya{B0yf-V5YoGslSzg-!77UdiC@P!N*Y|yn0Si zW|?~I5;rLVnH&ETcueK@w>E+u6#=JTT$;lIpYgTZu|3x&|L~nn8pY77^D`-(SSm|> zK-qxrZjm;`r<@1P2(6*WBPY4e$5*_6??^8|Z+S<6juedW55^~j->(qmdGPpjtA#pM zI?w;iV+yjYYKHCMCP^jr$V3z*8?GoF6^7+FFh9{gPOhCkluO4K`TE`E{9`FI5(n4H z=`?Te(Og3^dCN#!`#z8RdCJ#sFB@)uTukylpg8>Sj-8Rl+8%!0;8L~I(@>G@Pz*7> zD+1#qCOU0b1lk-7{7bYA0cZ*8`bd>SQEmo=y6#j#!2Bj8M5L_b;r$Fgjrvl))3uoT zQoQqNvvLatIyyQAHX=a{?X2CwbHS+gKEyBXO6`W5gX-0FQ&W@)(rH-K9YH2VLfUHU zVdQC^#$#F)+lXk>g$fgsuI;6T^bGM*B6$KeA!1FdhmR{{S)EQ@`Er8XDp@XGCoLHt zpQ?`tw3>)gj7~c?_ng7k^j$^ms5-e`QHq$FmelPHPInga;XjHq4ung5#L(9gMj6y1 z>c7N4;%=s)#M88rv?W|%$Tf=NU5E+!NI)kaUm!2Uu*XdrqzZ~zuMRdIs48^Qf;bwC zlVUeWsJ4iu^&U;eN3!2Q3^IZWH*g#su$msRX5wBwr|Y&8J1xImxUlH5y_7Cln!u%p zOZE_ecb1j}%oJ8g!Yhs*DL6%QBh*cGL;wXfvJUu1<3EJWcqDq)m zY5(r(ddK4}Ts{$h3tZ|cT@GiCbX-eC9ATZkP07rCuEtF^NApV%AMeBuijOS)xHb4q ztkjQ@wsEbOsvluJ21Tmiojp2z`SGJ1r(l0Fd^L-u!A4bKT6#0JltO-`fxJwD)0eU2 zZy4=fsJdT{Tt}x%E%%c^ulG3HFU>Ym^|l{U4~+FCJ-X`Vbd#;gL6$CHna)B_YYLH4 zst)01fDssay&21sr3AeYx2l+pR^|~#}Rm4nUClD_sm_CrOn)364$Bu zzTU8Dc937CZazdSiru#v9VJT*89W~&oI)U(IYgRQ;_{{vw8c{i9N{L`>}2JFel-G9 zD-gwBP0CsxP~8s8{60Dk_9iVR{As>kRzipPHz33HGfBjg!S~BwT6w=TOMJF9QY0*6 zMQ!DL$;o8AL8sf zeGc`REZQ8e4lhlGKAl1-CTck}30}|--Uu&#(drO-aoQLGNJ49iyPZ#&uXx;!py(I7 zF<(G=r$U(Lhr`~Mj2Sk)XG3GL7)Q3JK7(<)75*yDo%C)$^9_~__qpnZ%CdN&0W#Ee zacitg$d#Gs>+_Yf@895fE)y+p`8j`7kvl8!?T^T>EZqLROTN|;vF8Br)4{0!q)STv zyiVq*Y}um=q2ID{8Z(E$Sw2mI4HVI>ATEw_$vmZr7|$4ySOb2zawVxk545FH&>3u8dQ&at&VV6)cjdV=Ys95B z+{I_p?k1-F_8U~fh{KE!*!|eUh!AP+eh8wt!$3a~a&C$xThP_Xyu} zt1PLRRAvcR6U$Sj);VKKv|?>Nn(6~cg>kK)wDdkSjZ!`@7F#ctv{a-s7amk*#+iR7 zhs9jEKNXl0w$;vQMKUoYVvB15JqBOVsmH4uQarRE0Q8+j8QFC#+2o)gg^mtCIU1IJ%~x91>EbSiv$= zZjBsFSsE5-_yUCI4-tc*CK*{^Wne;h9`>QWue5bm$HIn&lX*_tyLo=@V|}IpvNoR% z;$zi#pA$?%z=w~AP(QzsSI2?6`^F$wf610i)U@6VkMz;Ti*#D@rnmh=m!J4OtlOAI z5FOR>kd3&%@Z+B2DYr_?`Dxbg_&TdASdFKB-YFX!v))V+h=L&l^ev!*nR?+ge?=*K z2xXNXyrCpjmCbdWT{6iyVZ>B>S<)fvQpDs+X_Tr zn&-)Ib-BGed;1~R*-GwYpV&Oh1@mMUByv`n$^svweEh1!H0R7q0Kc)Ev@}UWB_H0A zxj1Dy^Cj+k(^oKxVzF!P#oMiT8+dUlk7?E?BM#sDkktbve+#jmoBt+)jON z2fB7eQ;BHngimWfK}4XAj?8SLjuq6oxJ)8k;&zqoOI11i|EPP*pgPoSTa@7LuEE{i z-QC^Y-2=gbySr;}cY?dS!@}Jy0g|_}cke!Z`rKoE>;8CEK&|56S2fn0W7-&?24-!$ zpUsnkz`P;=FER|bg$YY;vV9=OuPg@2H#9{0k;Ne^=v~u-+r3$^+x;7;+kp2@SYUk$ zUuj{n$g5XJ&u-5v1S`-R28*~CA4Jfm(kJ^>nV5lZgp z=B`rn-n)Yorz2Ll^`h;*b7)##y(m`O5Jl~I5P`X5On;}i689Tu2Z=iVp)S)QDS0?_ z=eenOU}>w?r_!oo{d-!w(Tx2Lb>s@nEaTU>{#aLR|6j=iD=G?inkqW%`yIah5ETUQ z^l#!OxOy5jYL^Cx;74sP)1HUzNX3QrW~O`d2PTnI!}(o#?6ITPx45>5Oo|M1jfHzD zZ0?C3;AJ=X^}LYIEc}zE>0t}bknet4Qk)d}+lx=LX|cGtA83n`jOLu=r;Hay z0r4kzn+BNg#5z1kmMR;eJ~k^wm{^4<-B!Z*6LlYGXTut;B%CMr?6Se2M_u(t-OY>% zA0OwYr6==RsNha97mX|HX7{RG=x^q{*-ZMEbyk+&#lFS<@JRa^LHMqY_{tFW$<`j^ zJ2A<(;88>AUmi96sCqFAPB8&j&e1-zms~_x&|&KlKYfI&a_|imZ$2&3g7!rWS;wNu z&cf#<73RoN6sY-d%Yb{plpjvBAjuSBKfzGJ;LRykG8Qs(_C)x@=w0{_q9uTw6_Vq7 z&axUZhH&p-E_&5+%_eh}%mMeH6bnisX@N|alc zvEmCVl@aju`(ze3qcJ0rb}lFHWn6M5DzJpB=&l=2s}fH;1N_l&HqSX9Cl{`f>Z|EO zJsB?%{&etB;2I_Gx$>rc@{kpIP!jP-74{(Mj?T_SaRbzt_!Icl*mNc;CPCG%d&rO4 zPhFU8EoS|vLmqv$v-fu_D-$gzSXz8+5t!rs`?6etd;$d_%c$!#?>`}{UzRPuP2G3O z;}ebiJgj-Yta&ey+z_m%8T51u{q`(O_xLe&50>W=KPb18VekVM2@3g!>`ChbQ)-G+ zqLfMG!X2u@cANyWFLqftPWw8%dV?xb1pJ{}>Kq}MU_OlC{0pVqt|iGGT+W4|wV?mK zvYZz>np#i|h0RL%fj(F5$uYXEoFUSNJ<)S;i!^U0aXLNprZ(GjHZCRLZqr#H?Ymz~@&~+r~7l6&U)*e^}4> z-S9<{$RQ;I&P@)0Rm=aj;j1aCDF3&)iK_i?MF4*WwX5ND)y=4dimcy)0Fc>4gLLEg zr7%5Yli$CK$aXi{%2N-1uY5p@Ao|0Yq`ibAJid;N|M}s;JNJJ1=a2V&$^e$9hV%h_ z^DAms!wmaaC|9r10#|gdNPP0pN!HV`n*ic!ECuW)(VYgIRNVQ-orh^14<|Yu2Jt(D zZ}gjJC{mC3P|Y_*7c9wm{=3*^g_hES=&`0yKr87c8VO2dOOJ`x>6nf?n*%?tPp=*0 zb%mS?;)d8YH~2+3KsS-EUqQFw^u~Wmm%JhM*3}yFX)mTnvQ~{~^Pl21-_O=O@(}Qr zX9A^C$Uo3Hk^qe%W#*F&EBq`_Pfuhwe&WmQoV#2w(eZd#0gt4|W7T*je2i7_)=GEa z);;tk8sEz{`5|VEKX9AhjbG3-0)+sY-S5py4E^y>XGPdb25wFYlT6B|g}mp^LIbVB zU>@IhVp1%P;?#7aG+0x!Ng6W-p_^G5zrux^& z8rg80VVzcpP^!-Dfn4x%Q|nP=m7q}x4{-$Znvrq#k|{xF0FNJAv~-~v{QAm z7VZ#o6a1BW!sZEQFix0m;U0+uUALX#oVL|1FPGC#N4g}r5hB+T7O4srEjR@&KSBOI z2Q1D1u}Au^<4)?gXvTmco}ShX^yxMa)NsF_NgGvhw^`dJ5&$W z^Z`F}LaKYE412J+qnp(L>yM84M){-h{>1z^giKZzKa+(89|-#D)Y5XjHh3K)cSAUN z(Z`nFF|V`lguWhgm4^|T1C=PA!B%+o`6Yi4d+MWTxoOQ)>s|)rMU`IbX|W%wkG(p* zT($MrnJmwE<>?Y!wQG>V7awb=K}ay3C_O3C9DW7~^}D|tD;!qKHs+r`livAi5K_2q z+bXV9k3qH|2dcI$hClErxtREy%IhS>{9Ib<%WvG_diB?xM9zAIV2!r`acAMLf|n7x z1E*6+QMC3`^{OVwvOb`Sh1=XCS=)3qcfI4iW0UbxoTmv{|CEWZ`=S_|hE>Ucz0#M;bc?k$$lRu{2#ar^{=7* z8}8(Qxa>Vegx7RzzvF6V!Y?j$pvW?lMrpLq84^XCZfX|PMS_*%lK;6LaM`Z@%1mezi z7t;aFC-_qiiRVdAl&^C=@9ja8-VY$|Vns$sSr-yB>?O*p|Di$idmC+k_(9-bhMl6Y z#9y$}2ZlRr|LOAV80NAzq%u`bcb(p9$QHOEIz$3#v^|FO`yWC`k8;bID&hBYU1pPs&j2VNy`4*27IO3Yu0A4I{W%v}5xkbIoW>Vi& za$$i2C>Fm3Q1*EfjoWMZzSnrpCHGZWc~B)*zS7TeqXo{-IL|^0eq|7?xPq#2XYh%= z69sgz)Sc8NtG28Mw#Ccuv^UwTS0+9K4$3u*wb;*(3mL0oZ}cirAje&4JAmPiC;2@| z;X6?PptsAXp`4k(ay7isXT0@mT0zy*x;>7X9l{t}5=aUs%19kDxpjH%qCjJW+gk~_ zVA%L`2mTCpsvgdI?1RXXhK}XXq@oS!!i}%6?6Ml$#^>>^g&R7|ge8iysTz)R;CZ!f z>rU!x$-7h-rim3n=&@!Fx~MtixN;*NWFZE{;`3)tjm$uP6>D~#vB}~)=&@|6hVGsd zs$;dbF%4{knTH`c+eiUIyWoXu)-VXOlj9D^(lk+zh}>~E76N+s-kv1ZFyIK)4HN>K z$|R%f0yzY)O}Y$obO8nfH@|-;O$G{c zI;4)}%?j5|sWIsKAdKjoP)x%^u@P!fgDs(TV$u5?9EBd-SGx=aoMW6+E^$|{UdULT zc!~@_(LmY31?3YnGm8o{3tbeO*MAtR{)U}!uSx8`oMjb-|JqLYdzS5BK0<%qb2}?l zfQw!VU?kGQ4CApEVH?lRbF{ATY*V5g>sx_9LPjS)!_V)Rd)(Fh z&HvX6On%T7-I0@SChz=aiiPe-H}~d>@yQ=2Gt6dBA&iB7p-swM7PGk!u@iNR$UUze zo;IBTlvZH0;|#*Q#=i$1v~rb;6N#r4%tMRJ@B#QG!BL+1IN45_zNoTq5DU6r_Hwf# zm1t644`c;dD&1m5jEq|DlvWpWTwd5~cC-w6+ zJhF}eQ?8G}~p8a7q^4x&nKUM9|VNy^qSa+$_kw3^+AvYD><6!gKw+7!fI?}9wR zfVzH)m=0yZ8RPt`KEaAp&Me-6Eqc4~v;1ac6#Yn&>@n*Oa5ECNn;=7*Cu6Nt#Qy!C zCS(F_w*~(f;qGth*(ra+-BtPK?{J6pN4PW6Mc@()*T$zQg;7TP-(=Y**7Om5`zvc# z!z_YWsC%zbW0wPNSbU(W1nXhNO+2yrks@|9Ru3so>iKw*qmQLL4t|tH7)g7_4r&e> z3e`J4RLo7$8B6k+|E^A1;W3pUdJQdD6rwD*c_l$O>)Jz(Yh`ISjW^LYAv+DQ?0r{z z__BnOYs=m*wf+JZ%nv8B!V(}c^n2d?>oFW5R^fH`r>A*GB!m&FSpx%=`bxwH69?qYtE zJ3bK>%0#&*C83IoamNn>=N~o~7LL8A zbzje)OY@bnI4PMe$=K~{7wHz-6}hgl7xw}dYc=%`uR4Sz|2%HG zkD`Jr7);Ih4YChvrAZZ5Kp~TyY;L_j$X%}x%EZ4TcVvH(yQAMlg=;>>a_FDrt}uzw z#63~N<}Y$50VH=hKyn8~-2u|5w29w~jm1l%A|GXsU>uPik+nK|nc4PbBV?OwCx4Wn z<9g3P@4|tvU5(+L9!2qd_I7kqWo)vA?cZhD->?&ALAv{wv#gTvU)F~IoMk)yt)>Wz zE&d(tqKW>;X*RkWm}V6-U+4MaEhI+_Nrc>Edfj?@!N zUt}&>qohU*b*_%3!2LBxOhd(IV(3O5N#`(CEZ3;yY)CiYeT*ln;n;uEyQCX@%=jb< z#;F>%-|9KKtp@5p4*g0*;pU1F2a+ZfA`5uH4o9yfh#kdY9=HA~W>sl3GSqO0anPhw zca8}F*-nhWVm9ipV%GlT;kB44j_zGgv-iMdlwn@=ivmT_(1%q|7nL>{4p~a2kWkb= zi`md~H<{nXtdvy5--}t-{6C8dAI`d}L`Ea?L=7Lkb82h;tiOs1X?i&84v_9Yi&iquBOSO`fcx4XapVsMsI#a@DZTsyBw=6?hAQWSlh`k#ioX7Btd zQF{+A!l`}cu(5<=DkpTDdB)_je$mk63_)`ygV$Iytr}Xzp6eV=b0@k?g2;n2e_1yL z@%#r@e763$uR!sp*Ff8xh}@z#rM4P)Iv%>iq2;Bf3!<=$1FiBnZ}d+0)9=!&vT z{YmcV#H4Z0Xq#v3NV?zW6Z1q5ef480;bm*!?InE*Y-p<+O^zs=6Rcml^T};#GA{)W zudKZ=qeg9#7A!Qg+(UCJsy7_R-{<{{Md6s65C;~1qmBjaQ2lR3MbbAs+NoZ`iYDCO zP$#P zG6Y~nW`SYvo3N8~|5a2_{4OdS033f76=7GMZCL-VsIdCavTTU`N2W30y7LP1ztFn- zx63MxQ=s}Y`Y--@k9nph@>x)Na|~!|WHaFQv3%Bipin)GKJt(?3j&z63ME>8eh_Wc zD=3Y_?iD2fpPrC^B-sBU?#^o`Ys@TBf%ZM#`+Dp7>iX*WDDU&ktt zgWx{s4Z@)sz#HKhBsx(CaP$};<`Xd9&(OZz)BNh90Jy_AO0|&yXa?p@!ETfIWePig z3GE#S(Gi}@3@T70n?)023s&cJj^WcC4MRb{nd!*)h`sikR4btRPE#I@ING#Od7oVIL~tPe6pD z)PcrvOAy+z<)gs)%<>|F2ZdwP0d$zm9e&LADCQFQiX-jLR_XkDN6pS#j>{vsF^GGg zY+$sCIfIumYTcZ^d|#S5W+f4l8lJmNh{L+*Y|oaL8~t#npX?zzFfeeCl~d5}3WLC% zLyR7&@ciNidmJx+*@ZJva%Wx0R7W-N)}$eY^CP6<*cD!7ZZxsaax|D2j->3EbWU0| z3Ug$btw zRv3p*DR#H&yw3FEh+B=;CATQ2^b0QDibmZ8)8g3ALT+WY2zAwwFY!JuUSowRzwUFz z$mQ7GkLq}gCBG%uQ7b&euGs}r!hZ=e z&htE3_*#*fgr-BL4V#|Y0)L1oZ!_GMt13?~-@%qxY_LU@3_Rzdo48_0(bM6b$*J_> zsn%${I!^PJYBw4i5Lca%XcOnlhv63$iGsxG@?Q_$T9|uARTYviBN(!ox!a>OAu(iA z(Wzw^uOO*!1;#txx+LR)i<;8{`9zN5+U%;)^U>%-GW2vMchbG1_?z5l;G8`g=@#XC zA<2f2y6|O?Ztr79pP(`h=Pk3SYV#EQxkYmIgPmZfeOO)UNS-e3KH8`8I%^NnP6@cu zf>JrzkZ9c(x#8m%kztgFi5FBuX17U1WA-|MW~a!+R9z?CegYiBeY{Y9*GZvVpnK$j z(T>V~7QrB`=P^TjqT#S-_{0k#DT{wE436O5$ARVc7M0NHFeB=rUSs#f^^H3j2hEeB zLQ6rm1rID$)1|HwnLG{wYRXDU3isJ@W@*Q-lBDF_w)pdMw~LBn%I_zq#hK1N+<|Gf z0j;uMF_q2UP2r)kbtvZMKONbm^Z2nk7KC~SVKf^MUS%=0mC@|(%d}DG> z_bPsIXT$U7${}eEm-L9oyU0w5v-6G&5ykBXZAn8ee1VE`0C3yd)ABV6wF8WaGL&!1DeZk{7>z#Dol`*ZW2i%ot?U;_6_s%-+ zB0y*=D-hoq31r`oSfbLwD5};}M+EtNM z=!x2PR=Z>s-BHNyPZ7dCqeO|o5{a=Q8guW7=&gdf3^pg>zJ{P&t|}U2QF`b%-NRrM ziUDY-+@9uWzVN2*jJ(n%^Tlx@p#97LS2d$VxSy$f!>rs#an1q~--8`-Q** znFCI&7t5~7g1$}550Q4tH;Wx8mZ1*q=o9co6?&Uw!ltw?yli04HzZU+H7TXS z18aKKb%~%yG3{w;b3@%Ty*?7XlKC!)rgH{UPwrs~0zrbh82e&2^x>8f>QA)e0*(Ei z!OK|;6S(%}Actqn@UWIh-1&YSR!MM+oL^Fw%3H0w_eJbol+N)NjlX)qxd&{&&?q4} z+T07hXDoNtm^ru<&W7wK_fPg6OFywGtg`Q2MyfB}e4FQCucXaI!JnDGDpn;5CLBlm zaprP?JNORP|2>N7S8iXxu~>B*f)Ygk$>)DRU$7xH#$@^ztzxwPK}60`as9W_H7$WV z{4wO2QHP+y7Hm0te76=GMT0f42E{^dY{l|9t?Bci{&FI)^b~2v`1IkaAT`I=8rMAD z2>Li%fbV$Z^z<_C+c$r(audN|@ju0qU>)VVbVJMw%?j-b`{M-?d!l23QrD+JeJ|K; zLB{RGe$E1IHc@p$8~iFRG5G_&SbWK6JeV;jl^3jPc)}-ZX`gn-KknsHiex3yZ)I*F zd{40g%69ny@2AuaGxHP?akh1zujkQ#Zi-W1IT^mkZ}4CFda%NlT%YbVCbY#WyesS` z_V=FI$R#e)zpeBtH35x1!8-lXB7Tdz0t$+hGCW9_suUiX`4$H_4n5bQT+2@%I!JrO zS#Dk_JaAI^P`GPuNY_##8%#h5qU_7|4O*^>FHF?$S&11J=U6fmx z&xr`E*^};(7Qek>vi|al0sEU*jIxCceO#}SYQdCA;9d~DJ z_v|kWVgWHI^hXVMNH6gcq^_d2msE6st1uT=Ge ze=ai4y5qeJ=3aF3Swh)KhJWjc&<`b7q#D8KNz||4rq!@s$Iq}}g67?mlbGmn-+2A) zSA^uYx@&po5!dS>S-Hb`K~yiE#O*CDLmKTJivyp>f0#V{?ule|GFJUxVDRrs zApbv&gSuhx*VV6{r!Xngbrwr_X`eD!M`N`|H5E|7*K9K z@@7`KT#gq7s2cYJoAB)4Ft~-XLxS_-2b8&!%?-!bd`SR`Tx-|MEF6up1q-jDSgJ6- zPTOD8`eNensTeDM>4Jp_&B>s36Icpe$~>AyV?hrC?DpVUa%C1B7H`FgY)2$6V_t6D zc77m;;a+!)(OH>U&Rjou5#3I5i1Hl^#Zfro5od)eMhlitf3TPhE^a;gV7|^eM5n(* z#afaoX(U*o)r&d=Z~hSpjMhs|-NUY*C09u!pp1DpJ$pQhK~q92oeaIatQ^MHR8vk# zJ(i|a`#)f?CA6Dx12tXRwC3!$=D#IS^B?rEb9HrB>9ceLE z4;GfcpBDZ(cIAC^ToHhTgd~OZ@PO3tfaH*Xtl52=FFa6doy=B~fJ9Nm+GimpZ7m$! zR4aQ+mg%kWj`v3er?%YP0 z|H^yV{-yVz{Xc(CtQuhjGf%fUH+G^qW%MQ$I*j9iHjuv{I;n7 z27Bs)q`^Qt!}sjLE;qkl#Z`+3sQE+D@N)3Ty`#PGWEt36|Af8KKrC4kw zfAu!tH%Qdc-pR$>)z#Y3;mG*ZX-7P z0_y5!nGA{~Ci0w!B>BU zt{?85Cm?v@@3d91nnl7c6XY)?kvYV5S!>YmEU{4}r z%;V+@Ehmg>^$m|;fwx-pO@-6(EHwk83ifU$86JGzTkMG`pK=q*RB{kzPWzhf#JAX8 z&{_hdm>czS>#uYJ`w<$^i5B(!Ry{D?JWq6%soEcJCbNy(Ew+<;n``34g{HE^2j;P? zSlC)GG(UC;a{;pJlj{=jJj&CV9hJNrO;3g}UO~ud#5MD+DX3@dbV^`3ZN?a~SU5h| zePl1lX=Ji!oMB z_1HKYf0VMsMcmB~^;>1EbERh+i`1UPiG{=?x5zokYov8pY%W3?h#j9;0r!w3cRIW( zcdj-w+p?l}rRKFH3m3c82@Y-m)f9z@niLwa)?0EySRwZmHIg(1Ve5+JWb2A(1#h8% z)XZn(hjs%Rc~W`l4)A(ue)Q=}M6Qt*_3&e3luetxA>76~v3UVeSuQkSvlTZqegi`w z+9M65Mxux{NAc*QS_lt$RYgur=Q(p&KBJE*32 zHAZZ+!)!ZUumKH@hQh8?u;zOERk^|EmYplDGv$@9wv61{gu0AU5iK!C7{TM~8r#J- zZOTeX+t^8pJw`XT7m-tBoVjQlrj<3Ru}ckrQk%Hij34u*DtT0oNsB7awXw5WYzK=3 z*mwjAIT+z=nH?&j0-yMhvBT}D?ndjmoY(4W$6Fpy1?p<b;h$qIu0ZD^aEEVH9M%@)ilLX) zc_p$*u@Hi7-OIZfs-RL$5x{`|eak2OZlB^xHw^Ol?eYkU zExS{Fe*VMC?C3EaYxTFs0$0*f%s$;)u@zlN)|gzBMZce*DxH6b?iB+T5Lyn z8obDqm#*ok`m4X>wN7x$0#cR2$dfzhmNnL+OsCiGszc|~X_3B(R9^b!liZhtrxvcQ@7>f?Cya#Vw)gC*4%t)=y#gv7-<(XKQ>GB!Pf-370#0p< z4_;n5Ni=N(&!z@_kQ_J~r6d~h!peQ5d>Twq+z{3dYLm>x6e%o&Iu1KU%lA6|c9BIE zD-IB3*Gn&*7wyYy+NUiTlwblbER;dI5i+2<>HhMxzY}UZ{f+Du;7f^B)3tC z1@DkA;7C@&{VC!A0&8B_QL6rsYsx<{NdVPVuwQD!^+k8TCq%qKnWbdW(d`*ymz5Du z;BX+9AR)t5Mrno{zLn_>qA?IC4rG%{d11mHv2h^uD}Lt<38j&!{isiZ!qb4v!&*=@ zC_;(zOW43o%6ADlG@Ti*o;dM{e06BYdnsN;B#~k|@d-a7B07`Nlzi~`^FNV+^xbuB zU*M^!6gCJ5)qjaZu|K(|>)&9Q=4rGrgw?wqO;TU z`t_>A@A;@2L@6B4#fbEiZSb{AFX)a(AQZrt+CSbT4P8*?HVIu&Hp$TJS`+V0;-(Yf z=f@XTte-*OV15$6q#1Gc5w-|@6cd3f5Vj(}5L?Zdm5>V2hjxW_g}DsTFR|zBzY5_u zYb`^7FlOxE4)KG2MSUW@P~-}5`UnsR35I?q$Cu*@aiRh+^#ej)QLYrZf|%lNK>9!R zCxjG1OQI1~d_hip0PucN7)n$Hl5Dw? zk95RtsHvzO&=b&Q$O`0cXoTWiF|(p4<0ebzA{anVR0O=5zeu{oF zV^#oPe-ex$akiot4Zu323@umKivpk>Vu_Y3>cs%?4mn0M5b`1hh=*XI8Hlt6+^FQy1>MN>S3=hw4Gh}4I1@9B582-GP-AY~_*C==6VAq{&=Ge<+*qu24~4cK_4=f6 zx3Pr{u~4UO+;HI42%T`Wa;HXf43n5g+-ypri7?Jw+;lk!yRzWYLX(pu7?E)k7RWN` z>>w*}P?A7HHMOQ2eKi4u{s=N+L9s6<5={8aUdOPmhNrODZkZ}>iXuseBQ18Og68gM z<6sv}nOM!1pqiKvT58orTvER>d^~Ocg|!d?F!Wk z5YrV>Z_locndx`B?wRnQA3p1D!KaKj=UT$Wo_ia$x170W_l4An2jis_x6N>!%fh~q55-CpT^SBGGLZ<{lH$D zT#^n`P`krKpXokc+>dNcVU6;$*>V$JhWw6jgL2bYMT5AztXgR~c^gaPS3^3&ntd&& z(GuD*l+S zh#rgV>F_Jl0P^y@^&5{|FA@7Ha&ecSTMGq3Z;v;evN(@uH}kM#0L1pE&eb(zG`p68 z0TsKHJrwE|>02teF0kvS0ahUV!hemE#LCg6FQ4TzHfi4PHF<|m*|*KddIGkNYTrwj z9TNx0!U$R>%(cK$VpSRej+19R9sR}}iJSh4N|~;-St^oJ>>tWheDoV`A#9T8vEt?P z)xOs{LtNZs-x1yY_|#BQQ`0hF`fFqwPF0s##J@c}en*|EuV8uiCb>L8bP~k@-co4# z)G3AcP%2{GA!3JC@{_^$gx4-q5d|3H5>qIK1>uB{_`9Q2ge(X-)^FgN?cfXSP~zk9 zoBXnQ_>8J3)b~!Na?WEh4QjM*Kjb(MQG;lr`|@S`+1MZ1utuho64*s7#DYIGgT=uX zj1>5vDi0I3BMztv#Psc_#-M!FQ0+7`4e5gIVi1rSI8R70p_c4YXa%>d(9O&!yS}e< ze;G$luJHau(;=W319~`htYk~eKBF1KHE|ej$R27~f-cLNPfnAM;c`!oG4C$K4r!T+ z%g6y{K&M_Klj8E>o^Gk|ttUSyRcZ_-$OUTIC}v$sX^3A7O@*08U0}=RNGZYF=Zwl6 z*M+aF!p!Zf5QNMUN?VHQvl|RM3kZg}%8*K|W_df!VzNYv=#fy0B8NoEcoq$-b0xJgv2k=Gl4UOt$( z4FL6beO&)mw}ahbL`7M7LH(VV$ZWKVEL?}op~rc|nQ=ouaK=@Ds5W%i^}CE1cHUAs zLpD5R`zI_e3pR2zz1Y7#C~o(Lc#I*IT=PUbFa;HU6EyG?%1H z&Net``@8lr+gV9tmz}O%Z3E)|FC~sULC&pSnp#q!)qbS5^LO>f9%`xXoPg-9WVvLP;;yN?KbE&A{$9 zAKJ>w=`}rqMl4Oo0bV`|eGDqdScXoWEWpvA#@y-R-Y{Q}r}neK@}pAA%+%*+K$Mpto*PK>Zm@j1qEp*IY9!2 zwI^i-->~zI^H(JYKGxTU_Ej5)V}CW)I!^!)^!gX(om3hVF)I!HGzkeUFbRh_SL>OG zPZm~8g)5+?+jBh7;Q~n&V%`KtY{MA`U@BDTe#cG|VWkUpHRjfXq4jbj--PfS0IQ1> zyky6pZpLqkQ!ze&01Jx&v&`utyc6re&d?Fc#U_`q5yg#bV&VWbo8QQyI4E8enj|J7nj~dog?Z1GO{Xx&WSIRG094K#I5nvYWgX1G zot7c*3TYhT#+}9(V9TbQUU3STew}}maI#+~F3?AavAZyyR$>>!BaO;%@ zNb02qn)i4RqJ|!E9cB$(bK8{Z=A4q+vT!{_-*I@GRnGwq)#R|h`jU=Hx=ffpDdgQj#Fh``c>czb#MW+6F4``<{v(pYQyj7X!Lrfy5Dr0 z)4mybBYJ3W2NBWd^(m(2?OIL{z6{k3)DDBZOpONb#E`rUq{Dy4HF%jwNBoTUcoUZp z@;S!Us1=xlm{V_jUC9gUKhO`Gu8yq+=ESrnMCYsyt$yJicDS&Z8oFBkxjMiD>Z=P^ zpXZMHq=^MkVv5e0B@#$o$*YedvdVLsF}VnkScS=J7_vOF%@@B1ZoHoLH@%r&)b*u7 zedyCX#o97)uLV`J4}5&1>AV&gm3`JI^R=Dtc0V<6=S%Xflsd>?fUIvN(0kIWDX^HxU}46!>Rj6CR9kf@0B{oqh^H|w7jtoqD`_npB& zKr(}%+l zc-1;oh!u-ta`~)eDq)1<6m-tiTjq)KP)gQF?@)Z)27C{DUxE#0owH+)e`4@^-yu0= z*FS#mK}eo^+CB9B>_79`b^Yq6nD^@ryw_ZA#2GY+;)1L6MggC{jjp+nZ+i(c_XFWB+xtAaDfKJ03EF$mLb;vCUdOOlA_m?p0!`9Vh2#EBOV6*aoJZ<~ZUV^R zQ(iq-)38?UZw&$d{93LMkTkj13?5fYTN+apj`OTqFu2o44GVY0TkdCoV*_2ILe!?r zr_crM`=D8Cj;&OAV_#eG&Nt`!j(yIr(;d1`qG<)zs1=^eD-rlq9-tCe9@L7<^`nfl zuAO8~6q;*JSG+CP5FXZ)Zn897^k@sU(a?kElBvDawFDJW!d|0*$8uWG?w(Ep86wNk zAN@tPv{t?aSTAJy2sy)B5SEo2zB|NkZ{5{SWgFnia+EGvqfDng7j>BUE-WsGT^I6> zzMX^Nn!yT{fbAQy-J8#r?9>$$@nSOhH-Z*+dorNc`@!I$&J=-gFG`u35Q$%(nYjdl)0m>?=XGA{t*=jzHOo-=8}~LKh9jK;^iWrH5Dr$(GgE?Ft_ld zm8t1n68H4I;9D_g@m-ePc9DNtrA=byXSP)I)2^w#hR6D=!I2_nfiPjak;_n9fZH| ztL)PY21UK6ov|u#W!A+w4W0En3nO)O#6K3`e@s^)XReRnK|s{-K|m<}oA0lhvE|>& z?-WfqBlINZ)vk+r8IBs{k0-Hoz zzE^&pxxY^8DM1#)RggZd0)#nw0DTIZ3}L(t&XiYoMp##=0|a-M{DhlPTP|&)eVqK* z5suWW`@)D=xtgsNZDc&Cq)F z#b9A{9S9>BXx#8a?0D{DAYtySLkK$Uvm;GQsPvsXyeZ+{hT;j{8F3`ehY-=eMBoWN z=Fe$;I~|_k^MZ4b3WjJV6O1xixm6pfr zdGU1Sx=~mF>8h|9l0_xCZVZ1$CmavyTmVOJ@lP?;UZcJIOZVZYz^`%*l*p%RW?rVf z6{=TF_nD#_R7`Vs7S_e|C?^g}ds_*yU+}THb_pK4XG%wBa3wiaI|^dRYAA9&W5ydV4lkuBgG z&1PG#f|%Kg$@HIdYu?PBg8$SVf?V(oeD zEUk2{6s<(9TI``|qqYGKYL!)ULN4meDr?GmT=ca%j`J?LkEP1RjjW|8*o7J2K7Kw2 zZ=j-BU0A#qpo(XvNvIdwZ)@eMmZ^+q=4XrY4g5f3a(g_wQor| zgSR$z$U%e7NSRx}l$N@HDhX3>ER;{6_*a zl=NFsq#$4h_9qF}XAEp+rHaUJ09?p#aRQ%J^;B;?--1h4`?m-phSj^`KEod90ti;L zT-D#;t{;--Q4<<|#UMdP_fex=%Gep<$c4p3rrmI^8&`IrmyW}@ko#Cm982c=2@Oc0H50rStdfZMi)`ln^HOdslE0)(} zz5GS>=_@ul?5nthCq7=3!1x__v;8cc1_Q2&!Dmrl(sQVd)ngP4&3&D~+tiPgA_Z_H z!a)Ky%4xPAm+_*#2h5Pu&D_nxTAZ~>da7Lg$xyE9Age7h3}W0=IbJ&19O>vO62pB- zbGAMFWV=_Wbhq14Zwtd=w5;zGEW1x4J<~MHO`5O=XeV26Os49}>Cf*2Lh?ARikb3C zl`^zs2eks3lR36%?0JY5)^w;%vS}j4BO)#8+I+%n`^-ek@xHeDRCQZsJ4k+2+;71j zo)*#*(p{!jQZ{g2_h;-*X=YQry3|6^CYObLW$UQ!>YtBIB-?272j9<(d5r*&ua^@4 zsAnHoH_U4I?B#2_@MJNBdMN>Nz`tzwSs1>k?J9}3=3I3$O0aY+Xv&+n@)u3fH?#7i zd&tPK@f}H<{dcj^^pGm#*2nJT>aX9*B;gv>tA2>lmuVkahi2W*PcZPt-N9x-iW3j0 ztWR#&ZZ30Qc@yE77^=%mr z)m@sMTH~C=)p>Z+sG5(MF7U2|#X9`tWP2A_wW{ z4MB)kIvP}}%fk(fTp*lkeKhNmQ9ndm{0tqPWEQm$Y1t>vrL+*zdqOj==d(tADjsl4 zRE8a6Gp;(YNLwVm>25RkGa8rg;DTpcKfMtQP0h_4FDavd+P;$L#w_g(-13V+NnDgu=@A}REEGz# zNMxHwW@m{|E|wDr>R*ynYWnd}0xMeDgieu-A;M%jk%~Kf-W2VrBu+_mAW%`XkDMxi z$P}d)2i}Fe!-*q^3+p^07Xe%-M331{LPYS&!`}up>uKS#E+O7&KjqPN)oK%7QgQ|YibeOLunWv7_?vyP@ILQ zsP~k&5`@g@fe)N>`L(n8msEW#yF=CG{q|gNt)_%mWOCPipcj247fT3FE{+(Ya|*!( z9gPSJve>C0mZ1w0y@%f!EvQd+^Int`z3Kf5C*)?-Pra5E%}Qfnj{3m{J0ctwqA(ky zpbd9FP6^00#?7bir-zo&{j6$uS%3%|k$udue&kF)!wXdr9GYZw%>Wb)P$JsTc`5Kh)*B0SB)-88OaC>c-Xo`MAck`h*Sg5OMGH#swk>U!H^hx85i;ns|SKJ_$ znh|cxLxci}`oK?@SeTdC5}rKdvxms?8cYUDalD-_@%e&CkC;P5jq^X}XKD&!mH1q?O!HNs+ITe7YV5k5KwF_qG#uK-YhaPJud{9jav? zZS$RhnM~Ph-c#lOW9*%RL<^fW&0V%_+qP}nwr$rg+qP}nwrzWtG1YT=X8P}oIUTVs zzKa#>W@SXaU*?lBgb430P?px(XsRGCKCgCG4cAW8y#6yQ z$IUsW_DZR*A-2pF-i9rEe`3FgNpHgNX~GySDho_^go{lKhZJm4^lMqbdRPx)`giJz zYLt32d)(DTaIuHT6i;yxPh(ohKb0?cIzWXTqyl2?YV2HV9JFd z>O1-Yv?Ob!Ibe5GQL2PH2P@-u=F}Rdwpvj;uT)0VwJ~`*0Ek)()ho7N=3D255i+6B zzRn-OQ%Zf}L0^`dec133CK++F_pHD4R=a}Ld)@ThjeuM8ocI`_E(*U#x^4eT-Y+CgAMyKu5D`*~l~@3#;o+Q4}A zBoH4(vpm=wqt-b(6^y4UTnU`u8d}(ga$@zU9CSA1Ev@h0C8udbMxwNwMaeLB7t(J; z6fDMVk3J;F_DuQcBYj3*iOi)pS$FBj|L85&6RPck`101;gy|ZZ5IGK`pp(@I7q(%_ z9ANrV+6l;O|BYLdwAPN*bpT?G#JX2;U}9*1;Tm?`BC{1xyy~MeEWKF=eZNAO=!r>f z6z;bwi9NoGT$7|@Gr*!6QT1$3eQnEOBGZ+)RWCMc&B)|AMh+%dWs>cu7%_|D3UR3M z4d?*SW1XCZnsQ7(ee@x-uW=qb#HgMDJ(X6=pS;@#)+1=N(7o3gtE4VIj5?m6p*7A+3_OSmBPK3;<9Q6Z_fyeKPvgt911s3U4S>;(Q z3P9DP6Z0TG+-YJa(bWF(0h%&jYVp`8{gFsrJS%`gr=R2=Uj7qN9F zlbRksiT&f*v7K9X3PEMvKOm(31U{2U(_5#lXo79GtaR1#zgIeDN%|t)ek&b+etjSR ze;L4EZb{k1-C4xe$j;cp)=bFG*44!E|3jFPm38c}M38w7tGZ)4CARpbFN5m>=GG)G zi(5VfkTfyL@6fiVMs`*NqWZSwq0;cn#<41D*lOL zvL#>B;Iz7UkHLZv3TqSLoavWIadko*l_h6T^K~7PFko{{nbh? zaVKfz*|bBloqmZCf#>WIn`6Qu0HedG8hA~;X%)n<*JAZBBio}JdN*}QJi`OuQ5C4k z9!%_y6Kadn&9D@=<@<@j8?HYN+eVrtKw^+?aK=rDIE=s%p?R5D7Fa9kRjYx1oP$)5 zKZn_ju1v6a-R?u>iYaJfXU!y0F#y8b69PhGkRrwt_F#Z>H}~ve)`PNW3BH?(OY-5P zS2>>Y`TcgQ-esGSJ`NUV52HQW3$%Ci2Pmro(;Y?%M#@j^!07Kz=js5OrLqVko7nbE z6tOLcs(yNCYpPbMBUMais(D31HXyFo(0uQ2Qll}^>RU(4x9yeuI+FdUOi<7-61c81 zM5hqX-9`c+PHnZvdd39cWUm)-ME#&EZ32`Bkc-^Ey5#L?$H z>Gyu<)bqWRQa>!7BF&^05)0)@5;OBN1-2$YFPdlFw3*F0n^lzX}gKp_N-gZSSJRAt~ zK@pDegz21-!jTraj!d4Kx#~HLz}|90xJdP&CHKKQ9+Lii&_~t` zq0?O-(WnM!=51k`Ln)FY z3$GDpHjqrGOoLi?L?XCv{ zE~a4MJ!CueJZ9fMe9&gn+4(sF@iXl}6~OXvwt&h<+5m7zUJE=K{*B2NFh9F5l&k3^ zUZ;`h?b<0cvV%8qmmTfFH{JK}Sfd*U@L)co-4|PkP1?%vEh6#54-2Xz#z;Df!^0@I z5f@YaOOt1E6#%e^pgzZ9j?G}`u{tqCJUan9)X~+cl4RM~kg`dex5V}YQFeKiL_uFU zIg!EhmLGh6MURN#IMI1k6o1ZyEtL}~z06~N3|uyi5e9?#mSoZys*HVz*r-TT|N5Si zy}l*R>M>W}xKg&S>6)TiiT!B5<2bdIBn6=NwG$J{12}L%M+;AnNYw4RBe9@Az5^T3 zpt~xLd%+qSshf0st1!?=iXz^xKO?=dt~?qhWs7ga!O>dxqOrc;MO9blA7wI1>{oq= zPUPURc*$A9Ks;anSVN}4rQ%rW#zJu+weeOpsmvG&Sp4F#q^{?lL(_9RR=OzMYoJN1 zBXhT8X8hnyiT*c*DikkgKOljD#Qp(eF~0=ID@?te8j!^TE><4uUKug`cc&|-A>en5 zaY@>XKEP&lN^pZ^hc}BvApv)w7)XH<&6yjSUv7jdK)1<07+S3DN)|ch#Xi zIIJV*7W@M{A^k2Cfl(cJIF404k)4TRgY4yPebyuOD#|3WN-Akvc}MW^3dYR@e9Qre zgs33;a3n!ja4JXzUXs-LHx(cY+*AQFC+a{YJMI94gl^(!B0FiFd8$#na|00YMjSy>6 zVW&Q*{wpHH9DM2_tdbRV@4{#32>xu(Nu#^Ugmzzt2Kb9%KW*F>4e1h-&vE62CuQc& zV0QtfnaRiMfKTbr3-xBrOIh1Rw8$P)0Y_#aT^P|6ea{yJStW{YB_9ooI?QQUpTlq4 zr*tOF#hUoLozNL!q?#W5l01MnfHzB!Z$_Vv))0@@fUgEWz>5AJ1oV#OXUscNfDY$c zm?Z{UGYuAxCad4^MmgM>fdRlfh-`j>TY1lE!zbe$>X4}_FYBPV8uEJ+{8GK#DESqQ zg5U}CA00W#viH^qJ|sm|zNQA=N5P@`+(^X7(k_mTvbsXNj%4RTMMZT_#ux~-U6lc( zmL>~C6JJ#}iMYYPBFce{m^xMAJ8Wkc=!%64tjyO61&GR3`EJF^g`0x4Dc?UmX3Bhd z$b1VQnPo$AVS8q*8+2C*di9XK`Cz?Bt$cN0ex700e{25351tXensxQAO<|4a zQxr{c>f_m+8SxPRN}d=8{nZXu#HtT}@EW^4(wY{sAZUWnwd6by95p3S|7xX|do`;z zXs&GPFlksv^QacMnzX7h*cX$h^+?>e9aM{R^$^PY_+RY%{ztvtqu9Yf?ianp{zWe- z|C_|)%E0hjawlf^uSQvjqK(|*uS4k#>xvC(+UtNYeDFXh-4aLtYFw0pvjLrHHTobL zoz0@lN{Tbi1>Hkq2D%Y6Umu=z~Z%Rj0CD}42r+DXLW9*diEd$Oke0uG33<~3l!J!nMh_Uio zsrd>ZsMj+a<7VJlbt{w!HMVexB~XE)&NOJ)e|NRId+vjU@!gxBQ6{2qZygm zg}JE;=T_Ewl%YH8>{)CowAGhrBiV0>Vku)JrKdQAonVZv7@&W=U0}QkuX6#w0=$88 z$KNBEfHvg47=J4huCP*BY9k04IO@3FG?+g8>e)6Mi-l}~^K8Ljpw7t-Gq_pGo3|;7 zZDWH6L6xffi2eaxlwMqpQCNiuePa?T#&6Qj^%{gK!NRL#ZP8^8kM5YC3(K{vhIP0| zR=p0pmThj48nwJORkFf(1Mv($d}7q-!4IWFW*j@@zDG`%A(j9LveO^sbJUA_rS3UW zD^k3U6~BhH$+%h@lQdo=$|RtQwob7&HFh$7BrBMO_#yj5A~tqFSVR{BkWwe0U6@oS z+u=v~wO_~)B4fS7B&`n-dJ0c$8l__#4XJSqcz913WIJ|bek0zEOEfjuLV87Z}m zNRwuDwPscEu;!(zxemD^MxDBd)v~5mwaTWZO?C5cKghJXjQoe=rQ74N0pYdx;MB*B z<8;euhG(-ov6T01U+9lK;RXt~90*#9Dc}L&4UOuZH%MxmLpdZy8+BsIgnNCI*YOtB zsV>M1Wt-Y~x8#kALv4iD@>Zp)eLEyan_#~`mYSm*3L6XLN(DW@C32M-0h$_>dq4!t z+Sv#x$Z8oqidtvAMn5Xb%>GRXWQ|I`f9GXdpC_9yB^29UX}g7reIewq`h<*pzYJv( zy)jno=5`s?TK+(LTSn`dvOQBH>ckL@d%R?K9aiTSx&lMQwr!Vse;VX5x*9_OPgjr1 zuuYrJFwQH6E$=1Z;Vvx--``aG#zX>IlQo?!?UKFY^jD8A!QvB16xBmU(q|BmTE%FMgNt&!>Lt*w50w!0iR(|tF4Jhl&%Pg>2KAS^h8vapKfbwt!P?tnA#fD$z-+tpLUh`uqW^06NU-55+>`V69r>j}B;Kb* zz#YUYdxPVhoUqezAB>1$ypKvBGpL@+DSKn*%HKlZb)F(5#RaH0`FSB8lmgzFQ} zV?)23fe(_{UuJYnR9x`usE`1HVq2rFDB7%tR8O0*SXH>cD|>Rvr{;(TD=Y_8WK66? zyl-q&bd;=QRCFB6P`TR>4utJkRbFCw5QNdstJ9N%UQhy|n8^HtA!QtB3rLmuloA*I zb)>gy^H~Vq4&Rd;3ba9s_dW)f6jG5<(J(?eFKn?UiMOt?G>2YVC1}H{$N&;myIw+q z@l=N!k&ufC6dZ6;72edaV95{DU0rOJh-Cp`3vpR-X`(^5g&h&(W+lrGpC;f;`pht| zYIK*XE9F6!0p{ZRr_SILA$08&36$*AI+MPLe3XbGySWV7Dr_|ENsSvJ3g18sq$M;$ zZsb6YC`lb(#f)^=q>i&Nc#SfjBQ7`t3U7*>HEtSJ+al8Gwq&{wr;Jx5`W@5tCHFzyy1TID_6e-5l z6%i1QNYSmJ5XPV(0EwWeWm*6dY2Te8NEsbSP?_yo{Op(q2Zxh_h73m6R)#6AIJGU% zPjrkY8hW9I^50F`4yyE-F`=cl+;11U!?|THD=@%Bc|#F?uvljFz#>ZlBm_u=fotAX=(10(5`ScT*ZTVW0Zc_bJigrpgTSwXZ+!HvF`SH-4<&9Mvv5ltm2 zvYfb=37IhZ#Qm6bQ759LsZkjdqV&^HSYrE^IW6vzAj~I8$>;J&j}qAWTA&$<94??J zD3>I0ev8U`j6gpLH2}5Z9UZX<A`N0dfTpwMK}Bu0rC z4nyybAW#q_C19IiV*68u;{`HKe6O&GFetfF3qHlEE<&FiW;S;Lue51}(Ib%}RE02NoGq|w%Q|k~gdVxTgJyX+EOMPHlA3SWe1BF5o=d`g@(F>8LOz#*2_lW+$EW0FNf=}zcttcp8R0oA_v@d zV_cg&@KjR9;DIZ)JD;mUyxfbNhs~fnIY%N>eL##Bek^Zn5Oc^kkxlG|@6bJ*3mQox7;CnsAJQKL*B} z11ZCX{Ww{X%nD=BClI-zl%^JE!l|LS#5~9ly`-iM8Kw;43~Y_<>4P#5EadJ%aP4d$ zrHTs+L)xLaWG6~09vj4^2Cxa9PU|aVi7JRQfHGN;Arb20OG6%2KZ+TlWXxGHOrTI8 z!nL#+WhGEboirUWNstDK@dnL7sT2-u@~VV%giaYGXe{;Mvhp?H%qz3nZT8f;g%-O86JCod;~e>`E{J+pn)=_fhE8X?Iz(%0EltK$ zvG`Qtk_Ko_U|s;aOnRYJcKd_xN>Nsxd->pTt%V+?G6%>j(36jU53HGHu#OgNvddwr zxLlZOp_#C(C5ycnZo}IP_e%I$*5|-=-vhkjaq#2Jx?R|_Tc$0o1ttOf^RvY-nL>l4 z#D=ui58^g7o~!xIm=8NbqbXjR?gs^2m~a>ZMwa~(`Qvb|R1kNY((Fqz3mfT8M`wEE zr8DJ}sF5R<6lK6%5-9DHl@}G56PB7lF2Cv^U}B|%g@vWs1ZHyePKm-p&yNo;44x`* z7w#~d+K?V~6)1?e9sY7cmAB^|HWYm=Rp*500p3KIa|jj%tGbfZtBpA^0C2L8PMFA$ zQ)h`VL0D-i?Dwa9?lI04!kkmuyS92^{eZkhZwe;SS_W-rZ9iPsy*-V~S&3Ac*@zh_ zO8^g=1|O}4Ff#dQ&cc|8V#@FdJ2W&$r#eZB%qbo=C)vKW;Jicg$u3&=7B&f<1PA^* z4iLbhEiAY8u*zdh4p;=iGXV&pUrlxDz+B!mQW~R;D7xDGO6Af|d3_QQKV`&WqzJH$ z@$t4jW*L?sLi4I9B=&X4Z56RKe#H}8F(w+{Hk%20%UYWePw*C_jGjG0D8ulNUS0H& z)n%U6HrIdJg|3qf(zEXO3^$4pyk8+e;n@*&Es_#T z-QO9#m;5qlMm{5a_0e$i==%=tfg5BNBXW92D5pG*U!_Z?W9g#q5t`HLA-VmF4`$Q3 zxd12c01STfc#HFBjW+yKW_ub)P7Koz85dlD1E=iJF(1^B>wSDGwglZ({?g!^KJ1F` zStVSX0xT1bcOI97+WVnKKxH8ThamU-Xec6aM|)9t0BgGCh48kZ24e(9G;1A!x8Trl zz|^W|{rHS=NxSFRF6qrbaa_?G-nc&L-Cwy5=-uDA9_XVsV%d=LvoiHx8OAiE9HVNs z;cN+$l`damWCq&08wfwhUaM2cx^dzUz7{{5K} zUW0mUV}lB~j}^GzAformVuEmj)+CWglLETswoIV!U26YXN}L)Lme@Fap^YobG#(up zY?n|c_h5%S)#=V$25*$o`Kv!qpl*F5*p)R~^m|cT%Hx|!4mRNxxbwA3FXGm4B{spt2?Kf(J z!X35RgV+L++qb!+mbhcS3DVnJyn{}-+?TrJ?t!J-`?%9Ohn9;+=1qg48>k(p=@8%8 zor}Q#9_f?1Z3nIcL{4yd+|&C}9Bx?Lh*qUJ=>L6#*Tx@yhl5h#e<0(8$?v&< zd_&vUyb!aayh<4u81$17R|49R-6Y5*0X*YRZId1w}Y~lg8x`BG~Y!YDZn(E;_mft6XPGu&S7{|vDD#_ML zueH54`{6_XvwGTZKNusEOZvTCM6NH)sLu16pbZ}aMlA2%Ku=+!_ck$LJ7S^8mCQ5{ ztx=!QvSr$-dfMrY4ev1yhd(9c6WQuU!@2}9_15mDnez^>orX<)|opargbQuP3!$Ar!X+ZKPSxAf0c-`7e z9%R_MsILTDwh34p@sjl}K^r}URbt%@YML|jN+O9jB?Q*gInmuY=1%p$J%%;$!o7Z8 zRs?^8Hpmh~n4kXq<`3mxDTV8&b-(LA0ub6#W(5vSWLwOp`|WxACdr@A1w1O#%Lqc>RWSlL`8 zYiWGvr8gw%-Pw_sT*0MhR&xPoN-XDVxJhW2rPBU6I@g8-oQgLEMs{H5{i8hpLlxdg z16JN1mPya1vnAXX?zrePcPYojlT8d7HNYL!@396XWzVI&XJ!C$6Ra7r2jdRXw5P&q zu%aq`*yFja_)IfJi4boZW2Ch0uf_m zGxT$L$d_d*+=g@wCUt z@mF~T7|x0%Kk<`}-$z;tFWr+2xMSJ(_ZfhAfk4A9=De4Phv-G1{FE^6*D^%+CJ!}A zx!W^m0CXA_&!TX&??I0~jbvCr^&XMXTs}oyM18PFoJne_gWMU`NP5FrpyZC*|3beQ zr$)}wQDiI?UXeS}RpujD?z{ap#cs>64zA6zu|`-W-RB%6Tr;epJJ?`^&?5kHd&ODe zbw+kIqqfHh!AiJOiO{hIe)v|saHbwV_H^35rr*fTJltTPk!T&ka%0ok@B1pCoL&ZQpR7DZ~$wjMd50NPi2H#b7^wY@A5 zZP?LWrOLl`Sdv{}S5BA)Qb8=VB?I~zFpCh=0oCU;+*F%f(>}coo@!XL3gyxvdd>e* zn93Frs~A96OrRm^;s}uv7N;&rGO_(3qiH(hvi{_z`Q)bMM7QxoS7utF;`eg8U9#5( zD1qUTsqt=hh{?2vvM-n=hE8j7#1~YhG^7l=TWZg{&Z%N zwe~~N%{|F?z7q^p^|zKt+jO4I8QJ!EN6=-oHPN2x#g2*a;d-lg5WKm;uM|PZ98srE zL0G@BjxQ@@Y7xo3#u{yar=d%*0VGE1<_G9M+X{n!sg3J?yIq98(_z&AZMWWZ!GCE%ssQGJpk zBy2XC?hDj>%1W4WGes2_*S3viXV{odGt;xb-YzHI{!Fet3yehIRjMn|m+yt+4Z2U5 z>I{eFW?f?6ON*pA2#EwUlp97d6cbLoY7es?mP9~|ph30}yDtta%F;=M9b-*v9;}(G zRf|rREl-&S;v1-_A+}#9Hx}beR;js7zeqsjIDa4ap)1F`q|NG;oF$J(`WOIT_7IR-ugzrOqI1xD?vcj|41YnjV|xdAm% zCVLK+1cDmfV@+S<;bbPGqIA1DX{UEMcxH5654u#6wx*bO{ykq+XdTc-;YW9+KiEqP zQUDvp$1~78ndRg#LE#hVK)233(GcL@b^74>C9Pz>NNKsCIxv_KU#d zn~7U3j$>yTg-=YiGe!{FVZYQN!6byF?HnZOE#!=(>-0xl?JiDgln9{_90j6bHRLl- z^!4p7`FlR@peNW9AQ#_PBMw)9ITjy4z_UB>2?9|W_#BP62$B(hO#hD4mb}cH=;me) zG4&YM^QoaU$Y1x_b*?lu8TS2O!$!ZqF6_d5oG-xn=j>}qneMwj_}m{N<_M0bxmR}# zAo4skyE3)Z#Z4njsKW=l|BUO~X#bc;|8L6ZA?Rt8>lBqSuP zCd-0y1zdWHYP{u&@cFeNvFO;I*S#P8!`m6^E95xW1gDeF8;+N)N0-~$*4}T}K3{YN z>j5PMYvI4f*$NG`;~j(Sr~-&Q3I8NrwHuO*<)l_h@o@xL-V4$D^pVN#q5|{j85OMg zRr@7C1|f4$z)h6aofY|ufGav_oF?X_&D5!o|NRky2TaZuT305eQUICeTGS!?AOQy_ z-wyiv8V68ALk5o_=K5QNU7%yZF`k{15lJ1%|22)=C?%4h9_UfDm>8i1SzNx$#W*(rMOy7bFsr}YOjJRCdI2=kE_+$+e-2s97DGy6I{*9 zf$JrUpVN zcGSKroZ@zdy~SYSylTmMH0{8HpqgGY>xloTN+KP&(?fUF-ITmGleIOH_I$#0@HTAq zQCJLQdy4Du#{76QLh<>+f{ZZK_(T zIaJI09ng>r?j0S@mc{QV&Bmf%5JJENKGj`zjEnnX{edE6z+=juqU z&=62$S=g<%@E(-gpzVVv@Ho?v4>WHiX4VjH4YTKFT%T@V@)1K78JMTv_#426eHB9Z zXl=m(XW-+cEtSr&#cJ{eMzS`9t=E$ub}*_cJG$0lzW_ER$7|z}zUs}-6b$lWO>~!y zy$x(aOoFEbnK%(~^mD-bgb2Bmpu0pEHN-qgz9b|{r2O#@n6jQ=bW)EP3!0TN1(5BS zgYY;M^umC_+L>UyNVb83na8SLNDS1H_7Ii(cIt{XMfIq-LhwuIajCVjp*Ket^RP&c zJVE2e#qnz`-Eel%A#t{Iz!ShZ=(!ulp$hq`{0DEvp;nODTAq}Apc*{%l-I?l4ZT@TvDSyaRZzz<&FX zwug@o?2X374kgZO-69PaH0B%2=x2NXbb?sKQ4^zZU!zhv9~{bwWRClhns+`OoV)uk ziDcq-@O>oT)1TbhsZ!JPz-sJQwv>gSj(eyp2P>BldN~^;asE{nRxYXdx-3&RbN=l} zcp|w_EmLE)fQ2#H%K#f5U|XYC)bqoEVN2ay9@vD^HoEUUNOT4wwLOse4DRO&MNuxdy}D@D_k>Zzte zg0g|6`x(J9ARZthp@A#D*U;6v*}V&&d6oa(##}!MZe2z45G=rA?5~CHQwW^3O~Ux< zv`3vnJE8Xl@52ZhPB#M$dQRL67(CYz0>-&$yEV$*P~BqP_r!lbOvJkk)XV?9rCrj# zba)Qh#a8VUg&_d@+UF81<2qh~urR-c`UVoLKZ^yBz+$Hpsch3lx615nCs>p~CMKzsF6?{x%XQQ97)L?F+UuLaf|u(teS%Q_mx42tT%0uF);abga`ks0IbcKl4Z z!zlHMui89GtJ*UM{8^h9Jq$p|Q?+9K9Lj2}&es$-bXm#BR4XjHoh#vu4RZK!!!O7p zrCxHfszoNWnMnwRuMQ`+GjVvKAeoC{qvZKYz&nPa^PtLN8hn-pb4EKRv(jy)0>}buf-$A2z!x>t{zeKea@bGLQ% znpdJ+vTnUkf2vQn?uTc4AF2OLA&EJ6Z2=+OL9+R>0KxZ; z3@2-A4-c>YGAEH%?n}*_x~C(TJaOS{XYPey4R!G-moM2 zX^xsP=0WBDlNYF@8$5m8e$@6()$@+E+CANX<9-$TL_ni+zZ-o;qSZY*Ai42MAMGAE z^qm;4)b2VN@jLAPjEeMIz31C{&Fwmy^{DLKgXldvP}BZIL+hOh7X6d~bGk>P z{hk>9alB`v{f<5U@{jR*;fLni%Yk$G{PleB&}WkZxzE-9Sc}eWyH~0~l)0=~bzg_6b=&eGOW>|9;ojwMBrD%cor%8r4am?R@+Is2j|NAw_D}WZ6?_zc)oelhs)>K zr=GvAi*spJ>GV=3B5oe}4ED{?2Z3*ZBS?(85=N|Jvi0Mg6UcyY^Ex(Zu~0if`}9^X zig!ca&#m~TFX7Sa43 z=rg3~8{OK`Ldjd+-O}Of@`wriWNADF0^UA;yUNCV4}~Wz|*cq4S=dF5h+)J}-U4KT2?zGHdP23W3@Z{-Z`-A5s# z7G;(gGG@Y_jHST}h``TBZ&uZ>XuUOAZL$)^?KQBvN8Eq2Vi92z6@NX47kY1+SCk=B zweryhPE7MF-W(rWa4hNa7CMb)wSk`;UW=B)LL^O>8?b_VZV}<;+HS35dskp@ihH~& zqIzC^XcZw+j+t{HKl@vJYFB~>Tx77Sv}OO|JR9%ueo?FiF+88*dRxQZ66<^^U}ep9^_wUv`{mMo+U-pR|;K^1OpuUrqmK4%H@RU!f9Na@Xn0j zFdToQ8q3(DDPc@?fH{xf2V-ys-ZUHb{)r8*)(4xFscPjRY~A6E9(k zaU({@PSWM1(tAsR!s@q%wk2ng*O&=sG9}}POB<$%5bGRzkhbTCWMQ6Lugj7 zM^&zPFP|t>R4kUUVz@-V;x|fIm1!EXg81WDwrDi#QlPQ(RX4+&od)<7L#YaPe5eCd(KjZ^k~dxQH+7V z8K*oT5bEGufH$fYtol}FtRvhj0V_?i`UaT%MX5wMlQu3HS9u$k; zZ|ld$84;~pq&u2EFvWN3%0G~4*qyk#ALeXP&ZX+-T8sa*hnKD&FOE09Q93x3T5gYsGlJ<9inyKsxQp`0?V?cul zMmqpkua!@;hBOm*7PX-b$w2fTo-~0GE8mn{NCuZ3u=OUA&UXYnl@@n@fw-GnX;?XR zp{bs<;^@)~NC2->QwoGFx=+YnTzv&W*^E_Asf})7zczj}QQmc)jSD*Ix~LmB1OKbwv}zltSwY`#dISCg@fF!s;JN) zpS!#9BA6&7-@YnN@hPv@$#vh;seJKtB^HfCX54Y%=|E_khew?R+^l2IA#fhkFf{CeONQ~t`iKi zeNq5Yx**a&1Ax_;5lx-Bot6k#A!o>m-4u)hC|`px+xlsEfG2dr&b5B=riC5z9P@oc zqLqa2@#2%XI3emEatgrk?8JtFxUR!6Ou{i_Phg7aq{Iqd9K{T*3e1!xr2HBCF}<~0 zGJ@drQQLW|J&m>@e!3c#I>2uUkQ&Azk55)Y^JMheg;B&z|3a9lLqk%uQU`^RVPncY zcJAq|D{RzW;gLAq%`+4SO(C!vSt--dH4@gvHx?H5IB1YzqS)4QgO!6}sM!pbRemyW zQ+)^~?V(|6TGm4jP+yGAzb3Rft_|PcGkIkgm=Q99Zt$7lhl+(K6+QfQi+Bved_Xzfngj?5&)dVs&<^=+VSpk;BCHu2<~^&!!=Y`#@T69ogW!4bLfX@coub-ON0@{GH-a94l+ePd=m(sxh#0D1`IKU1 zN>S^{7FHMso-r|OaV`;96s)Xou8eNsFhc_&-lIlgnQ4=m`$7XUTLqC?F!gfYLTDc_ z4w-G+@Vmw%uwh)#4rHr02M4yaH~R;=lyz#}k@Q6iZbHhHNZF<;6#NNcK>c}bO ztMG7j$$aKvf5+s92TgykG`J?GFKGll)4E6SR%$nSTATUQR5b(EU$IyRb?yW3atTC; zat+rpc#?YXvUn@a$kWkYG7~&qFs#cHIL_|UjNnS!;ydFUAOlzVt@0um32eeD@T0-LLPC#7ZTA-el>~p&!5S%_4TvEu4n)6UFIv!$EAHdJU_o~)l)S5+64c6t}jS}r0)Cx)wL0nDHggF3WnYGZ^4;yDx0 zNwk1b5Xx+;%4}X%T2+@kD>p8+EUh-FFx6VqoK2xq%s2%v2pef7E7aT>uSwg*-u_^n zL#5A6i#sJq`dx{$F@AAybXUf_LTGSeeoP)OL+Ck*PIto8eu^*b+noufu_%LP+jev? zJh`p}6J1Cr$4sVM*m{q>JybVm6i+7d)bh2gW%{;p>HCaepzsaMH+b_fm$3iJKl45B z6#`6N^Ej8PiKq}QPYRIgBs?YAealhT`l}>-c~iZmCMtg2z+XP%l<*^q&=Z-Ypl3}Q zHSaGG^5LuJ6b{s=&gzr1*r0QkT-0UN+j2!oetkA`m5Z&@uw}~NNn&EX{KTc~VW2ke z0P)iJJAFc8PsHs4N=Rq1QjR&-%CJm{YL6DCTfW84xEvUP?+MvQQk!0ya+gQ4o46el zJMn~P`@5|Cjv$rjbmcVr7D>V$cr6pQ@;;S%AnBILbIr>zxfWzGms+Ko)FLpFRmu($ z9F;_c*bLjk5npXA4DERX>Dv%3A9a0NmT^BqPgC@>Ls~o+k&>hx8f|D=P(h?}arUjT zlcFqnaJ+1rwJr(V2hP5{nm>5Q)FL^Jq(UJJ$IY{tk*^@>;OOGpATAM?I#9Po$FDKx zi2S)=P}Hc*5Jxr6&nx=IV+@OcXk8;RDt8cNtRsL$7m^rR7zTR_d9M9n*qvpLtnBm9*#2~U@~T3#6WwiZmI z#ZcCbx3d_1_6xaeF4Fv458rPj{e`lR;e zO`>IxPbV%w{_?s|BJzrkqg01e5bVC znK`rhW>cG5)aqAt>VEF$y1p${yJF6SBMp^b<<4k}sPFK{$nQSu%H1aN3|^Rlx`eM- z0f>D`!lEyiz$~4!>1}JvuV)yGD;fTKcQ5f71Qq5!dL~}DLJB2*FeGh0^V8%KCOOY& z9x&Vl-G{QIEs$Q>@)~gD>PP~s;D-9>dB-x(To&-!<{EuF-FHu$%WE`B(Ye;-#Udc? zz#e6ZQb;KD!qUXh$?0D3!?HJx;I=?!9bq>98HE z9<(daM+qpeBQHcnlK#-Z z36_+UPcKQt~)FcI>#iEaN-A@dY=UE{HN9}VW2vY1Dk z0wBgfFzgQQn&T)xXymO%TwH`iW-YC(@~D=4h>nsgnW(9MiaV6V6DXte{^4>FKo|l` z(Y2k*1}fcHR@`L+nK?A)FS2elUkpPkBP4FQUxan8uNOriFG7$Hu7r!*y5G|t%wS}~ z@0*KQI0vevpS}^?T%=&*+;q=7S2{f=zd`Ob6^RFg(*M!y$SH`PQ%)lh&Dnzs7b-T%}I9#357(b5B(9?&Dp^8-`dyaY!vp24g+nj9X5QSd{PB0 zX~*gg+f@aG5#_xM8L#|VmwxNimhxE(!>dv!G%9#hP9XKhYGgW=QBSeXsfH{*ERG2{ z?OTlx_+>xbSLYrLjAc@qUk+SgoVqF@)tFxKXJpQi%TnFzPb!wC_JVYb85?gJYjJ>B z5`~YbZTk+DOfd&PN6_jVIQ;7AsT z(*~uLfFiuohk`N465QxehCL;NYWYCR^C3+|T{0u~yIk?Z(c7#iY9MJaro2N!jFats z$Y(~#F_;cTmWAc8WAZYSw#6q_6+NCuid>caJfJF-oXv{a z8f_j|kd4&~C+twCa={!TTU8u?jk>Q1(_5_|<9lUhkQEE!;k_`WKH!w~ZYO~i{ zT6-a#I8xxp8U7I3s<*Ty3mPui&kr-z1vBMqMD`aR(u;U{7}}Ui$j+7V5Ucjk?EKfc z1Wu@$wWgTEJh;x^G8T=oCEh3u?e{JT-e$24Ln)@5_7|M$3eK#1r2dW0M(lB9+eo`B zdj{wLKQsgZuze>Gs$JH-Q)_(Y@EC0HyIX`k5Ly@upj#FO3v*Ubz9?uz;XZ;%=~}Xn zaFRvE9BtBobuNZqFzt&DR`B`Eq2>vcaLdlS17fvQk&yl_7HYkgAW=+?#7#FEv1?kP4*QBqz+0)EIf4Vj*5-c z98K6QA=aX3S!8pdmLy0qVhhzqO1Czqzye0zQ>Fhv34xW^l@GU)CbSgr0wN;Hl=C9Q zLNYpdln8<8bj0<@=NA=bRAtF-IPhytGFJ>GvlhN$6S+<0uHk}Z2eU3`3=L&zTf7;3 zV+fNB>*(?HzHk8YEl_Rq4YhjFL?{j-vGgEuhpLF#IufiPlvom7h6ra9Sd3_MWvcWc zZ4=6$QR>Rfm4DQiMIyDp`Glo&R!=3q<#>)ab_RXYvS!#a#UW_ukPbAZpNS!TidSJ<*9n82g2@Q1mV^OPF z7NQ3*QJZof6LlKLN1KrV`9i6eHyM6OBC-WIZx311vL0}) z>g>_ZaB_n-3YSeq>K9A1BMMrSpx_08gk2IAdCANg2^PJPFQyc|pelVg?&cw$MZxYD za3*Cy$6l{Dv}|%A9Hs`QDXRnNN)U9Taza^YX(_R|0U6VHK~3mL%6VwR=6_;)jH0F( zt#F2U5Qe&bv3`R{R!Q(jO~x#51N^OMJHI2PkVBaf2KfOLb#U zZ5oOxUosdb4ZTv)E=ro_sCp;uNc$SHH25u_#N|%~G-PH&N$C4eh8J(b<1= zw%`y=h&f_5fdtO{&9VF>Bv)a7+MzvSdkTas8?Y%BqZq}-fw{HqxEwJ35W`HK9vENlmLM1gpi``zst3q0~JMwD8DJpcO8xn}NP#|2dZ0C<*H z9=D|_`*=%|`O;eji6sy_VL1N0{Y>+GIXiI-eLk!_MRAbNv{%4Dy(BLuj{x z*;h5KnY#8BLpCKyYJVVBjTskAN!Ub`#dyWbnov!8FjuQXy$x76#rhJTjD)c9mzR5F zYv9&gAD6QljD!y;OhDHw81XXUKG|p==(#|#wD@V1`JD#5^zsiDX7bvlxkdcoQYMP( zmYu=hU0>wa7f}!8bY*(v7$1*#Qva#PI;?}dA3Ui(8H@VhykW_&^$*lzyY-W>=}xbe z57HW6FsD)bg2VURlP9w4#Xg8Chr587*J|?bO$xy}HH57jIqpy=t^{}aa5QnvX;gL^ zKpkxC61!Rq+e65`PVv-DahH&LSRU8}gj-%STa&1%*twFwd=rc(7X7ajdqXn&HwY)%6suS;L5;3#))3}3lAa@NRW1DSw0ARY!O$Fkcb}2GtEq${XS?#a+Y7T4xl_whY=3|`eGrtLBcq6SZfy=Yu z2=?@5*122^O*Jiz>dCth39?cQoU?2zFM1CZl1k;0p0|;)n^6zsB^)jBj>D5D35#0m z6VC$69vd4>HeGg?2sV~m6?lA{Zkux4E!%9=vqz5N3!kCM=(vZ?BqusiT&r@~{K!{_)QK4r0=Ldw)WJg zJv}nVmz(0SLF)e-M`>Q06VeT2ZTADI{j>jO{9+S5{9*fuL0-3oTqM_Cqq1KK`qKGP zn99B)G-9pjTq^HORmx*M3HOc>$vZNj76E*>p_47P$Ru<@Ud?>aWb>B}={1GHTm8*J zFu@U(#pn})-8K=+AMWoNBCxI$KR4Sum9xhO`@V`e)=MwC!wC_0zO+bU!IYKn2K$7m zsx$wDI`v-gvy0HC1$@4I8`RR)b5P@wDay)oNOD84Uh^I6U)>4$*&2E`@d<=rg(w7j z+%2F&5YEv$!8rcOo}f%Hp1pZ!ty(ZTcLNo{7Q9`JKSI-LXTX2Mxm(&7&u}GgAm4Uw zmw)5lr1?pZRpwoEa4vSjd8q&|a7oN+7~2^i>PH*%Aip!ZgC?%3P`j*fs6F4+JS)#N zdb;}NE)~c3qyz4ML4p;)RKvrH&d@4Ro1~a2MBkz#*l}X9BrU9L6EMsdX0S1-MVT0 zT+6sOLN6=G`?EMMeoXh1&fa{w(yn8S+;wn+x!NetTrMz^4Ww;*zFTuBl=>@?U45o= zJLiyKy&BU7z&)cKpER>kXhBGFX*2?mW}7IZ+BRl7#9LR*DA)G9ikxm_^+QZsm@cdC z!kOuUoe5j~i_Bi}W~;iflb8@dC}r!|PjRV01Nciu8Gw&vb*-HE0bafGH#F{HtMC)m zZzJER>k0d0=?l)cxo?2;pN94mxY8J?{2pDbBrcOVGc5$K<{FF1a8dgfp65P$CRO!Z&U`eGaaJ} zjB4MTO;Q^a5~ra5gakA0`BB?HLB}6i*WXdc-*Nce$*&uEOlSWkJ5p7xGArM{>Eyz+ z(wa8iIMsruXC38?2b>p0snLD1`3OS(1v>%%o4F*zas8hpE7l*N zq>NO_(s_upmGaE!68DVQ|EVWzB~=dH{`Cjf$Ly1IX?^N#s8lKAQCgmv?mVGU6{+7e z`3S_1-}x(Fu>gkv(ufDnxZ9KtgST{mVC=MhS_Q(Ez*3~ilrLvL(-?kRw|c&3snb2D zX4W&_)QN`jf?w9&l~5)__u|6CH1O;Yt5h{J<;i6#_PAeGD1&-`S&nN= zOxGsMoOhI=8-y9+7yMB7Qh%&s^j&h2YD9u!(p?Pdy&o%WqKtQg>Yo%f1JfZ6Mc&&X zuwgl;Ia+5OZiuopFIuC;+$8)y6WVuuHhEAxex%6FyF4B^C82>aj5o)Kk3w&=BD>Ua z1_QJ4rL*d!R|S#Jhe1a4pw1Xzap`tf%?XKOJelc)(3`aXMI zXFXs2Gh83qzCQy9`%S(0!=zd2$gw4aAc(6;u!h@EhE1S7hOiEPY4OsJCzDKtV1&|y zw`*SY^Zpd0P;a<^ah6QH579$8C?u&0(L)2|!S2Gp6vnqGUi3GKoyw8=;m%dG;UvZA zh9tu6&%xhS$4~JYD5H$0rDw=VLQehy6V#;R(^ybJ!4)*k<3^XWXh_U-qw{ER(h8oN zRojiyZ_YJ^`|xif|6GD=HluZx)1qgh+>S0p4%Zw z@5yy)E_azS?^<$K8A8I&%AbryZ_^_7Y||?nhqM?S9$rb=;@xO$y9#xKUmjioeeE1U z1E0QB-_cUnr$58zO{G4ac88HAA`7-j6~KNJ9?=L`WxlIYzm%&^ayXXOAdEF<>yEgQ zFwc85Y>a`lOp>1%!fLJ}_gJW|o@}0mv1JDXSv@~pytJ|DxVVuh-@tJ7%x;8H2=C>q znhA!^P3}^HPbo>0o#iv0BI+vAeS))vGQrV6acGgBc{mvE4+einM!GN3C8<+v1daO?t~h`cD*Qn2`^@)azl)t-BG&hVORFlWr6 zQ0ixEGUZmVlpPk4Vk4fA6XNCLZh=lz*?H40yA#V^5xvc76}t#a$vHUqa&fV7b{0I| zce7WzHGBXzc2f>iA^5aHtl3j*~FnUL?flH>ez{Ge{72hYB-IB%C(N+R8#mM zeGd069Tv^>Gpu)^tr;HvkX%15qTs=2$;10WkE5wQbXT%Il~+Vp;Rv2XP}%R`QDNZH z!t`VTM<3z@MpU^UR!DFe^_N_>j&=wY`qb^~Q6H00oZ<1O(1Vop*rF9Jj-(PJxq2LHAc< z&E7tyo#V+(y;nN7ODK*yoEY{=0+j=+__V_oIVlfU;YV+NW1 zD01kXSG~(ivxrqnmF44}M*%xy;BBtQKC}hkhovDAc&~5`YoUv-QIy1~W#T-f@RdNB z^z}zpa`p+Zv9Di*nyB%kUtxrOL(&-adTpZi>4)tgx%I7kxTlR{>UQlH7RSZbPp}mw zc9c`uTlXnIO^JO=F#dq;Ak@UzIZn#S>vgrYCig>7CGEKKno4G_ib}+lhSq@4n#sE6 zNB&ulRMTn#3sv`8{RLr|csOv>mWaQsprnPp2?_D%w~xH`4o3c0p+Hi`UZ!=@K!*9t z1c7#}zaFQuTu0R3^Ex~XUU46@El$ceHf@3M4mJ7{mEyrxc3l9%a^uy*AgnlFKhL1i zNH8%t;u!-Zngvit%PtT6@ujFl1JgfsjX&y)@ePjkAEBOWT_1MLMt1fjdS(nhU={bv zw1yFLM&^LPV}^a^%s0b5$nMaLTl%bDWqSPvY#iOg9T@)r$aAiIlEn6=@Mhx`4^3e* zE_-(qw~>P=DPF&^Conqt2|b56m~q;Ooa=~$9&^)8mVd|W+G3dE<==8VPr29jY!<$Z zl{);y+b(Bm7F=Afh`2wpSo?eS&1|1-Tw3tKqcr86e7G}x>)3MhOa)&M5w3mox5a5X zn-j2!Uwfqe1>N)21S|Uolrm^;qDyJu7{8TkdbE#gTxxsxl&eT(XsD*>_PTXFGo@_$ z|6a@ZkN-7T{;-c3_22iE;=fmL|3_l~9|i3H-peS-@b=SFUmwdqwn$HTXcg>{*`(NB z?2*YXomu46r%I9Gn=zxx&Ek-0OQc$IBhjUnDX_!DfKc%ebrRKvfIwxETNhOk;W9_{ zm(<1pRl!h!5S>5fb#?e%9Gnp_O?>~Jd+j~zGUt6INS)yC_xuT>Yy-hQ5S~9b$PC0a z*g79!Z*md{ND7?Y``z?MDya^tb=cc2nfC8hO~hHNXM>2d9inRA}rN}n@07*+^m9B#PUMi zyoSpe^r`8u0IM_g?djJG-ZAwJ?H35lFveGZUeCQD{ba#P4WC*4BVd8EPu9V5 z5JE#w+QB1W`KIsi!E%s7b59vyau8oJm*22@R5z=3hA8bhkKAB#kYDMSv0zgWy~9uD z!G~am#_#;Wm|%f(PwK(+5MRNUwqTlYez}+UV4AQW20C~L>jzO!KQ4I^*x&`bO#V=<&g+CKu%&QyH~I+&%Z=o^T2sKcd!F5%TV0pu7FK5Ds?W37lD6u!_KeEjGYXvxWD(%LfhopyoN)(UJ3D=Ha0^;iQx z?RESYyjZZLGda4~@M0yR%}ca96Hlw2?PJ4qLswvk%2wJ@Z~xL6E)!QEk(mADoOf&d z=xt}lsIW(rE?*?Bs6!5;l~1&d8U|AdyN!2;x|JSWiTm=RsQl2Vys60hjBD^J4tPzZ zCv-6vuk{;OPpm>3{jdSvPLAMJ?G1QE9i^8{-ohxv4T2fxu_7KcF|x8l(^ToDCeripzxM(FlVPqa3_rq&i$3O?A$ss>M?-0UlK~@j32?lTJEEiGLlj zpZaR`Ol$qL{EhlwpTo~D1Ixj&(JRIC51icxAKX9%4KDb)D@oKt-0=+US-oD3$5l)n%>&HPka5)=zuWF zSh$4J+^L;S(fe#1*(Zv@(Cset3a`y8CNhH+V>9HzPDyE@>jl4;8f8ac-Bm#A&tzY~ zc9+kxst;X?-~=e23YjSangE*rs5!%yEIGo3!lIAaXmYNgJ$NWBUX9By(fGo#);XTB zZ}VR_T52DLd>s7f;GB`@4NePX_S@q>r}s(~HI9{sSQibHUOuNNKP271wv`qA_!e$PDFeJY6TZD$nOS^zSkfB53>K@@ zK2@Xm2lRY0lj0_yP7b9tej#einXh^!P&s)qU(u z^_vZqHjUF4&4~Zfkp__VtzDO8ol@bNL}{jLKoH|v!Ftgfu(P5w6O!e%3*2I*H6w0rIoNGY*lpp z_O9q6rXnf_V*!UX$>m`yA0y%#dHJ4=BF8+cQA}e0bB+cT`!Q5*MfA2(;@WV#l*WOG z`GtTGb@Zf@f@h`yX=!#(iZ|6B!q7`S2Ngn3Y9$uu?2WXunUTt7eaO}lRktrEAdB2!4!6U@L!I% z5UY*Mu`(u*ie)~TsuE6J+jzi)PMKA1C8wrs z9>A|=sabKAPyAfIrl}drD!0Zx9?+q4Y@J)@9t;TA!M0{x)+u&x08r}0wlJ;e6uM^t z4t3;O(ybX+bqd_W0ckp#*7`N>aex*b`j*SbfOA zvtr4m4uA7v35LkgJ!ZyaR${b_02WF@(ISBeu#W-%28o3z>{oV0*qUS?k-DX-ANSMA ziwg_JOrxHpXUMy#({}YJ4pu@>Wm?RjkRWtt=_2!UVi1B;iXx+qz$c1VOpGJ6qe|Yn z2Z|lLBkq|)4BUB%!@Ci|MX1cYlAVaVp-8SW_F5fLE}^j7@7w)OCy__?@`%56kwW=o z0v{+vk+XD@uJ;gE!Oo14{S3X}qq^uP)N_);p8dn9_mi6bIr4pF^WBOi-h^QlPI##U zr#23fz&+N8BMl*rHkTI4Q=PmL-MKq2oh|g6AcH+L9X4 zCA^{rPq+QpQ9Hl8%(x~g?ysZFI3?UB=cAL+)%XQ1V1*aUHji9LMuzN`A9A}6Lzb~N zml<(Lj;?VdnVKHpXXF80@^R}OA)7+dDUof2xCI^Clr5%~D@L|2{j{20Z#@=|3OuGZ zg`h@3Xbgr9L&u>>*&!NaY)O4OpED&KV@eiA+g3EadcC}b_MxI)xETEbk8Me)25qy> zZvY;2je5Cid>eq*sz(g}0K&EiQ7F6;<8CTiqXW}vv|6QJLpCIv0OzMuQ;tOaY%nS0 zd5I*;MSoNXB3m{P3t9^E*8~Cmm3)~>L5)k}%E2FtaGitHA(c&x4W=?3eu8GT0)4g& zESn5=k*bifae=Ct=*=4CuIV;Df>dRzgd7WZKC3!08QyI^fanFE;NB#p&0c9FUNOE&TD=(kk*B1K#kB#d0=kB z8$!tycnTL_FiZUc37uB}%yI!8VCK7FfSgN*hYgqrKBjpw?}!3w5_r{y98ZXa9P{6R zK{BUGLNL1kN8kd~nW(&?!I{->Y+YanrU<+`LJTuT0NmA%yf<)=eT*5Z2c868B_Wy< zXd#;XH+YbJ^cgC6`se-U7~KX;ZN10UM~HCSG;%f9{3lf50VGq^*@SMfVyz5q4({{z zaNA7uRzdtZph&b{WqQWjhr`=7^MWoV?scJ8Y9|35lRo{T$aD|l9l!H-r4=2KX%@Ket4c=pTM<83~^M zImUPk-}1r{tea;pnR`onw6zSv#`uVeapr)G2cQF zl(%dZx6a{uNo`@i7J?n=UZ}O@Zsw5u>WHwA+oxwJ0ksnJ^OJTa4;-b4|y#C{x3mGA1jd z!ZuJ+K*;@Iv!|gf*i?gree8-EZZ>9|@WKbA$k!Ldm=z*&QY=Q0OiPRh9i&#V9&2>Rlkism=HWSf9v1HE^ABNONl$^zNL7rtk z1R@iRIF>Tqx+{Uk2d_kxWjiFA?9G*<$hH%~{^R7QK&)8-;&CEFs3q_nun%{j9h@OkU z{!wY?l{D-)L{G88)h#O~eRxj6$<-~RYCEJ$;r6pv0j+sgKY50$Tj}4eND5MXA*zZt zRGC38i$n>#heVFGOqs?JDRvKfAmgk#?hp#OFepPN%)Q7UTqm|e;Udy_1krfG`>t7g z*j3%?lKySLcz78pvO!7LfiDYUlM&x+5Uv&+djpomE)q?@KMVd`7_S%Z^a#E&kr2rJ zEv{Bj-H_M^2o~;s!8}b6SrGyjK4<-~Rj^4Bd^#Rt*izp4RZ-2cPZ%V2_6tz_Sx{sUsXo>qq+4$`!Z{Zw`_LPFZ?fhMCC4r z!8eA^g^_D){a^CpVr*~zU$c!8ZCF2ymCx@_ zs_bbqb{QksT@*9P#Kce$FgjQ$Qdmk^Ff=4kWU2`Y1P71(E2^N!D|3}i8>R9UK&91) zMtvAfv(Y>AQ)^2bAdjf0`MJRAH89Z8f;*+2LQ6Q`>}baK+B5(9lKcC8I3v1TwhBr0 z7xjsN%HI?hnf(b-q0q8%tIFwI+9GSd$k5a&bOa%}ze|VC9*LGW^4dbw<4x@nL`{fH zh%UJK6|Nlvm{4;I9gDz@My@$vC5h&}pEtw&s~)JJ((%2kH|Z*bHQp-Rs3e~uN^w(% z;_-;+?}-*ZL!4smZi(X((cf_j9BJo>4lL~|IC>U0{2|N3Q{hr61K7BJ4Sscr*A}_D z2R*7pRS3NlFu$wZ9XP$>25dur(z^k0yM=zlzN!{<4FKby92Z~NLYa|Oi|pFPj_Dzf z*+6&f>M5_eyqod2NF8)>3%x(>3@aRAlo9HYJ8O5&x3Xbx0k1;`!Mp@@?m?;`;RraO3zDRsW@E+^)XwLI`LZxMqFn zX*~A7YnN2+H9XE0J=@nkbj}`V!~X~-2}~3=yCJ;mT>>Ic^&W!VqUH+Y6=!>iCC(lu z;C|ea1crD{OggOJ%iwNP;tNqGbh-CZ$10*sJd`!Th=&TB-t<5PYCv=_k3Zjoi~b!# zhI%Fa$`KWYzZ>da1xg=$daG<;n>|=1#(3o`uQ3;m9o&wP5Ca3e2{5=EQ&uq9@KEZ< z5Cg>OiB0Ivn#dH#8rxUwx!uIJDJ-qjY?5D4C?ta{QjY{aKJ~uXe*90X+r15J;~&FuH|Xry`LO0x?-c) zdc<~MPN(6nz`-3ntNMsISdVU~;Od9ay{K+(nn zTk5JYyr-Y0Tk{u*I=#8G^TLbLAWc!)-CRxF-B3L(84V1>ZCyrbPvaO*7d0HgRCS5% zlqpPAZOXoCD84JjowAH-nKpaVgpi*uqnR?O*P9p%SeJE{30xTfR83 zcv(0T8P-oQ2K$~$3m&b5vm70Q4!SbFxoxcsMCS&Y>OIr?1enH;B!dfLMSPfe1I-S* z+OE=noEn$^ZE$8B)$K8Yl0&km`TWIpH%XK8q_`~U$<6iX=4z6I+FaxZw&8*%iIO$c zGKny_l6hdbxqYE64Nse4EJAfrJG6+@zCL1TW?+@=IyAL zlJ#Gb8W=TmP{Cz^WRcR_>4PjmenbG;N6J-NNF3e-M5#Ersn?YHyrN@JZOKok{vlhh1Lf9mLn)jX71b=SVcN zzgmCgP3#<7x_t#t2p5}D2`cO?y-HJkXCkHq4hn}SpJ^6-^G|c!yR}O;j_WiPsN^Zk z6b()*4L|@ms%yDlEyd~ySX@6?TyK7ZXY!u@3D5P3RN`_jRX21l z_EUW)2aaG6)tH@r*ro&y^>MyJ28vrH_(9f$#sRb5r7jqBMts3^TAvrJNJqjO>ZH)A4jPg6c1?R&cU zCa|`W>RVFap-!w8<{*6p#Xg{r>O1Z`UMx9DOwFx+{n6TQa-)3t+ldX!AwiNKp9Ty@*luD*W?|YHK^3L5_aF_II{mtR(LS`>R<;31>e-4=1q$ z$6j$UXtge<|LOfWV4+nXQj1+Hk2(u8KcM=o7llvqsf5Lli-6&6TG93Utkjffi+~@K zU(7cDToY!JSgzC*MX6?H%Ju|T$Kg&CflMr%g=1M*#Xk$4x;V(|YX~FLYRdT+EIdc| zJlea;_^Pc$n;SxyMk=szA(@aWzILg2T1Q!;OJ&;Ad%_)1Du#}0fqu#pyY?DlkR=bg zXox+q0;05X@R>SXeeno?c15&PE3!j0tvV}k$vkeA8*~NL#cQEf3f8 zYn1U#ZA^Cw34nHL@YehFD*sk0M+XAgAKcbzTm$#4MQeU0rXtCD85j3?t^Ru(Dv|dt}E&43= zXvOi4;96RqO)@c(jbSnpU$vNUi>{af$STyx({s1L*(2c=v{_H2~&km1#MC@s6d%e~6PUn*e+i{`}k^Za>+?nzf%4Zub^Gask!>^PQgCx?Q zE5;rs6SNsF&H=8>Cz(e%qq&l@CXhME5udHZ4m~znb(1~tPU?KfI)PQPh^<9kE{Gh{ zNvgrw6N$9YHAEw#f>?;O(M$>a>@Q239nF5a+-WUk?uNe$j5VIL9{_*+{X@Z!2e>s5 zdcei9$$sCRyFSr6gt3LUEuhQsIJD5xS^vHSm)GZ;sJWHlXkv+G*PbXXQ4kOMXj4~P zd||VY^3TRhs2tA3Z|hLqk_ex^R*$$@4o?-k)T`FWIuL zOI3|E(}Q{ESj*LLq@V?6((;ywMHE|id`^jRLr*ZAUK%B#al%?GA?7=^Kl~(kQ@u*u z(J{Jpc$ST=*qD?5#G?OeW4IkF>sXehJDfeWZDBMD_=x-o;Zz3p$#7u^cg|DnTJGTLV^b{_#Xqr9C*d4=}yL!WZxGz1Py# zWTWp^!g&eCrFf2`{9O+uw?Zw4v0hNO=_4SFf50g`QEkv4mqaD~f{30`Qhi~Xb9$^# z2soSOp({#A^LY@*JAWlcE+%3UnE^6WM9%&HXcLu>`>ui43^|}OmNj3Hm?L7h zE2(yy7FtK}sIH|Gkocfq4E>}`Vq0gTo|&l#m6wsEsHqHUU&^{HwLei>u`FZ04C!m9 zG99kpXnlmWl=6Vd!kH&~T9vtU@|}tX)_Dt+cK*-;uT8s~In~Yuzkwja%xm)SX+}`E zg$PZHGkH$kgz){Dx}yYXK2u^2U0&}OG%*|vrm$lpVvhk_&R7^5~m0PzPBxit!wfA{8mu<@Y!2IFJ9P;pmy}zQurrGT9-pX zUlbbGVDWRNhYp=-LJD0c>~6xn#KrF@t;qedz9PG>^;-r$c*bvPVW)K`Dzj2nF>x6~ z@U zoEkns-beUnOSjOCgy8=cEFs@Yr*d=g*NK-A>(?$Nte!ulz)o5RoO!=X8XRE!IG7H$ z5Koi!u7IIaR`kX}eW09_u11hj5#3OMKe5DNwa70yzQM56LufI<-cf^F&E^-m2fCV+ zn>LSI_R_6#9>=^^LMxo=D3cr`&xaJb)xN;jxw7WA#l8s?AD1OD-ID6_kS(gdVoZx{ zDsfJt@9;>p;Hv^-{eal*PS6!sQ9%MSv7QT;O!g3BxqB!$82rGIvEguX)`mzAG7Kz7 zr*$pA#PkoPA9&kdsy}9he#o(tR}jNa^tz>Qz%-%VDG<3RMDj?-fg@vjata}Tk1 z0aJ*>u>T_GzwvDy<7U1cKM3@Q^!*WDVD<*<>2Erf%#&umHGiOvU!>oXuDjcQ$Pg{t z^<5eKsh8Ri%nRHI324v!Uqr+##La1t}CF$Wq5-W zOsQEP#gLn0YKs-**XkMS#8kGuf@mwJxMR;eP|`xK96>d$C|w%FC)aJeQ?4r&Oy7wJa7GR7I} zMB9oZeQdylFf_|B(8o+wNk&AtapafHlqNkEs0#{Yf|oU!8}qAN{T#63t_${l=M<== zxWr$O$6X)z;+7tcy##d&Ds|wJig)L@ypT;ETj0&nTO-vK^7V$<8HfvZr+eJ+btW;F z_0kMJvm6g} zU#OgJiEbKFh!1rKCKQE6+vu;W!J*yV;6HIi@qoHFpV$!Ut?fp9zCwqPI!MA5eBg)# z!v9D)m*7V!w^ZwukT2(jzdO0hkxb2UG$vJWj~%a)eZJxnC%(S$(4vLyIA1U4Vq1Fp zV<^PqBFmN7&RQ+BEPc0^yR3TWZ1|1JD(Zbs@Ng04`A0%lJNM5Q6*=5lIAYV3iNyhL zJdFTql)|oxylYii8h6-I@#Y2i1w9>!@4~>)9q2*Y80Q2%)ue_jHr|G20u)Sn&YyOWX_6M93X7<{kYc3t z{G3gg_vR_k4>M_vPXaL-Q52FzA}+0Zfq5M4g-#W0I;AV#;Z}~4VD+~ic~}TMg*ci1 zv+^U2S%mele>Bq-lRdf_-H3$5!cu`@ZoHSz@{kk-tlYFV`uZ8}{H>9;V6&E({pdIU z+o{LvOaG(kujMfVQaoMcp3X`mlDXZ>*2UO^&QSarW1) z#1Cu337!0O`<~>e6&h*6X{`W?XDx$M_0f+{H|oNVp}kaMTn2K78lQB8fZ0d^;W&XE z+X}?VBRwR#1MgFGw`>fsZaJuvqJo5ut2<}hz(ED>EpMDqWfRLuM|M+-!=lp$+*FMHXlmT6S`+baHGBD%>)}e!~tr2lvtu zbPVw!)_)HcKnsKf?L)gM3^IiGlIeGZ=w<-6ff=CQ@PpRDz4QdFLVSq!pM!nT01-h0 z(QYh315s~EgZkjS#}H;Lzi6Nwq#@M{X$Uj+{~+v~f-?)d zwB507+qP}nwr$(&H+J&IHafPQbZpy3_ut>tRQ)qYQ`f;h+ef?hQ|nplzSfuWfEIMG z>YYYtJ*I!cUKC8PrgO#~LTDGnEA$OUx5^#mz$(lQnt#t89{4NV4!yVVUEvg5rWq7R@61BPNk#67@LxK^#ncGrA4!ns`H|CGJccxGg@0LZIXh zxLXh@#dYu1KDC`NqKY5@PTeIvt+ylXP_UylAlO{aWRY}ovCN6 zz^Rxz;!eOBEwDPKj-)gFj2Czr<4D~3^NbSMBhH1kE$U9U;2_?Pwk^_5V=?)}zJRkRaUs$V zmIXC&Arjy0vvTn{#SY89{D@* zOar)!)+6}@1ze5!BmD%qP!Rn`{s{}n74t{-33FjLdWX_C>dXN68ofjH5qu^F>_htw zJ0k-o#R!soq@ERs7odE{ow)&n&;mrBh=5Eny`rkv08sHMmyeWkPw^CF#38?RF398nYK=-qb%$NxJu~FzQ+b0R9W1(XzXNoF4yKg1LQyB4nXr zs%Q4n2I+lkL3>S)kl^tx^m-?lZwoW_BNW7#?C2~K8Ix5PaljYrg1?NO9X;NAsDCsa z5{jS2i#>W@ZE~2vOcnixuqOY*iG_d~)nGL+0oP78M#cSw+P0-JV#+kuogiVL~-0Hol7y1V~vXlSP?5DK}Fo98F?P~MrIn~1v zJIcAE$o}Twjkb#e-X>}IpCw9lQS)b8aMygIn1px_ch6L$;qqZ@I@EhbkYpOb`mApPDZ_9G@G2f`ps=}${J z@ku85&p11Kzv_0AXz8BvA;;XF<6jp)M<{A*)TkBf+LC5o)BhUTsG5ZMTTvzDZ>y{4j(u?KPRkv z8?i#!Ckmxp*KMK_Ntdv`dwY4Y>O}=zFstOvnNgMm;1A)cP3(xXAIi~>zU!}DK|NIN z@H+Vx*7NKnRnn4G-njD%C6DC&83$9V!R_Q0*hQGgqw8zr41-x!PGIKGj=`*c?n~to zkK9#e>FK^P-zgWGa;FS4=(n}A?en_Y2W&QPRkzS;3+lrrGe zw1u4ZD$9?pO1_mbardxE@HX;5MLLH)Or7D44`Rb7!*%pC(~Z1%4!)z4|+ zHn#Olpdl^=QVqni8Da-y9R%m49)bka7RV=a2ACx*W5M6n5APz@QIOSv=MHQCsZPE< z%8s3)c#SF-ZYi;6PK#VIoO*fU;u(k`%zdY5PrDHUPZepgXzn%nE60@~k1{C^3S5Jd zsHpSRxT&VlxuGY#QhZ=SM*y|LPGP>}-vse9FEE3+q`YAhfl?!;xHk6@qBY^}n7Rbc zC8y>BRnD#ebkt=vNW5nwfvCd##U)9PVg$K?Q<|R04hWhz`|!Sf%nZ9Sr%kZF6; zJZ0tVqVr+WG<$Sw8GA@L9Y}XtCW_?gpJD9j!~>Km7dfo=cmLL zunp%b`o5ancn9a=2F#o5DbvTz_q@1a9|^Rn8=%IXA-!r2AL>&nEHh%6`ke=7Kj@!1Xw} zp4ZF}Zzo%=?&Q*oZOMpZHQ%`T-`-GUu)h{u_oojZ64~^O)((1>$?yMc2|MLJC=5T| zi+1bkzKZTOi5inHrR@^VQC|8Utb>Q3b?s!yojhur&+;S>q8U&@1qIXlqkpA9+C zM_4$P9y`V}^)M`TCHT^0osY#nn?`|FGf|GL3Rxu}$<38L^9@Zo>&a6!NLz8QXHBTi zDsG6{C47C~yTAV6BtnF<&lo65y_tQTugj8k8W~izxu`TXQ=l&!Sh*cuynLvbyR*~xfS-Lf;#YQYlLTFPGnd-)4rd1H0DnI*!#Xy;AQ))PNXdd(6& zILwl`w!ObWxr|6k67#g-X2b*?_pCq8m)acP17Zd(AQ{o!V;_CI)Kf(*f@R9zR&Oz; zhkrimpD@*eID=_Ao+9iJr1^Tz^d#n;+wDV@58C<2{2}x6MV;~dY6vA9K_?Sr#o1Ml zbu*+MXC&6xjF-(|mK&k>0F8*T8pZ5Q65wOySXk`6bV$m#lqaw*k4u;7{G!Tsfe<}G z13B~{lY0=BGHN(J6vj4`Y#r-cVyVomryskxy{zI9=2mJRiN!~*S|gq}7EiB3N15iK z&$*rxfB1bXKiZgeiVin@;8w&|D@3;v!TKvTUxAik`_G!FtXt$>YPusO@Kr%&GG0RENvZ_2UWWQ?x@Y=0V=C>hMJK-$??j`-+~Qu?@AlL@AHiXd?;g#pU;_E0&!TjD4emCZx=HMF;i|#owxJV0kDrF5X?Ou%$^-gi@ejBdOjHI^U2%0Kb)}X}YnBC6AceSGOgbt9nXaTe^a6?aR7^S=fvh|A z0xS?ioGwNaBT!ijt(H<(tR?b{88{TZf?7-Ait;NO_a9s0j-*IGqsHZqC~V39L265? zE7g)XE_FnvtJD%Qu5?6YOKD39iwqGRDlP&@#a1w@PkB*gsM#Qm92z ziDgkKVmhP$5z`st8|@pdDoz7r5Z8-tL;bJf;9q(0p8}yYhE*H~82Asf=>HT77BQ~k zJV1VxeCyzU;4N?huf;cGJgNB{CK;n#Ynt$kLI@^ZChrkD3Ez~SSU68-8uogeZg82YfLk+fgMKVT6M^bq~ZslQy_8Oa|??ohMVe@^t#XFlR zzq@yDV8s}Dth8_iS;pDr^o#o1M$EYlp7YiQdjuoi>8W0C<-wj8I@5)!ucDQ4vU83& zcaJjUJlCGO@!X$sZ>SUqcIxIl)R)V&(ixKNg)${s^uct6lk9lP-ENd-U+W$(^bNzr zYZ)#ql_oSAuEpY)r+TdJHt_P-Dtq z4GboqJ|s3FOwoqwbJ9A4;?0zCV~%Fvk`&6bf$s7TnHd=^gCt;px_mC4uXLr(YkdQK z%G$Vm?Iew0x>Wn42P?}gqo@qe6-U4)ezj_#!QEIC7B(R^f{BQGen3+E{0Jf7d!W4V zvw{wHXa!g3sP)4{TV^V2J*`FGj#(eN^|Gi}G(vp-+Ee0*5znzj#pNTO84Qvt6vg!A zgqf^nM$U-S{zJv8CBYCvUnL-!`wW}*%I38Tx0}5Vc1${R1=l4ifCTsD1i3}rz@1h{ zh5xw{8$au0)en{)e?lGOrj^@pY+(WvA=y}MIJ2ggI&Wl>MY8Kcg^aq2nfQ2kbU;c* z5KVSYT$Xk5P&WY2pX58W>8LZN)TIl9ba=e{kRGBeDf989~?{1y_uK=A+^Tqzr%f4-|k_F%iu> z_fs)BQPK|MJNQ#E1yLMfhCiuq)KSVjA4NfYe)1RbQ^}Fqd>45^><+^(v>vGkn=_h; z^5TE*h5XQ*umZly3c~d$J*=PEOq>>4k=KjdW^`kIV^5p{ttbkj@>Bc;eGMPN7NE$D zf_oJnc%QBTOyavF@1#$8fYst#fIrJeBY;U{m*HLY>5$wgGO+uIs+ zcoYRJAb*E_N}(`{35-3eo>xlq=lHMz)QboiJPggxCHpgcWC6P7=K$Rx-}V#RXQ$FP zB0^fOOdmb~E?@zZ584L=pkAy`*_G%+0#Gm2r|p{kH$(bHs!#pF@@a}3324OV1N{v< z!38v;@xlJ4ogh2Yk|VV6xV6C4gy9-uz;>mJtQoaC?_|^t9GDb1;_$|oOY_#1qqBbBp?V#%xquEy_OCazrZsMR#FxoI>6Xj$ z3Syb{30-ZiR*S^E86b~dqKfso^<5+Du{9UjdcnR`hyt0wZk;MpB~pxlYc{VPR)v6T zHSZlpiOs%HCTeZUe{qBHw=-@x>kfS3>V%N z?}%mGPPte_0kZbr^5c2mFiz|vu8LpMARN}prh&q~HHJ(&;yofw6~1N*H&$FGvlC@ehJ^k z^^Kr69Gd+-qp~fl+CHzibkl}r2$;BCI%e%#bB+uf4!B+0Eqv^4b1i%vo*6c~3v1hD z0a|9SnJ)qfHf7t@jo)S4<&B>Te!^x**)PeXgq+tX2?DkouN*I#HbV1jhh+jqjZ_Ms zMWcb{8%Z25sWw6jYfEL{>SlA9FKh_{b{lgXFS#~-^J|Y~-%aE<5DDLtEm#~cc1wnf zYfkchI%a(w*BA-kvn^U2FMdn^(sD%deg?qecZ;ugwwyOgGALKg(?jY_5#T0_qxra$X`v|CnuL z;C@ar8{-Ds=!1>0$3bG0>2Ne;MgFB#Xtq5wPfK=vpTdvy2)2B6t1-V!kuPw z=!JyJX%i0PUBa|&7;o`Kz|3hA4=XKWSlUBgO1E>au%Tnuw%MRX(9CI*3>%Wys}7lJ zfkfCU^I^ZsUa1gSD%?i8Bm^a5{@Wd8EYR@pdkjbDCxi-O8{Iq=0-rGl2`6UmylSgA z{K)^q8Gg%z$v3YzOY;^Auqa;h zOS(2bZBAK(z;-3+iZ>W`G{$NUxI%3!FqkA9N-keNzJlDh;i#or8%$#!!x45Fzo_ZPd^7sI& z)KqX^zSjKZ^WyeTzm)hl>l@HFXSi3;Xhf6SQ^CDfpJw|4I56*1Icd^LrMU8%#C@r1 zO8hp2XO@`M&_|8c$d!h-W|Y>ot~XhH?iCn>=4SLF9p zQ&NDVPxANX1N!IS1LhSq+;>O)Ftl zt({3O$B)BWsebTF%uMTTkd&J80rN`==j3O~Ow%5yGF>9D@@Jh)%K(Tnz1>ip6(y6h z8PH~X+UYi)qS3Y=whq#+BEQ+LoJ8 zQEM+luA64g71uV}CVn8An}$&wZLj;xn^+B+YXcOcVquvGj*Z~_K#*=y@Pq?uYt)_w z#VgPPZm^ZODdVsXoGyTaB* zq#RlHiR zhhIK8lE}7)+JUAOYCB3`!-;qkdb{|FG?wLz6u<|f%YqLd>wwJ`s$$cB=uxrM8klY_I#|5)o-nx^BN^BZIA?`w)Z0Uax6 zqJn6s4k(G|m39n4E;t`$tUZLux+?v8A`P;jUO_}WS;U+wu53s{tMFP;i+fQ~sRf%J zD2&Xcp)6kEQpT)%8B?A~cF|^Y%qf|Ma@e32Yj;UsaRc{;(b^_?9lx zhCuRszcUa@Ix%|%-HN|`caA%KL8DT9+aG%k=+IEwJsG+V1Xq4CLE1-j@S@sh9NZ4~ zgBBwGN_J-27aaT!?+J&3MnWYd<(KykzoXt~89WT9f)*m>mw98^rwT8J7NYoyzjGU8 zf>uHclv$JVj=ZBAtcRIH4HSE0*ykC1499|ILNz3vMm41D7WGcM!`=573>*X*#0%$w zfr5#Gc0xf!OGHjY4V3cExkKDH81xH&g&{%~B>&34`-v2Ew{HgVS3Gb`akCZ9N2`b` z-HUC2rYm#y1kRK4utS6}blqKwd1JG&x<_E2Hzo0s_dMF}*7?A3!)3_rvI`wk$u@vp z0BvR_3zsfpV=c933K0`-{oI(IPtEvp^2VM~?@Z;6og<0bd+5ETSQ%~VBzNE-(Pd0w z{cx$KGVYk_>KtWr=Hj+#QLlr9uUI+H1$JReeqdIC`&}kNL1AXME&9TIAiu+}swd`P~!oRcOhY@%l#b#?bxug#SXGGpWw@RM}rMxQ&*aA9bT%px6V{RCf-X?7J%769PcIrCc>Nqt$oFGB@<>&!m|+Y{0`ZE7m1CiX16<-@#q3b zu7j4n2@$B`DS^kz0H%3sQuZ<-)SMaCW^dss>p^lXHj)&{-D-xRuxvCJwB8n4n?WiC zT1sJB9e}R`x8owg1xIt)a<52wfL>Iqe3k~vp-|Rx({3v65-X>5tkOf{6a2934D0(a znPfV<@AZjEu}qBx&oY;(wjQMdAAnMpwCY$`+Yb)ue4QcSUhSpZy#eFmly4o@D(}Pl zzBu_e7n|TahZX=#Bds7o{SSLiN{y3qid!-Fiej99`Ydolr}sqjSfQ3^#MsUnC083XO^m@K{ik5 z9k7PC&sLrwD;LpzcBr``Og@%bBf<(@&p|EV)de-4)?G)S5Unm^@uH|waVt`q$MR6N zX7TwGr?<{&b+Mw8S(q15m98!l&^Db%z%KW~Im0!!pW&kbi=zXuj#4_MUG|Uhy#K?_>}u%*=4yJqI*xWu3mi{ zlF&noR(B`L%Cin8ZS>NN@`8sV>{kWG+CZ&JE6I&i@0BHi)Urdh;ravNSM3*HG(>q9 zTyBfdZws$s0!F6>F0BnBrA-xZZ>uV#!q6NYEjR2|Oi7M>25qVii?K{+gj*2hftA$ z-=TKkn-F~9tFVTYYdrP49-)_g6GM;#QxIL?T@YNb|MD>;9Wu=19XibPYjkT=*eF}1 z-lfLsceDe61DSildxggO%p@He&eF^}qTi^r0aNODA6a&9DB97G%ZH-r4E_OpjnE|Y zlJKVwd3u9LgQ~rQrzY(_*0W<`9Y2&BpPRq1`(iD)2b1QcI>3VlT)*;&Dwy6#KDe@- z@n(RY$S=O{ib?0#p--@wmXL(P~~R zMBI0M2I*Y3I@1gql6>azUG8&^_(08}XA;#!@U5jdYfdLKtsTXzhSSnT5wET7nCyi7 z)`Vo48VUBGgRJ#KX(yB#^u^Vy#bP$^2`PDIR9#_#*9#hnenyJd{X5KgDTMua2X_c# z++~GQ_evjjtutcK;GE)9q(7b6cxUv#Pql{ePytM`A3r*kfBc~SzfZM)dd2@vAM(L? ztN;Fey2Uk-BX5Wq2@Va8jm&ILg8TxWT*I6kK?wq1!A#C%V$6zWMM;0-*VdhsXNNMAq21+mi%IAdyqd+DM9&+3`*lLLw z@AZD%&C`EJ}4+*;AHq!((P~x7&x9k&x4;y<3yS?SOyt$5!a0UlUm~Np{CJws>WO6R1oJS z(!pRytW9IFi(~n_u&1bz9uGA%;@yIcj@TFueKx?mGRM(7uvf_)6;4`}4pz_|6-u|G zZN7Y(#L%P9JypiHB@k8q>Hke5sgK9xH!3qnz$~`19kATq%<2rL4`*iE;~+d6le;G0 zRZOtru1sAzwMi9CmgNY5s_K=%f3o9DgL-c9+6pq3I1A6lEyRL{_Dx33J3oro)oS1X zNV|zRMgrmjx#s;L9%6?W`=hg5wlzkzMq^|NJiyy9g+KR*{UVe6v#>vK6Puo@!S4+PGHaJ#$ zgj^R_3uBEu{nbA<Z z?+b8a-h0hIhM5X%{nggn)>N8qsm@YJjEhIB#m?cRt+r`zKfI&gHA)}>51q&;uvPQv zt`yB#h%R3*+Mof&dq!5hbGeG=*Tr={pgBibFe?w;;^%M2FTxa*lh<}<=>%;e8$i6K z(K)iTxsMPoU|`_ekZM@Elek`blfAw92%=PZ*@QP-XZ)f_+Y`1Js;eluDyzr= z>_vX!@l!d}rGGx-L55ih1={FzUR6il+aw!`Bra^j3f>O>83JB1_;461gUPrYqcPW` zxHnAHyjQXgIh7|yV=g#eU(etXn_ZXRARpA-;OIsuvy(OAsCzXLQxAb}CUPnvmPi8C zmCg40QjkSoFPZ!~;xTXPjxwd#p9Jq4q<8581p(!uZ2^st#5`z=uqjztH?$erG-dw2 z*0NvO;4irML4NaiD+s;qkU-Z-I_Iu(B-5X^Ndu}6I5`xVEWlVk>vmMUtPmR3P>Z2j zZI%EChl-`CKXlE1krmR#Q!?Npc}%ezVPJ?;V(Mbmh#K<`6e#gZHg_FmH8H%ZI(qvy zZFaBjKRt{p+!=lj8K(SH$IDwxRd<7|p1CVjcfqpp;ybs{rZQUCB)mabw3PG}tA>Kq ze84|KVeKxucw^3W6wU$CF-aewMA@yVs2greeFSYJqlhT#SKi8>M5GJ>)G~yxdZCd9 zRQYjUSW93wxhGUcwxMUjl3)Ll($=yeU%iA=7~lXH(*7i-?UjbE(-N$7mE+jv|SWL$>ZbB(Y%rF?N%YcwxKNk?-( zdo4ZL1Lf(sdk=6QqsbwpCmmUu+A%u5!mb=7Kqe8#3DmL~x3+*~S+l2s6;h5Y@C zTWyhC<|=?KKt;Z9Q5rnNp5>Xt8N&P?Wq&7Y}cq zxDxX1RtDc}XIFV*my`8nv76+X#U>@$Rqt0upU|NRBjPhsRsAEV0N*kARazfXQkkM& zu|VQ6oLl&J zC1t+2`iNS#w=O>UYO?l{-9fUqB--4=UO0$)lZ#~1hiJC9BEI^_WA&fHJxu zdMHdLA$%DddKJR=o4{p~OV%|yoPi@8qdvt-IZa*BMw?B;&cbVaghDsErgg{yGmghm}8Z2E209qH4!CsOby{!<-`#Bu-gO&hI%m?!3M zj1tGy-ipyOAs>LXp$!6l=VyEz_!SzzrqlAiE zv`l3dDwwgpZ+n#vV@jPFpr-q)GP0yvp+gqUD5lsP^B4xNArUJ!MWs!K>h~%Xpe(kF z-QL1YfO1C_V;)_7_#WSC3x>Wi-&aFo0X+u*q^UeBRG;B4TtL@oOu=K*jAy8z!Ouj8 zQc}1{q;`-!NIVIexrmQtQ;?w&&|vp9&IT0GWXWP`0J8xJn>1X}Ji1&ED~w6?i}6J( z7ul?$_~d`5pc(t&IIad~sBlv%SXa@hN<}86DWt@hAlWIja7t;4(^znClpokFYFHK3 z9@6f!Sw*rcXc%*Wv?=TsO|F14`GMW=KWfQrPP!(P+Aps z3*K{@6`F`6qNJRv6v6^w)@Wtl(BtANbQ{@5RUi$UH(zNstJ*}-hK!nJBW~)?YAs8) zeYa?1i#k>%wUg!s%)2wudm{xJEn0R96bqzD)1#c|5^(3%ff!|*Wrv^DGDgQ~P?lSz zG;-LhG?Rqliq;E&P z+PxtQ#xvV6GenbFn**9xt(iPJa}J8NzIgn4x4L4*h?xD(|Ti|VU3{P=>q(^zU7r1h-Sbl)t zT^cB^-PT&6QJttLTHTv)oV%ggRo0e88erJe^MKEIAs`^YYn4hN6Sph^ux0EY0x6E8 z4^5t=TOCN33DmDZrUOtgsH|-mGb7v2i;)1je!@Cg*Xpm_+IF{5o_{N`!efk{ONmv) zIjOEv{hE^Vl-`T4!|ky>#h`L6?{ZPF=;^W)Q)5$UX==1_IE?J{&0bU8l&!+Tn)@;_ zuuY^z8qMLgp@aBVB%j9dA8+4Ady-4v5bf;sxTBl(7=yzRH-L-y#8fJGWXLx$C#eN_ zoHl13b_`EVp4(JZlf;7eL`mhh;>b{Rr2`ONE*zVvZ4&`ex?3#*n51kmj*XQlR*XXL{HwkU{<$ZGj4Mt3eOv`k;${QVs$M|jR^ z4QTD^yCUmfRZIX}IUJL*(7 zH(?>1#6yKP&5ASq)jd}5GE^37Ud3BZ*@iA-Uj4Ve^^X;|KkC%Cyo+bo*y_%dR#*7+ z`~Z4yxJUCz9e4goVscF_E5hbDNG$4&Q3|X_K-y+cs6c~*U-FF2-bAi_hUe=vqk}fb zW`FLKP*U_x(8>f~2XmaO2P%8A4Kbp&B+^RY^b=#szEQ%OLG14fV|7dREySxT*vrwF9$b^9t=`Et<_bh3VXx0 z&Z4%Tp~aH3&I;@HVnFD_X)&HhU;~FSdBTHj$n9NZO1gSx-vi5aR@l`O3FF_IN952M zlC?Dfie24KK1;G1?w@gMMU387NRJ1_f9oXO!PB#_2+~>vd`uSJo=393D8tpuB@Lm* z)U6g)jl$AgTD~TJ+oxpRYxRfSyK`&xg9X|dv$cj>sx@cJCcl+LXu@EE=i9k?EDRjKlHv zq+GMvA#m%3os1)U=IkwodV4{P!C|AXK5MKdT>`d~4Mh4y^EbyhqET4tul&6%g-^v2>>NX}mts)-ScH$te!YQlx|vU{#aO zzn4=ek=0^KFvI=(Rae$l=jstqJ^d|7$-w3MX*HT|St@a>DaLY(f10WXRwgn;UU&rZ zW09EX55nJ~dZf42VP~{}zg#zdSVsd$!L%!jJO`1GSw`U;5N=Gaf&lTE58mc1}~d=NjoD4QvK7Gpj%_Wz6VOjXJJ zm?A-IL)G(VhUh%R%(Z2-KFrZI6Zt^v$A0QbK5-W(?rEq%Y5`jP@EYg4h%+La@nDM!$*kjHG|2}%m_zeT8pN2)`w_=O znxprcW#VQ-&Yc-u?)Wniu=+v&Y1alNT1w+gDD**RoN;O*oCa;2dEEQkk4{d6VFxVD zARQEu!P{9YTQONH(jca_wzqiOn_R#hc4V&6m1C*me}ZD$!1g1Fg34P8a+{$Vzr?3r z#Rww`xteVi{Gb(ZB6k11N37bsCyC8~@z-)=o>AtA8mwAk)Le#fveivqN1jrKxwkor z%%9R49Yy^Kl)Zu9F$7=C76;1MJ;zO+=!k$F{3jzsBVG$w^0s6bt{iJze+Tr@BVQEJ zuXqQ36S>rR0~cBkE|+&g)ymtS?l)mscVOC}NQ>iS^Wc8bn<#70pT=zbAlrB3;QKUy zbCF-~qJxXF-fpGroP*lU5_+xJuAGU33uXEb{hsm2a2R71nNZ0-;8(PX-=UD1Mu*Y2 z@ZG#nDg^j-0m~4MTt4vBrlK$if;xlE!88PmkR%T0c00`Y?r{l}d@a z%b-#&IA(^If{!`*nf!D!CF(Gx<2CIP z@munfy$n~r}_L`-e(*NkMk4*xi0d?LX&Aet2gI5A`CWdOU79gm5sAFl|eAa z_cK`mp(b0(xz0rk`2{ap4?P{%|0Pw5Ts2{8nTUcrfOR3&}P3XsBJr4H9a>=Xs_w{MgM8seC5)tp3P1(LC)c* zI7#fLdT_E9*{D5@#HnTv${K-APwb;eg+U*RN*{s?_$>=qq|Ajf)c=uT#-pDQw}+w+ znsli8#-KSs)bQ`7lb1VoYGOlc&%9<#);^wwM^oZhuJ(QLuw>74@TIi!=yxFj7!~y* z8YB5<;V4TP!^VIhDqhM<=crO1?{i5?*^`^Wv5JKVY+!%5{v@Qb2i#b~1*eq)(J~?V zN#@3E4T*%;%DtJ6`mqI|q1&3M0}JgcR#NQe6~(8qg_(&=AovB;z`QV0c8z4Aix4|W zM7##%Aa=+@f+F-C6;R`?!Hi1bHkBLv%}qCY)0{JkpLR;F@lLOCzC&icL^ddYxZwY zswEn;nzpA>T)(pY9&ZN*GMgzOt*0|~qRXEKHbzlhrH|VN`SCauw*%-^9r2kfYh`gUL8 zjwT^MBxVJrI}P;4;i&btpS2tBbno@fy&J3RE^sRpsSt^1(C*Hp8-i$H^IoO0GOxr> zD@<1KK&Zr|9l*sC;U9sJUrg);tEqYkJxyk$tgyiyrHc<`Uvl2u0BNT)Wm8)*)-kl~ z>WHHo2yxu&!M(Kn;IG^l{-IQ4IAUQy%eY$v^y3?W|Ii!I*3t!e6j;J=?#~T`hQ*_P za7YaH!a{FA=PXSO~d*k zmYjqRyw}N0niHewl}3D_nvaa4QSP-b{dgy5M@)sq0AJ7q2+Nd?K)SXgl#wZbxqzQk zuW^U*W;>^4i3W=Ho1Zp_lqIbv1|Zwgufy#_Kh-giFl=FlTsJj_;Z5@A>|ZRpIjm#p zJJ)`x$Iq31=>Y6fejGk<-Gt?#%7D-6>NSmRxbRr81lRw}`HM!gf60uxTVn7xK{dR+ z@W*bXs(+N{UqYOCHtAEIt6vD!><)sUr;>a8t}>r{ zU(ou(S?c)?MEckTPU3q&1Lf&$tba){xe^Z{2Om0DMOf#jALJ8WbaTn@8=*zdx@rhOB;_wia_f{C1Wu- zk_KTsHAQKrr<)z*K)+UQQ!LGt(%!G{NF*&lU@V1wWk&G#rJv%U8BZb|Q zRe@fOGwskw?f*8F)URsTY%199_z8e3X?ii8a0gixOEeJz3`9)td01Mu(&YEK7yx=o zzt=V$3C{KH2+!#^p;o!;i@yztLT*(hJi&r?&vK=WwmM@BWWXIyUKn3kEk8%0w?vzr z(&m>FH8PjRD?_Nk6sAM$S%^ksA($2D!&y}jk4;hNQRE60b5XUZ8Jl585SJAmWM^>M zB39+O>rg#h`e`totyK4hn;91}(L3O{a{A+DHh5-gI{jfd>a63c<(BAUN+^`A&fh=Mnzn;nIu-!}*xt|o6v`no>$ZVm)Hs7_)m5a`=N72MI_z+BR- zzG!ANVSB0dwjZ#AJwlHvWlSD@mK@G9O2Fk+|40nMcXQ^a0(}?aKW(*$Ls5P3=iV3xHz`4c9)4-Vsrp{+=28-t15avo72KBlCZfI-BkMuG? zxN%jCFv29POX6U0n=k&3Oq444reYuWV63nutk)gW<_&igt!EP7K|mSZRiwUUhT~4- zGt_+KX{`|Vc&hAwu#t76>A1Eq!tisX9l$!yF*~QFvRZpNHDP7ndL~22Q5rJWR52*Sv>5 zmvZ^e0&^@ujUIJ)RWV3fF}MtDq=cha;ZEwe#$Y0qWg3-}m$k}Nj982mh+*76brBq~ zd{33TZwhJnL^Ux|fc;dM{7T@)rUbqdzm^U5GzftzEfWQUIY@l&%Y+MhSB2;*k+G`^ z^G2(?fLFRe?<4aMY5GCur$v71`%DUY_wsWvrCq;{eeOkk-vNIdK2m+|Gq+YgFEV21 zWY}&ZF-eUDb`k|r8go&oJUpI$?qh|jmM?$b$;J9~B^l^+O932?lhuJ6BRR~nUkH{l zLCMWQa8)Cl^YnjYSndeU&~HPHx}i>Ek@jHkN%W}%L-B^k(xJ3Pbx5)J{4KY`wGP@V zoiM#C{NEDUw{zqn*DLWmVe2W&5<=lBbAM%Ldem0Bj;?vEtUZ_M$Mt)nk5<1Kyx&It zKgRAUy0R`z7jVV4U9oN3wr$(ClZsWbZQH1r74IY!YX?=?Nd+f=|2we8K zzxloIQ`#gtPN3N*JD#_atUAj@Mx6{!qSKo0lp^$~rH;-i^&5#B2fqX~a6sJ6U`ouL zN)r_6f-uYM`X044cpM&~E%$w}^v^BYpJBDt4EL!2nX&I?Ne zm{;2gz8`l$0Hp}{_qqQ98ew2c+}`_1khk3E*V6M2JXgNfd?n}_nJOXlZ{vYyx?s>k zrNacH$ArqoB50#SUd&+lS!dHEIUR8=$7N8F5K@aty;GIYw)~gzo2cgTwHhL~K9xr+ zCb}B5U!=!Ra4C$H+plQ&v2t8A#-g=x-sq+J8h!MczgnFK2yR&!e}T0g>TVTw8Z^qj zQCd<#FEO3J_4Wf%N`Kom4@=qM3(&;sW<4&;5nIrjnH2 z%c{*#WV>HnY8#OU!n@T_l&Nm`Ry}@$Z^djaC+fDXZazCWpYsEz0$kxhp&eSo*5Fj4 zK6&*3tVJ|r!DQyN`4Sp_GwMK4CJ^Od)ar`gjEcDuS;2^oa+E;cD1?`isx)2>+S+4) z_a52RBiWs-nQahdFaAzV>m44iM-3+TFe+t6Zc6>aGJOssl6pr{SK`mj`Hc}Z-R$LcHatBVs}WoSasvE1|J%Y zEzn1iE_c{O{Z5yeZ#WRZG{y3|7@l4rp&-JGL^y-@t<)i+IgXm?Yf>vLVRZ5g z>|8xx$BB*7w=_dp+Iu7S>zortB|7$x&@uj^<*txSyAo^=`EvkbIGd^oui^wd*gML9 z?biHL;bK!<*dg?(sww?{scP*1PgSk|Q&lUo@8PyxY18eg_+h~&TbVPfU`?gC%vd(f zK_rvrk%~E^B`S()i35p~E-8X~(2`Ds31y*|oD#Nno!)$XpnT_z4j#A~ zZ~QfcE07gDkKrS92?ajsdnXo(V|g?VS|g0>jR-RYUz3RfGBuRP6-*KT)-Y ze^E7ze^E8ee^IruPgHICUsNsNUsMhJUsR12+}Z3eM5sE{-s~Uj&=p8N2WKoELx7{e z`u6iPawvPBj|?FH)gx;t2mIE`KY2(j^r@v^8Nd+w)EX!Pa0o?dc`F{`1rHwkLmKK1 z^`3pL3^{Ker~?QHO>PR*0D!L-!W+;4Sv!&u7|=nG+tg6l2mx`|3y@6cAomVs1Oo;j zUdIAF0~&~M+Zfh>4Cvc2h^a#d)OPq#2B?J&TKx?hvaB0K)1d-(Iv8W>Faaq$m=Wqw zLGauAaCM(%PDdlW0TU3#!5E`U3~=eNkJ_aMAlV$Cb;%eKZhmVWS_9uV`->B55BZ*P zz5S1pHWz;j`^q043~N9SH0=1m>{0^wJM80h836`=27Pr2A41uD*Dq2ANIM8)>o5X^ zEs#*paG+Z_A=hEa`cv{LFmoz}iG{Mv!9ueN0VcQj)yEzF* zhZ!-R@z`7jmrGx61lsghbGZisLOADuA;B)|?JPu54~3d)_N*=#x`x zDc6Wa__Wn#k|S77n##*;FriPwMW>r2algYrQ;Mds#Qj{J=SDD3+0bD~K!Zqn+F?qN>u9s**RlQK1#eENzg4MaT4yDn=bpe)^RwYM{w3

    JE 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 z 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 habX8Ue}IURiv%6E_3+|&n608`Hy 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⪻URlY7o4OZUVbHtAUBnkIBY1^*twa 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

    lgY>1H6 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RKau%I~9@` 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

    =gyMf~7{7sE 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 fFS{Zs@Yv-HC4K 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 MGa4ZTyB4tj1LzeaDF6Tf literal 0 HcmV?d00001 diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 00000000..7e896c52 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,75 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/hemanths/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +-dontwarn java.lang.invoke.* +-dontwarn **$$Lambda$* + +# RetroFit +-dontwarn retrofit.** +-keep class retrofit.** { *; } +-keepattributes Signature +-keepattributes Exceptions +-dontwarn javax.annotation.** + +# Glide +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { + **[] $VALUES; + public *; +} + +# ButterKnife +-keep class butterknife.** { *; } +-dontwarn butterknife.internal.** +-keep class **$$ViewBinder { *; } +-keepclasseswithmembernames class * { + @butterknife.* ; +} +-keepclasseswithmembernames class * { + @butterknife.* ; +} + +-keep class !android.support.v7.internal.view.menu.**,** {*;} + +-dontwarn +-ignorewarnings + +# ------- FastScrollRecycleView START ------- +-keep class com.simplecityapps.recyclerview_fastscroll.views.FastScrollPopup { *; } +# ------- FastScrollRecycleView END ------- + +-keep public class android.support.design.widget.BottomNavigationView { *; } +-keep public class android.support.design.internal.BottomNavigationMenuView { *; } +-keep public class android.support.design.internal.BottomNavigationPresenter { *; } +-keep public class android.support.design.internal.BottomNavigationItemView { *; } + +#-dontwarn android.support.v8.renderscript.* +#-keepclassmembers class android.support.v8.renderscript.RenderScript { +# native *** rsn*(...); +# native *** n*(...); +#} + +#-keep class org.jaudiotagger.** { *; } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..5fa8503e --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/fonts/circular_std_black.otf b/app/src/main/assets/fonts/circular_std_black.otf new file mode 100755 index 0000000000000000000000000000000000000000..c62b210c51fc6b0a7e4022ac9dd54d50cf5942a3 GIT binary patch literal 74500 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�$ENekd=fCSx(51l~{o+rz#-JDFw1p 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%0D3`R&67{=)GDS8?p!cah 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 DB}TqP literal 0 HcmV?d00001 diff --git a/app/src/main/assets/fonts/circular_std_book.otf b/app/src/main/assets/fonts/circular_std_book.otf new file mode 100755 index 0000000000000000000000000000000000000000..3a1f1ad82ef9ee891d7977cd5f6736404cb3afa1 GIT binary patch literal 68940 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 bm)u+K19{O;?hmegZf|)^1FfGBrz`&-FR{+x literal 0 HcmV?d00001 diff --git a/app/src/main/assets/fonts/product_sans_bold.ttf b/app/src/main/assets/fonts/product_sans_bold.ttf new file mode 100755 index 0000000000000000000000000000000000000000..d847195c7600a96700df62b68a5009be200f234d GIT binary patch literal 55548 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/index.html b/app/src/main/assets/index.html new file mode 100644 index 00000000..115106cb --- /dev/null +++ b/app/src/main/assets/index.html @@ -0,0 +1,57 @@ + + + + + + + + + + + + +

    Phonograph by Karim Abou Zeid

    +

    RxAndroid by RxAndroid authors

    +

    RxJava by RxJava authors

    +

    Material Dialogs by Aidan Michael Follestad

    +

    Calligraphy by RxJava authors

    +

    Android-Snowfall by JetRadar

    +

    Android Sliding Up Panelby The Umano Team

    +

    AOSP Support Librariesby AOSP contributors

    +

    Butter Knife by Jake Wharton

    +

    Glide by Sam Judd

    +

    Retrofit by Square team

    +

    Material Contextual Action Bar by Aidan Michael Follestad

    +

    OkHttp by Square team

    +

    CircleImageView by Henning Dodenhof

    +

    Transitions Everywhere by Henning Dodenhof

    +

    MaterialProgressBar by Zhang Hai

    +

    Android In-App Billing v3 Library by Henning Dodenhof

    +

    Advanced RecyclerView by Haruki Hasegawa

    +

    Android-ObservableScrollView by Soichiro Kashima

    +

    BottomNavigationViewEx by Ittianyu

    +

    Swipe-Button by EBANX Team

    +

    Font used(CIRCULAR STD BOOK FONT) by NIELSON CAETANO

    +

    Icons by Austin Andrews

    +

    Croller by Harjot Oberai

    +

    Material Design City Wallpaper

    + + + diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png new file mode 100644 index 0000000000000000000000000000000000000000..924099d542410334e9e099785a989a2da907a5f6 GIT binary patch literal 60177 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 XG?y2jmDV4DfWLERP4$cP2+{useNCxA literal 0 HcmV?d00001 diff --git a/app/src/main/java/code/name/monkey/retromusic/Constants.java b/app/src/main/java/code/name/monkey/retromusic/Constants.java new file mode 100644 index 00000000..2252315d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/Constants.java @@ -0,0 +1,48 @@ +package code.name.monkey.retromusic; + +public class Constants { + + public static final String DISCORD_LINK = "https://discord.gg/qTecXXn"; + + public static final String RETRO_MUSIC_PACKAGE_NAME = "code.name.monkey.retromusic"; + public static final String MUSIC_PACKAGE_NAME = "com.android.music"; + public static final String ACTION_TOGGLE_PAUSE = RETRO_MUSIC_PACKAGE_NAME + ".togglepause"; + public static final String ACTION_PLAY = RETRO_MUSIC_PACKAGE_NAME + ".play"; + public static final String ACTION_PLAY_PLAYLIST = RETRO_MUSIC_PACKAGE_NAME + ".play.playlist"; + public static final String ACTION_PAUSE = RETRO_MUSIC_PACKAGE_NAME + ".pause"; + public static final String ACTION_STOP = RETRO_MUSIC_PACKAGE_NAME + ".stop"; + public static final String ACTION_SKIP = RETRO_MUSIC_PACKAGE_NAME + ".skip"; + public static final String ACTION_REWIND = RETRO_MUSIC_PACKAGE_NAME + ".rewind"; + public static final String ACTION_QUIT = RETRO_MUSIC_PACKAGE_NAME + ".quitservice"; + public static final String INTENT_EXTRA_PLAYLIST = + RETRO_MUSIC_PACKAGE_NAME + "intentextra.playlist"; + public static final String INTENT_EXTRA_SHUFFLE_MODE = + RETRO_MUSIC_PACKAGE_NAME + ".intentextra.shufflemode"; + public static final String APP_WIDGET_UPDATE = RETRO_MUSIC_PACKAGE_NAME + ".appwidgetupdate"; + public static final String EXTRA_APP_WIDGET_NAME = RETRO_MUSIC_PACKAGE_NAME + "app_widget_name"; + // do not change these three strings as it will break support with other apps (e.g. last.fm scrobbling) + public static final String META_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".metachanged"; + public static final String QUEUE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".queuechanged"; + public static final String PLAY_STATE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".playstatechanged"; + public static final String REPEAT_MODE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".repeatmodechanged"; + public static final String SHUFFLE_MODE_CHANGED = + RETRO_MUSIC_PACKAGE_NAME + ".shufflemodechanged"; + public static final String MEDIA_STORE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".mediastorechanged"; + public static final String RATE_ON_GOOGLE_PLAY = "https://play.google.com/store/apps/details?id=code.name.monkey.retromusic"; + public static final String LUIS_GOMZ_GOOGLE_PLUS = "https://plus.google.com/104046235912044592643"; + public static final String LUIS_GOMZ_TWITTER = "https://www.twitter.com/LuisGmzz"; + public static final String PAYPAL_ME_URL = "https://www.paypal.me/h4h14"; + public static final String GOOGLE_PLUS_COMMUNITY = "https://plus.google.com/communities/110811566242871492162"; + public static final String TRANSLATE = "http://monkeycodeapp.oneskyapp.com/collaboration/project?id=238534"; + public static final String GITHUB_PROJECT = "https://github.com/h4h13/RetroMusicApp"; + public static final String BASE_API_URL_KUGOU = "http://lyrics.kugou.com/"; + public static final String TELEGRAM_CHANGE_LOG = "https://t.me/retromusiclog"; + public static final String USER_PROFILE = "profile.jpg"; + public static final String USER_BANNER = "banner.jpg"; + public static final String APP_INSTAGRAM_LINK = "https://www.instagram.com/retromusicapp/"; + public static final String APP_TELEGRAM_LINK = "https://t.me/retromusicapp/"; + public static final String APP_TWITTER_LINK = "https://twitter.com/retromusicapp"; + public static final int CAST_SERVER_PORT = 8080; + public static final String FAQ_LINK = "https://github.com/h4h13/RetroMusicApp/blob/master/FAQ.md"; + public static String LINE_SEPARATOR = System.getProperty("line.separator"); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/Injection.java b/app/src/main/java/code/name/monkey/retromusic/Injection.java new file mode 100644 index 00000000..481613ff --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/Injection.java @@ -0,0 +1,23 @@ +package code.name.monkey.retromusic; + +import code.name.monkey.retromusic.providers.RepositoryImpl; +import code.name.monkey.retromusic.providers.interfaces.Repository; +import code.name.monkey.retromusic.rest.KogouClient; +import code.name.monkey.retromusic.rest.service.KuGouApiService; +import code.name.monkey.retromusic.util.schedulers.BaseSchedulerProvider; +import code.name.monkey.retromusic.util.schedulers.SchedulerProvider; + +public class Injection { + + public static Repository provideRepository() { + return RepositoryImpl.getInstance(); + } + + public static BaseSchedulerProvider provideSchedulerProvider() { + return SchedulerProvider.getInstance(); + } + + public static KuGouApiService provideKuGouApiService() { + return new KogouClient().getApiService(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/RetroApplication.java b/app/src/main/java/code/name/monkey/retromusic/RetroApplication.java new file mode 100644 index 00000000..cc2abeef --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/RetroApplication.java @@ -0,0 +1,77 @@ +package code.name.monkey.retromusic; + +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.multidex.MultiDexApplication; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager; +import com.anjlab.android.iab.v3.BillingProcessor; +import com.anjlab.android.iab.v3.TransactionDetails; +import uk.co.chrisjenx.calligraphy.CalligraphyConfig; + +public class RetroApplication extends MultiDexApplication { + + public static final String PRO_VERSION_PRODUCT_ID = "pro_version"; + + private static RetroApplication app; + + private BillingProcessor billingProcessor; + + public static RetroApplication getInstance() { + return app; + } + + public static boolean isProVersion() { + return BuildConfig.DEBUG || app.billingProcessor.isPurchased(PRO_VERSION_PRODUCT_ID); + } + + @Override + public void onCreate() { + super.onCreate(); + app = this; + + // default theme + if (!ThemeStore.isConfigured(this, 1)) { + ThemeStore.editTheme(this) + .accentColorRes(R.color.md_green_A200) + .commit(); + } + + CalligraphyConfig.initDefault(new CalligraphyConfig.Builder() + .setDefaultFontPath("fonts/circular_std_book.otf") + .setFontAttrId(R.attr.fontPath) + .build() + ); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + new DynamicShortcutManager(this).initDynamicShortcuts(); + } + + // automatically restores purchases + billingProcessor = new BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSE_KEY, + new BillingProcessor.IBillingHandler() { + @Override + public void onProductPurchased(@NonNull String productId, TransactionDetails details) { + } + + @Override + public void onPurchaseHistoryRestored() { + //Toast.makeText(App.this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show(); + } + + @Override + public void onBillingError(int errorCode, Throwable error) { + } + + @Override + public void onBillingInitialized() { + } + }); + } + + @Override + public void onTerminate() { + super.onTerminate(); + billingProcessor.release(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.java new file mode 100644 index 00000000..7c9eef61 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.java @@ -0,0 +1,71 @@ +package code.name.monkey.retromusic.appshortcuts; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; +import android.graphics.drawable.LayerDrawable; +import android.os.Build; +import android.support.annotation.RequiresApi; +import android.util.TypedValue; + +import code.name.monkey.appthemehelper.ThemeStore; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroUtil; + +/** + * @author Adrian Campos + */ +@RequiresApi(Build.VERSION_CODES.N_MR1) +public final class AppShortcutIconGenerator { + public static Icon generateThemedIcon(Context context, int iconId) { + if (PreferenceUtil.getInstance(context).coloredAppShortcuts()){ + return generateUserThemedIcon(context, iconId); + } else { + return generateDefaultThemedIcon(context, iconId); + } + } + + private static Icon generateDefaultThemedIcon(Context context, int iconId) { + // Return an Icon of iconId with default colors + return generateThemedIcon(context, iconId, + context.getColor(R.color.app_shortcut_default_foreground), + context.getColor(R.color.app_shortcut_default_background) + ); + } + + private static Icon generateUserThemedIcon(Context context, int iconId) { + // Get background color from context's theme + final TypedValue typedColorBackground = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.colorBackground, typedColorBackground, true); + + // Return an Icon of iconId with those colors + return generateThemedIcon(context, iconId, + ThemeStore.accentColor(context), + typedColorBackground.data + ); + } + + private static Icon generateThemedIcon(Context context, int iconId, int foregroundColor, int backgroundColor) { + // Get and tint foreground and background drawables + Drawable vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor); + Drawable backgroundDrawable = RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_app_shortcut_background, backgroundColor); + + // Squash the two drawables together + LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{backgroundDrawable, vectorDrawable}); + + // Return as an Icon + return Icon.createWithBitmap(drawableToBitmap(layerDrawable)); + } + + private static Bitmap drawableToBitmap(Drawable drawable) { + Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.java new file mode 100644 index 00000000..85e9c402 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.java @@ -0,0 +1,77 @@ +package code.name.monkey.retromusic.appshortcuts; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist; +import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist; +import code.name.monkey.retromusic.model.smartplaylist.ShuffleAllPlaylist; + +import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType; +import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType; +import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType; +import code.name.monkey.retromusic.service.MusicService; + +import static code.name.monkey.retromusic.Constants.*; + +/** + * @author Adrian Campos + */ + +public class AppShortcutLauncherActivity extends Activity { + public static final String KEY_SHORTCUT_TYPE = "code.name.monkey.retromusic.appshortcuts.ShortcutType"; + + public static final int SHORTCUT_TYPE_SHUFFLE_ALL = 0; + public static final int SHORTCUT_TYPE_TOP_TRACKS = 1; + public static final int SHORTCUT_TYPE_LAST_ADDED = 2; + public static final int SHORTCUT_TYPE_NONE = 3; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + int shortcutType = SHORTCUT_TYPE_NONE; + + // Set shortcutType from the intent extras + Bundle extras = getIntent().getExtras(); + if (extras != null) { + //noinspection WrongConstant + shortcutType = extras.getInt(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE); + } + + switch (shortcutType) { + case SHORTCUT_TYPE_SHUFFLE_ALL: + startServiceWithPlaylist(MusicService.SHUFFLE_MODE_SHUFFLE, + new ShuffleAllPlaylist(getApplicationContext())); + DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.getId()); + break; + case SHORTCUT_TYPE_TOP_TRACKS: + startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE, + new MyTopTracksPlaylist(getApplicationContext())); + DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.getId()); + break; + case SHORTCUT_TYPE_LAST_ADDED: + startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE, + new LastAddedPlaylist(getApplicationContext())); + DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.getId()); + break; + } + + finish(); + } + + private void startServiceWithPlaylist(int shuffleMode, Playlist playlist) { + Intent intent = new Intent(this, MusicService.class); + intent.setAction(ACTION_PLAY_PLAYLIST); + + Bundle bundle = new Bundle(); + bundle.putParcelable(INTENT_EXTRA_PLAYLIST, playlist); + bundle.putInt(INTENT_EXTRA_SHUFFLE_MODE, shuffleMode); + + intent.putExtras(bundle); + + startService(intent); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.java new file mode 100644 index 00000000..5fb28054 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.java @@ -0,0 +1,63 @@ +package code.name.monkey.retromusic.appshortcuts; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; +import android.graphics.drawable.Icon; +import android.os.Build; + +import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType; +import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType; +import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Adrian Campos + */ + +@TargetApi(Build.VERSION_CODES.N_MR1) +public class DynamicShortcutManager { + + private Context context; + private ShortcutManager shortcutManager; + + public DynamicShortcutManager(Context context) { + this.context = context; + shortcutManager = this.context.getSystemService(ShortcutManager.class); + } + + public static ShortcutInfo createShortcut(Context context, String id, String shortLabel, String longLabel, Icon icon, Intent intent) { + return new ShortcutInfo.Builder(context, id) + .setShortLabel(shortLabel) + .setLongLabel(longLabel) + .setIcon(icon) + .setIntent(intent) + .build(); + } + + public void initDynamicShortcuts() { + if (shortcutManager.getDynamicShortcuts().size() == 0) { + shortcutManager.setDynamicShortcuts(getDefaultShortcuts()); + } + } + + public void updateDynamicShortcuts() { + shortcutManager.updateShortcuts(getDefaultShortcuts()); + } + + public List getDefaultShortcuts() { + return (Arrays.asList( + new ShuffleAllShortcutType(context).getShortcutInfo(), + new TopTracksShortcutType(context).getShortcutInfo(), + new LastAddedShortcutType(context).getShortcutInfo() + )); + } + + public static void reportShortcutUsed(Context context, String shortcutId){ + context.getSystemService(ShortcutManager.class).reportShortcutUsed(shortcutId); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/BaseShortcutType.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/BaseShortcutType.java new file mode 100644 index 00000000..28f16a7e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/BaseShortcutType.java @@ -0,0 +1,50 @@ +package code.name.monkey.retromusic.appshortcuts.shortcuttype; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ShortcutInfo; +import android.os.Build; +import android.os.Bundle; + +import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity; + + +/** + * @author Adrian Campos + */ +@TargetApi(Build.VERSION_CODES.N_MR1) +public abstract class BaseShortcutType { + + static final String ID_PREFIX = "code.name.monkey.retromusic.appshortcuts.id."; + + Context context; + + public BaseShortcutType(Context context) { + this.context = context; + } + + static public String getId() { + return ID_PREFIX + "invalid"; + } + + abstract ShortcutInfo getShortcutInfo(); + + /** + * Creates an Intent that will launch MainActivtiy and immediately play {@param songs} in either shuffle or normal mode + * + * @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.) + * @return + */ + Intent getPlaySongsIntent(int shortcutType) { + Intent intent = new Intent(context, AppShortcutLauncherActivity.class); + intent.setAction(Intent.ACTION_VIEW); + + Bundle b = new Bundle(); + b.putInt(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType); + + intent.putExtras(b); + + return intent; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/LastAddedShortcutType.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/LastAddedShortcutType.java new file mode 100644 index 00000000..72db3eeb --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/LastAddedShortcutType.java @@ -0,0 +1,34 @@ +package code.name.monkey.retromusic.appshortcuts.shortcuttype; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.pm.ShortcutInfo; +import android.os.Build; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator; +import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity; + + +/** + * @author Adrian Campos + */ +@TargetApi(Build.VERSION_CODES.N_MR1) +public final class LastAddedShortcutType extends BaseShortcutType { + public LastAddedShortcutType(Context context) { + super(context); + } + + public static String getId() { + return ID_PREFIX + "last_added"; + } + + public ShortcutInfo getShortcutInfo() { + return new ShortcutInfo.Builder(context, getId()) + .setShortLabel(context.getString(R.string.app_shortcut_last_added_short)) + .setLongLabel(context.getString(R.string.app_shortcut_last_added_long)) + .setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_last_added)) + .setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_LAST_ADDED)) + .build(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/ShuffleAllShortcutType.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/ShuffleAllShortcutType.java new file mode 100644 index 00000000..be3ba008 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/ShuffleAllShortcutType.java @@ -0,0 +1,35 @@ +package code.name.monkey.retromusic.appshortcuts.shortcuttype; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.pm.ShortcutInfo; +import android.os.Build; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator; +import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity; + + + +/** + * @author Adrian Campos + */ +@TargetApi(Build.VERSION_CODES.N_MR1) +public final class ShuffleAllShortcutType extends BaseShortcutType { + public ShuffleAllShortcutType(Context context) { + super(context); + } + + public static String getId() { + return ID_PREFIX + "shuffle_all"; + } + + public ShortcutInfo getShortcutInfo() { + return new ShortcutInfo.Builder(context, getId()) + .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(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/TopTracksShortcutType.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/TopTracksShortcutType.java new file mode 100644 index 00000000..3e78db33 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/TopTracksShortcutType.java @@ -0,0 +1,35 @@ +package code.name.monkey.retromusic.appshortcuts.shortcuttype; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.pm.ShortcutInfo; +import android.os.Build; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator; +import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity; + + + +/** + * @author Adrian Campos + */ +@TargetApi(Build.VERSION_CODES.N_MR1) +public final class TopTracksShortcutType extends BaseShortcutType { + public TopTracksShortcutType(Context context) { + super(context); + } + + public static String getId() { + return ID_PREFIX + "top_tracks"; + } + + public ShortcutInfo getShortcutInfo() { + return new ShortcutInfo.Builder(context, getId()) + .setShortLabel(context.getString(R.string.app_shortcut_top_tracks_short)) + .setLongLabel(context.getString(R.string.app_shortcut_top_tracks_long)) + .setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_top_tracks)) + .setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_TOP_TRACKS)) + .build(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.java b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.java new file mode 100644 index 00000000..4b90e941 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.java @@ -0,0 +1,171 @@ +package code.name.monkey.retromusic.appwidgets; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Point; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.view.View; +import android.widget.RemoteViews; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.Constants; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.activities.MainActivity; +import code.name.monkey.retromusic.util.RetroUtil; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.target.Target; + +public class AppWidgetBig extends BaseAppWidget { + + public static final String NAME = "app_widget_big"; + + private static AppWidgetBig mInstance; + private Target target; // for cancellation + + public static synchronized AppWidgetBig getInstance() { + if (mInstance == null) { + mInstance = new AppWidgetBig(); + } + return mInstance; + } + + /** + * Initialize given widgets to default state, where we launch Music on default click and hide + * actions if service not running. + */ + protected void defaultAppWidget(final Context context, final int[] appWidgetIds) { + final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(), + R.layout.app_widget_big); + + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE); + appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art); + appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, + MaterialValueHelper.getPrimaryTextColor(context, false)), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, + MaterialValueHelper.getPrimaryTextColor(context, false)), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, + MaterialValueHelper.getPrimaryTextColor(context, false)), 1f)); + + linkButtons(context, appWidgetView); + pushUpdate(context, appWidgetIds, appWidgetView); + } + + /** + * Update all active widget instances by pushing changes + */ + public void performUpdate(final MusicService service, final int[] appWidgetIds) { + final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(), + R.layout.app_widget_big); + + final boolean isPlaying = service.isPlaying(); + final Song song = service.getCurrentSong(); + + // Set the titles and artwork + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) { + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE); + } else { + appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE); + appWidgetView.setTextViewText(R.id.title, song.title); + appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song)); + } + + // Set correct drawable for pause state + int playPauseRes = + isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp; + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap( + RetroUtil.getTintedVectorDrawable(service, playPauseRes, + MaterialValueHelper.getPrimaryTextColor(service, false)), 1f)); + + // Set prev/next button drawables + appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, + MaterialValueHelper.getPrimaryTextColor(service, false)), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, + MaterialValueHelper.getPrimaryTextColor(service, false)), 1f)); + + // Link actions buttons to intents + linkButtons(service, appWidgetView); + + // Load the album cover async and push the update on completion + Point p = RetroUtil.getScreenSize(service); + final int widgetImageSize = Math.min(p.x, p.y); + final Context appContext = service.getApplicationContext(); + service.runOnUiThread(new Runnable() { + @Override + public void run() { + if (target != null) { + Glide.clear(target); + } + target = SongGlideRequest.Builder.from(Glide.with(appContext), song) + .checkIgnoreMediaStore(appContext) + .asBitmap().build() + .into(new SimpleTarget(widgetImageSize, widgetImageSize) { + @Override + public void onResourceReady(Bitmap resource, + GlideAnimation glideAnimation) { + update(resource); + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + update(null); + } + + private void update(@Nullable Bitmap bitmap) { + if (bitmap == null) { + appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art); + } else { + appWidgetView.setImageViewBitmap(R.id.image, bitmap); + } + pushUpdate(appContext, appWidgetIds, appWidgetView); + } + }); + } + }); + } + + /** + * Link up various button actions using {@link PendingIntent}. + */ + private void linkButtons(final Context context, final RemoteViews views) { + Intent action; + PendingIntent pendingIntent; + + final ComponentName serviceName = new ComponentName(context, MusicService.class); + + // Home + action = new Intent(context, MainActivity.class); + action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + pendingIntent = PendingIntent.getActivity(context, 0, action, 0); + views.setOnClickPendingIntent(R.id.clickable_area, pendingIntent); + + // Previous track + pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName); + views.setOnClickPendingIntent(R.id.button_prev, pendingIntent); + + // Play and pause + pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName); + views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent); + + // Next track + pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName); + views.setOnClickPendingIntent(R.id.button_next, pendingIntent); + + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.java b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.java new file mode 100644 index 00000000..d7c08067 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.java @@ -0,0 +1,194 @@ +package code.name.monkey.retromusic.appwidgets; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.support.v7.graphics.Palette; +import android.text.TextUtils; +import android.view.View; +import android.widget.RemoteViews; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.Constants; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.activities.MainActivity; +import code.name.monkey.retromusic.util.RetroUtil; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.target.Target; + +public class AppWidgetCard extends BaseAppWidget { + + public static final String NAME = "app_widget_card"; + + private static AppWidgetCard mInstance; + private static int imageSize = 0; + private static float cardRadius = 0f; + private Target target; // for cancellation + + public static synchronized AppWidgetCard getInstance() { + if (mInstance == null) { + mInstance = new AppWidgetCard(); + } + return mInstance; + } + + /** + * Initialize given widgets to default state, where we launch Music on default click and hide + * actions if service not running. + */ + protected void defaultAppWidget(final Context context, final int[] appWidgetIds) { + final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(), + R.layout.app_widget_card); + + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE); + appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art); + appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true)), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true)), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true)), 1f)); + + linkButtons(context, appWidgetView); + pushUpdate(context, appWidgetIds, appWidgetView); + } + + /** + * Update all active widget instances by pushing changes + */ + public void performUpdate(final MusicService service, final int[] appWidgetIds) { + final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(), + R.layout.app_widget_card); + + final boolean isPlaying = service.isPlaying(); + final Song song = service.getCurrentSong(); + + // Set the titles and artwork + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) { + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE); + } else { + appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE); + appWidgetView.setTextViewText(R.id.title, song.title); + appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song)); + } + + // Set correct drawable for pause state + int playPauseRes = + isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp; + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap( + RetroUtil.getTintedVectorDrawable(service, playPauseRes, + MaterialValueHelper.getSecondaryTextColor(service, true)), 1f)); + + // Set prev/next button drawables + appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, + MaterialValueHelper.getSecondaryTextColor(service, true)), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, + MaterialValueHelper.getSecondaryTextColor(service, true)), 1f)); + + // Link actions buttons to intents + linkButtons(service, appWidgetView); + + if (imageSize == 0) { + imageSize = service.getResources().getDimensionPixelSize(R.dimen.app_widget_card_image_size); + } + if (cardRadius == 0f) { + cardRadius = service.getResources().getDimension(R.dimen.app_widget_card_radius); + } + + // Load the album cover async and push the update on completion + service.runOnUiThread(new Runnable() { + @Override + public void run() { + if (target != null) { + Glide.clear(target); + } + target = SongGlideRequest.Builder.from(Glide.with(service), song) + .checkIgnoreMediaStore(service) + .generatePalette(service).build() + .centerCrop() + .into(new SimpleTarget(imageSize, imageSize) { + @Override + public void onResourceReady(BitmapPaletteWrapper resource, + GlideAnimation glideAnimation) { + Palette palette = resource.getPalette(); + update(resource.getBitmap(), palette.getVibrantColor(palette + .getMutedColor(MaterialValueHelper.getSecondaryTextColor(service, true)))); + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + update(null, MaterialValueHelper.getSecondaryTextColor(service, true)); + } + + private void update(@Nullable Bitmap bitmap, int color) { + // Set correct drawable for pause state + int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp + : R.drawable.ic_play_arrow_white_24dp; + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, + createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color), 1f)); + + // Set prev/next button drawables + appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, + color), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, + color), 1f)); + + final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap); + final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize, + cardRadius, 0, cardRadius, 0); + appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap); + + pushUpdate(service, appWidgetIds, appWidgetView); + } + }); + } + }); + } + + /** + * Link up various button actions using {@link PendingIntent}. + */ + private void linkButtons(final Context context, final RemoteViews views) { + Intent action; + PendingIntent pendingIntent; + + final ComponentName serviceName = new ComponentName(context, MusicService.class); + + // Home + action = new Intent(context, MainActivity.class); + action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + pendingIntent = PendingIntent.getActivity(context, 0, action, 0); + views.setOnClickPendingIntent(R.id.image, pendingIntent); + views.setOnClickPendingIntent(R.id.media_titles, pendingIntent); + + // Previous track + pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName); + views.setOnClickPendingIntent(R.id.button_prev, pendingIntent); + + // Play and pause + pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName); + views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent); + + // Next track + pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName); + views.setOnClickPendingIntent(R.id.button_next, pendingIntent); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.java b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.java new file mode 100644 index 00000000..120b9952 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.java @@ -0,0 +1,181 @@ +package code.name.monkey.retromusic.appwidgets; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.support.v7.graphics.Palette; +import android.text.TextUtils; +import android.view.View; +import android.widget.RemoteViews; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.Constants; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.activities.MainActivity; +import code.name.monkey.retromusic.util.RetroUtil; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.target.Target; + +public class AppWidgetClassic extends BaseAppWidget { + + public static final String NAME = "app_widget_classic"; + + private static AppWidgetClassic mInstance; + private static int imageSize = 0; + private static float cardRadius = 0f; + private Target target; // for cancellation + + public static synchronized AppWidgetClassic getInstance() { + if (mInstance == null) { + mInstance = new AppWidgetClassic(); + } + return mInstance; + } + + /** + * Initialize given widgets to default state, where we launch Music on default click and hide + * actions if service not running. + */ + protected void defaultAppWidget(final Context context, final int[] appWidgetIds) { + final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(), + R.layout.app_widget_classic); + + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE); + appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art); + appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true)), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true)), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true)), 1f)); + + linkButtons(context, appWidgetView); + pushUpdate(context, appWidgetIds, appWidgetView); + } + + /** + * Update all active widget instances by pushing changes + */ + public void performUpdate(final MusicService service, final int[] appWidgetIds) { + final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(), + R.layout.app_widget_classic); + + final boolean isPlaying = service.isPlaying(); + final Song song = service.getCurrentSong(); + + // Set the titles and artwork + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) { + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE); + } else { + appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE); + appWidgetView.setTextViewText(R.id.title, song.title); + appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song)); + } + + // Link actions buttons to intents + linkButtons(service, appWidgetView); + + if (imageSize == 0) { + imageSize = service.getResources() + .getDimensionPixelSize(R.dimen.app_widget_classic_image_size); + } + if (cardRadius == 0f) { + cardRadius = service.getResources().getDimension(R.dimen.app_widget_card_radius); + } + + // Load the album cover async and push the update on completion + final Context appContext = service.getApplicationContext(); + service.runOnUiThread(new Runnable() { + @Override + public void run() { + if (target != null) { + Glide.clear(target); + } + target = SongGlideRequest.Builder.from(Glide.with(appContext), song) + .checkIgnoreMediaStore(appContext) + .generatePalette(service).build() + .centerCrop() + .into(new SimpleTarget(imageSize, imageSize) { + @Override + public void onResourceReady(BitmapPaletteWrapper resource, + GlideAnimation glideAnimation) { + Palette palette = resource.getPalette(); + update(resource.getBitmap(), palette.getVibrantColor(palette + .getMutedColor(MaterialValueHelper.getSecondaryTextColor(appContext, true)))); + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + update(null, MaterialValueHelper.getSecondaryTextColor(appContext, true)); + } + + private void update(@Nullable Bitmap bitmap, int color) { + // Set correct drawable for pause state + int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp + : R.drawable.ic_play_arrow_white_24dp; + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, + createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color), 1f)); + + // Set prev/next button drawables + appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, + color), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, + color), 1f)); + + final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap); + final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize, + cardRadius, 0, cardRadius, 0); + appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap); + + pushUpdate(appContext, appWidgetIds, appWidgetView); + } + }); + } + }); + } + + /** + * Link up various button actions using {@link PendingIntent}. + */ + private void linkButtons(final Context context, final RemoteViews views) { + Intent action; + PendingIntent pendingIntent; + + final ComponentName serviceName = new ComponentName(context, MusicService.class); + + // Home + action = new Intent(context, MainActivity.class); + action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + pendingIntent = PendingIntent.getActivity(context, 0, action, 0); + views.setOnClickPendingIntent(R.id.image, pendingIntent); + views.setOnClickPendingIntent(R.id.media_titles, pendingIntent); + + // Previous track + pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName); + views.setOnClickPendingIntent(R.id.button_prev, pendingIntent); + + // Play and pause + pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName); + views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent); + + // Next track + pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName); + views.setOnClickPendingIntent(R.id.button_next, pendingIntent); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.java b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.java new file mode 100644 index 00000000..1d80a2d1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.java @@ -0,0 +1,186 @@ +package code.name.monkey.retromusic.appwidgets; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.support.v7.graphics.Palette; +import android.text.TextUtils; +import android.view.View; +import android.widget.RemoteViews; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.Constants; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.activities.MainActivity; +import code.name.monkey.retromusic.util.RetroUtil; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.target.Target; + +public class AppWidgetSmall extends BaseAppWidget { + + public static final String NAME = "app_widget_small"; + + private static AppWidgetSmall mInstance; + private static int imageSize = 0; + private static float cardRadius = 0f; + private Target target; // for cancellation + + public static synchronized AppWidgetSmall getInstance() { + if (mInstance == null) { + mInstance = new AppWidgetSmall(); + } + return mInstance; + } + + /** + * Initialize given widgets to default state, where we launch Music on default click and hide + * actions if service not running. + */ + protected void defaultAppWidget(final Context context, final int[] appWidgetIds) { + final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(), + R.layout.app_widget_small); + + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE); + appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art); + appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true)), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true)), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true)), 1f)); + + linkButtons(context, appWidgetView); + pushUpdate(context, appWidgetIds, appWidgetView); + } + + /** + * Update all active widget instances by pushing changes + */ + public void performUpdate(final MusicService service, final int[] appWidgetIds) { + final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(), + R.layout.app_widget_small); + + final boolean isPlaying = service.isPlaying(); + final Song song = service.getCurrentSong(); + + // Set the titles and artwork + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) { + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE); + } else { + if (TextUtils.isEmpty(song.title) || TextUtils.isEmpty(song.artistName)) { + appWidgetView.setTextViewText(R.id.text_separator, ""); + } else { + appWidgetView.setTextViewText(R.id.text_separator, "•"); + } + + appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE); + appWidgetView.setTextViewText(R.id.title, song.title); + appWidgetView.setTextViewText(R.id.text, song.artistName); + } + + // Link actions buttons to intents + linkButtons(service, appWidgetView); + + if (imageSize == 0) { + imageSize = service.getResources().getDimensionPixelSize(R.dimen.app_widget_small_image_size); + } + if (cardRadius == 0f) { + cardRadius = service.getResources().getDimension(R.dimen.app_widget_card_radius); + } + + // Load the album cover async and push the update on completion + final Context appContext = service.getApplicationContext(); + service.runOnUiThread(new Runnable() { + @Override + public void run() { + if (target != null) { + Glide.clear(target); + } + target = SongGlideRequest.Builder.from(Glide.with(appContext), song) + .checkIgnoreMediaStore(appContext) + .generatePalette(service).build() + .centerCrop() + .into(new SimpleTarget(imageSize, imageSize) { + @Override + public void onResourceReady(BitmapPaletteWrapper resource, + GlideAnimation glideAnimation) { + Palette palette = resource.getPalette(); + update(resource.getBitmap(), palette.getVibrantColor(palette + .getMutedColor(MaterialValueHelper.getSecondaryTextColor(appContext, true)))); + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + update(null, MaterialValueHelper.getSecondaryTextColor(appContext, true)); + } + + private void update(@Nullable Bitmap bitmap, int color) { + // Set correct drawable for pause state + int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp + : R.drawable.ic_play_arrow_white_24dp; + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, + createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color), 1f)); + + // Set prev/next button drawables + appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, + color), 1f)); + appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, + color), 1f)); + + final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap); + final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize, + cardRadius, 0, 0, 0); + appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap); + + pushUpdate(appContext, appWidgetIds, appWidgetView); + } + }); + } + }); + } + + /** + * Link up various button actions using {@link PendingIntent}. + */ + private void linkButtons(final Context context, final RemoteViews views) { + Intent action; + PendingIntent pendingIntent; + + final ComponentName serviceName = new ComponentName(context, MusicService.class); + + // Home + action = new Intent(context, MainActivity.class); + action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + pendingIntent = PendingIntent.getActivity(context, 0, action, 0); + views.setOnClickPendingIntent(R.id.image, pendingIntent); + views.setOnClickPendingIntent(R.id.media_titles, pendingIntent); + + // Previous track + pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName); + views.setOnClickPendingIntent(R.id.button_prev, pendingIntent); + + // Play and pause + pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName); + views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent); + + // Next track + pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName); + views.setOnClickPendingIntent(R.id.button_next, pendingIntent); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/BootReceiver.java b/app/src/main/java/code/name/monkey/retromusic/appwidgets/BootReceiver.java new file mode 100644 index 00000000..38fb2989 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/BootReceiver.java @@ -0,0 +1,32 @@ +package code.name.monkey.retromusic.appwidgets; + +import android.appwidget.AppWidgetManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Build; + +import code.name.monkey.retromusic.service.MusicService; + + +/** + * @author Eugene Cheung (arkon) + */ +public class BootReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + final AppWidgetManager widgetManager = AppWidgetManager.getInstance(context); + + // Start music service if there are any existing widgets + if (widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetBig.class)).length > 0 || + widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetClassic.class)).length > 0 || + widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetSmall.class)).length > 0 || + widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetCard.class)).length > 0) { + final Intent serviceIntent = new Intent(context, MusicService.class); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // not allowed on Oreo + context.startService(serviceIntent); + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.java b/app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.java new file mode 100644 index 00000000..b2944cb4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.java @@ -0,0 +1,162 @@ +package code.name.monkey.retromusic.appwidgets.base; + +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.TextUtils; +import android.widget.RemoteViews; +import code.name.monkey.retromusic.Constants; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; + +public abstract class BaseAppWidget extends AppWidgetProvider { + + public static final String NAME = "app_widget"; + + protected static Bitmap createBitmap(Drawable drawable, float sizeMultiplier) { + Bitmap bitmap = Bitmap.createBitmap((int) (drawable.getIntrinsicWidth() * sizeMultiplier), + (int) (drawable.getIntrinsicHeight() * sizeMultiplier), Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(bitmap); + drawable.setBounds(0, 0, c.getWidth(), c.getHeight()); + drawable.draw(c); + return bitmap; + } + + protected static Bitmap createRoundedBitmap(Drawable drawable, int width, int height, float tl, + float tr, float bl, float br) { + if (drawable == null) { + return null; + } + + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(bitmap); + drawable.setBounds(0, 0, width, height); + drawable.draw(c); + + Bitmap rounded = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(rounded); + Paint paint = new Paint(); + paint.setShader( + new BitmapShader(bitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); + paint.setAntiAlias(true); + canvas.drawPath(composeRoundedRectPath(new RectF(0, 0, width, height), tl, tr, bl, br), paint); + + return rounded; + } + + protected static Path composeRoundedRectPath(RectF rect, float tl, float tr, float bl, float br) { + Path path = new Path(); + tl = tl < 0 ? 0 : tl; + tr = tr < 0 ? 0 : tr; + bl = bl < 0 ? 0 : bl; + br = br < 0 ? 0 : br; + + path.moveTo(rect.left + tl, rect.top); + path.lineTo(rect.right - tr, rect.top); + path.quadTo(rect.right, rect.top, rect.right, rect.top + tr); + path.lineTo(rect.right, rect.bottom - br); + path.quadTo(rect.right, rect.bottom, rect.right - br, rect.bottom); + path.lineTo(rect.left + bl, rect.bottom); + path.quadTo(rect.left, rect.bottom, rect.left, rect.bottom - bl); + path.lineTo(rect.left, rect.top + tl); + path.quadTo(rect.left, rect.top, rect.left + tl, rect.top); + path.close(); + + return path; + } + + /** + * {@inheritDoc} + */ + @Override + public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, + final int[] appWidgetIds) { + defaultAppWidget(context, appWidgetIds); + final Intent updateIntent = new Intent(Constants.APP_WIDGET_UPDATE); + updateIntent.putExtra(Constants.EXTRA_APP_WIDGET_NAME, NAME); + updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); + updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + context.sendBroadcast(updateIntent); + } + + /** + * Handle a change notification coming over from {@link MusicService} + */ + public void notifyChange(final MusicService service, final String what) { + if (hasInstances(service)) { + if (Constants.META_CHANGED.equals(what) || Constants.PLAY_STATE_CHANGED.equals(what)) { + performUpdate(service, null); + } + } + } + + protected void pushUpdate(final Context context, final int[] appWidgetIds, + final RemoteViews views) { + final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); + if (appWidgetIds != null) { + appWidgetManager.updateAppWidget(appWidgetIds, views); + } else { + appWidgetManager.updateAppWidget(new ComponentName(context, getClass()), views); + } + } + + /** + * Check against {@link AppWidgetManager} if there are any instances of this widget. + */ + protected boolean hasInstances(final Context context) { + final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); + final int[] mAppWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, + getClass())); + return mAppWidgetIds.length > 0; + } + + protected PendingIntent buildPendingIntent(Context context, final String action, + final ComponentName serviceName) { + Intent intent = new Intent(action); + intent.setComponent(serviceName); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + return PendingIntent.getForegroundService(context, 0, intent, 0); + } else { + return PendingIntent.getService(context, 0, intent, 0); + } + } + + abstract protected void defaultAppWidget(final Context context, final int[] appWidgetIds); + + abstract public void performUpdate(final MusicService service, final int[] appWidgetIds); + + protected Drawable getAlbumArtDrawable(final Resources resources, final Bitmap bitmap) { + Drawable image; + if (bitmap == null) { + image = resources.getDrawable(R.drawable.default_album_art); + } else { + image = new BitmapDrawable(resources, bitmap); + } + return image; + } + + protected String getSongArtistAndAlbum(final Song song) { + final StringBuilder builder = new StringBuilder(); + builder.append(song.artistName); + if (!TextUtils.isEmpty(song.artistName) && !TextUtils.isEmpty(song.albumName)) { + builder.append(" • "); + } + builder.append(song.albumName); + return builder.toString(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.java new file mode 100644 index 00000000..bd13a4e9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.java @@ -0,0 +1,94 @@ +package code.name.monkey.retromusic.dialogs; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.loaders.PlaylistLoader; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.PlaylistsUtil; +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; + +/** + * @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad) + */ +public class AddToPlaylistDialog extends RoundedBottomSheetDialogFragment implements AdapterView.OnItemClickListener { + + @BindView(R.id.playlists) + ListView playlist; + @BindView(R.id.title) + TextView title; + List playlists; + + @NonNull + public static AddToPlaylistDialog create(Song song) { + ArrayList list = new ArrayList<>(); + list.add(song); + return create(list); + } + + @NonNull + public static AddToPlaylistDialog create(ArrayList songs) { + AddToPlaylistDialog dialog = new AddToPlaylistDialog(); + Bundle args = new Bundle(); + args.putParcelableArrayList("songs", songs); + dialog.setArguments(args); + return dialog; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.dialog_add_to_playlist, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + ArrayAdapter playlistAdapter = new ArrayAdapter<>(getActivity(), R.layout.simple_list_item); + playlists = PlaylistLoader.getAllPlaylists(getActivity()).blockingFirst(); + playlistAdapter.add(getActivity().getResources().getString(R.string.action_new_playlist)); + + for (int i = 1; i < playlists.size(); i++) { + playlistAdapter.add(playlists.get(i - 1).name); + playlistAdapter.notifyDataSetChanged(); + } + + this.playlist.setAdapter(playlistAdapter); + this.playlist.setOnItemClickListener(this); + } + + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + //noinspection unchecked + final ArrayList songs = getArguments().getParcelableArrayList("songs"); + + if (songs == null) { + return; + } + if (i == 0) { + dismiss(); + CreatePlaylistDialog.create(songs) + .show(getActivity().getSupportFragmentManager(), "ADD_TO_PLAYLIST"); + } else { + dismiss(); + PlaylistsUtil.addToPlaylist(getActivity(), songs, playlists.get(i - 1).id, true); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java new file mode 100644 index 00000000..4602d50b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java @@ -0,0 +1,159 @@ +package code.name.monkey.retromusic.dialogs; + +import android.Manifest; +import android.app.Dialog; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.DialogFragment; +import android.view.View; + +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 code.name.monkey.retromusic.R; + +/** + * @author Aidan Follestad (afollestad), modified by Karim Abou Zeid + */ +public class BlacklistFolderChooserDialog extends DialogFragment implements MaterialDialog.ListCallback { + + private File parentFolder; + private File[] parentContents; + private boolean canGoUp = false; + + private FolderCallback callback; + + String initialPath = Environment.getExternalStorageDirectory().getAbsolutePath(); + + 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; + } + + private File[] listFiles() { + File[] contents = parentFolder.listFiles(); + List 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; + } + + public static BlacklistFolderChooserDialog create() { + return new BlacklistFolderChooserDialog(); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + return new MaterialDialog.Builder(getActivity()) + .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(getActivity()) + .title(parentFolder.getAbsolutePath()) + .items((CharSequence[]) getContentsArray()) + .itemsCallback(this) + .autoDismiss(false) + .onPositive((dialog, which) -> { + dismiss(); + callback.onFolderSelection(BlacklistFolderChooserDialog.this, parentFolder); + }) + .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 { + + @Override + public int compare(File lhs, File rhs) { + return lhs.getName().compareTo(rhs.getName()); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/ClearSmartPlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/ClearSmartPlaylistDialog.java new file mode 100644 index 00000000..2358c2aa --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/ClearSmartPlaylistDialog.java @@ -0,0 +1,52 @@ +package code.name.monkey.retromusic.dialogs; + +import android.app.Dialog; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.text.Html; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist; + + +public class ClearSmartPlaylistDialog extends DialogFragment { + + @NonNull + public static ClearSmartPlaylistDialog create(AbsSmartPlaylist playlist) { + ClearSmartPlaylistDialog dialog = new ClearSmartPlaylistDialog(); + Bundle args = new Bundle(); + args.putParcelable("playlist", playlist); + dialog.setArguments(args); + return dialog; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + //noinspection unchecked + final AbsSmartPlaylist playlist = getArguments().getParcelable("playlist"); + int title = R.string.clear_playlist_title; + //noinspection ConstantConditions + CharSequence content = Html.fromHtml(getString(R.string.clear_playlist_x, playlist.name)); + + return new MaterialDialog.Builder(getActivity()) + .title(title) + .content(content) + .positiveText(R.string.clear_action) + .negativeText(android.R.string.cancel) + .onPositive(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { + if (getActivity() == null) { + return; + } + playlist.clear(getActivity()); + } + }) + .build(); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.java new file mode 100644 index 00000000..a09cf4cf --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.java @@ -0,0 +1,103 @@ +package code.name.monkey.retromusic.dialogs; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.BottomSheetDialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; + +import java.util.ArrayList; +import java.util.Objects; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.PlaylistsUtil; +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; + +/** + * @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad) + */ +public class CreatePlaylistDialog extends RoundedBottomSheetDialogFragment { + + @BindView(R.id.option_1) + EditText playlistName; + @BindView(R.id.action_cancel) + Button actionCancel; + @BindView(R.id.action_create) + Button actionCreate; + + @NonNull + public static CreatePlaylistDialog create() { + return create((Song) null); + } + + @NonNull + public static CreatePlaylistDialog create(@Nullable Song song) { + ArrayList list = new ArrayList<>(); + if (song != null) { + list.add(song); + } + return create(list); + } + + @NonNull + public static CreatePlaylistDialog create(ArrayList songs) { + CreatePlaylistDialog dialog = new CreatePlaylistDialog(); + Bundle args = new Bundle(); + args.putParcelableArrayList("songs", songs); + dialog.setArguments(args); + return dialog; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.dialog_create_playlist, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + int accentColor = ThemeStore.accentColor(Objects.requireNonNull(getContext())); + TintHelper.setTintAuto(playlistName, accentColor, true); + TintHelper.setTintAuto(actionCreate, accentColor, true); + actionCancel.setTextColor(accentColor); + } + + @OnClick({R.id.action_cancel, R.id.action_create}) + void actions(View view) { + switch (view.getId()) { + case R.id.action_cancel: + dismiss(); + break; + case R.id.action_create: + if (getActivity() == null) { + return; + } + if (!playlistName.getText().toString().trim().isEmpty()) { + final int playlistId = PlaylistsUtil + .createPlaylist(getActivity(), playlistName.getText().toString()); + if (playlistId != -1 && getActivity() != null) { + //noinspection unchecked + ArrayList songs = getArguments().getParcelableArrayList("songs"); + if (songs != null) { + PlaylistsUtil.addToPlaylist(getActivity(), songs, playlistId, true); + } + } + } + break; + } + dismiss(); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.java new file mode 100644 index 00000000..5e408ca8 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.java @@ -0,0 +1,89 @@ +package code.name.monkey.retromusic.dialogs; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.util.PlaylistsUtil; +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; + + +public class DeletePlaylistDialog extends RoundedBottomSheetDialogFragment { + + @BindView(R.id.action_delete) + TextView delete; + @BindView(R.id.title) + TextView title; + @BindView(R.id.action_cancel) + TextView cancel; + + @NonNull + public static DeletePlaylistDialog create(Playlist playlist) { + ArrayList list = new ArrayList<>(); + list.add(playlist); + return create(list); + } + + @NonNull + public static DeletePlaylistDialog create(ArrayList playlists) { + DeletePlaylistDialog dialog = new DeletePlaylistDialog(); + Bundle args = new Bundle(); + args.putParcelableArrayList("playlists", playlists); + dialog.setArguments(args); + return dialog; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.dialog_delete_playlist, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + //noinspection unchecked + final ArrayList playlists = getArguments().getParcelableArrayList("playlists"); + int title; + CharSequence content; + //noinspection ConstantConditions + if (playlists.size() > 1) { + title = R.string.delete_playlists_title; + content = Html.fromHtml(getString(R.string.delete_x_playlists, playlists.size())); + } else { + title = R.string.delete_playlist_title; + content = Html.fromHtml(getString(R.string.delete_playlist_x, playlists.get(0).name)); + } + this.title.setText(title); + this.delete.setText(content); + } + + @OnClick({R.id.action_cancel, R.id.action_delete}) + void actions(View view) { + final ArrayList playlists = getArguments().getParcelableArrayList("playlists"); + switch (view.getId()) { + case R.id.action_delete: + if (getActivity() == null) + return; + PlaylistsUtil.deletePlaylists(getActivity(), playlists); + break; + default: + } + dismiss(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.java new file mode 100644 index 00000000..1bdb83d4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.java @@ -0,0 +1,112 @@ +package code.name.monkey.retromusic.dialogs; + +/* +import android.app.Dialog; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.text.Html; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; + +import code.name.monkey.retromusic.util.MusicUtil; + +*/ + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.BottomSheetDialogFragment; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; + +/** + * @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad) + */ + +public class DeleteSongsDialog extends RoundedBottomSheetDialogFragment { + @BindView(R.id.action_delete) + TextView delete; + @BindView(R.id.title) + TextView title; + @BindView(R.id.action_cancel) + TextView cancel; + + @NonNull + public static DeleteSongsDialog create(Song song) { + ArrayList list = new ArrayList<>(); + list.add(song); + return create(list); + } + + @NonNull + public static DeleteSongsDialog create(ArrayList songs) { + DeleteSongsDialog dialog = new DeleteSongsDialog(); + Bundle args = new Bundle(); + args.putParcelableArrayList("songs", songs); + dialog.setArguments(args); + return dialog; + } + + @OnClick({R.id.action_cancel, R.id.action_delete}) + void actions(View view) { + final ArrayList songs = getArguments().getParcelableArrayList("songs"); + switch (view.getId()) { + case R.id.action_delete: + if (getActivity() == null) + return; + MusicUtil.deleteTracks(getActivity(), songs); + break; + default: + } + dismiss(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + //noinspection unchecked + final ArrayList songs = getArguments().getParcelableArrayList("songs"); + int title; + CharSequence content; + if (songs != null && songs.size() > 1) { + title = R.string.delete_songs_title; + content = Html.fromHtml(getString(R.string.delete_x_songs, songs.size())); + } else { + title = R.string.delete_song_title; + content = Html.fromHtml(getString(R.string.delete_song_x, songs.get(0).title)); + } + + this.title.setText(title); + this.delete.setText(content); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.dialog_delete_songs, container, false); + ButterKnife.bind(this, layout); + return layout; + } + +} + diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/HomeOptionDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/HomeOptionDialog.java new file mode 100644 index 00000000..11873df9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/HomeOptionDialog.java @@ -0,0 +1,125 @@ +package code.name.monkey.retromusic.dialogs; + +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.AppCompatTextView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.io.File; +import java.util.Calendar; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.util.Compressor; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.CircularImageView; +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +import static code.name.monkey.retromusic.Constants.USER_PROFILE; + +/** + * @author Hemanth S (h4h13). + */ +public class HomeOptionDialog extends RoundedBottomSheetDialogFragment { + private static final String TAG = "HomeOptionDialog"; + Unbinder mUnbinder; + @BindView(R.id.user_image_bottom) + CircularImageView userImageBottom; + @BindView(R.id.title_welcome) + AppCompatTextView titleWelcome; + private CompositeDisposable disposable = new CompositeDisposable(); + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.user_action_details, container, false); + mUnbinder = ButterKnife.bind(this, layout); + return layout; + } + + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + loadImageFromStorage(); + titleWelcome.setText(String.format("%s, %s!", getTimeOfTheDay(), PreferenceUtil.getInstance(getContext()).getUserName())); + } + + private String getTimeOfTheDay() { + String message = getString(R.string.title_good_day); + Calendar c = Calendar.getInstance(); + int timeOfDay = c.get(Calendar.HOUR_OF_DAY); + + if (timeOfDay >= 0 && timeOfDay < 6) { + message = getString(R.string.title_good_night); + } else if (timeOfDay >= 6 && timeOfDay < 12) { + message = getString(R.string.title_good_morning); + } else if (timeOfDay >= 12 && timeOfDay < 16) { + message = getString(R.string.title_good_afternoon); + } else if (timeOfDay >= 16 && timeOfDay < 20) { + message = getString(R.string.title_good_evening); + } else if (timeOfDay >= 20 && timeOfDay < 24) { + message = getString(R.string.title_good_night); + } + return message; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + disposable.clear(); + mUnbinder.unbind(); + } + + @OnClick({R.id.action_about, R.id.user_info_container, R.id.action_folder, R.id.action_settings, R.id.action_sleep_timer}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.user_info_container: + NavigationUtil.goToUserInfo(getActivity()); + break; + case R.id.action_folder: + //getMainActivity().setCurrentFragment(FoldersFragment.newInstance(getContext()), true); + break; + case R.id.action_settings: + NavigationUtil.goToSettings(getActivity()); + break; + case R.id.action_about: + NavigationUtil.goToAbout(getActivity()); + break; + case R.id.action_sleep_timer: + if (getFragmentManager() != null) { + new SleepTimerDialog().show(getFragmentManager(), TAG); + } + break; + } + dismiss(); + } + + private void loadImageFromStorage() { + //noinspection ConstantConditions + disposable.add(new Compressor(getContext()) + .setMaxHeight(300) + .setMaxWidth(300) + .setQuality(75) + .setCompressFormat(Bitmap.CompressFormat.WEBP) + .compressToBitmapAsFlowable( + new File(PreferenceUtil.getInstance(getContext()).getProfileImage(), USER_PROFILE)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(userImageBottom::setImageBitmap, + throwable -> userImageBottom.setImageDrawable(ContextCompat + .getDrawable(getContext(), R.drawable.ic_person_flat)))); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.java new file mode 100644 index 00000000..a3a80176 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.java @@ -0,0 +1,87 @@ +package code.name.monkey.retromusic.dialogs; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.BottomSheetDialogFragment; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.PlaylistSong; +import code.name.monkey.retromusic.util.PlaylistsUtil; +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; + + +public class RemoveFromPlaylistDialog extends RoundedBottomSheetDialogFragment { + @BindView(R.id.action_remove) + TextView remove; + @BindView(R.id.title) + TextView title; + @BindView(R.id.action_cancel) + TextView cancel; + + @NonNull + public static RemoveFromPlaylistDialog create(PlaylistSong song) { + ArrayList list = new ArrayList<>(); + list.add(song); + return create(list); + } + + @NonNull + public static RemoveFromPlaylistDialog create(ArrayList songs) { + RemoveFromPlaylistDialog dialog = new RemoveFromPlaylistDialog(); + Bundle args = new Bundle(); + args.putParcelableArrayList("songs", songs); + dialog.setArguments(args); + return dialog; + } + + @OnClick({R.id.action_cancel, R.id.action_remove}) + void actions(View view) { + final ArrayList songs = getArguments().getParcelableArrayList("songs"); + switch (view.getId()) { + case R.id.action_remove: + if (getActivity() == null) + return; + PlaylistsUtil.removeFromPlaylist(getActivity(), songs); + break; + default: + } + dismiss(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.dialog_remove_from_playlist, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + //noinspection unchecked + final ArrayList songs = getArguments().getParcelableArrayList("songs"); + int title; + CharSequence content; + if (songs.size() > 1) { + title = R.string.remove_songs_from_playlist_title; + content = Html.fromHtml(getString(R.string.remove_x_songs_from_playlist, songs.size())); + } else { + title = R.string.remove_song_from_playlist_title; + content = Html.fromHtml(getString(R.string.remove_song_x_from_playlist, songs.get(0).title)); + } + this.remove.setText(content); + this.title.setText(title); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.java new file mode 100644 index 00000000..10bdfced --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.java @@ -0,0 +1,79 @@ +package code.name.monkey.retromusic.dialogs; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.BottomSheetDialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; + +import java.util.Objects; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.util.PlaylistsUtil; +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; + +/** + * @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad) + */ +public class RenamePlaylistDialog extends RoundedBottomSheetDialogFragment { + @BindView(R.id.option_1) + EditText playlistName; + @BindView(R.id.action_cancel) + Button cancel; + @BindView(R.id.action_rename) + Button rename; + + @NonNull + public static RenamePlaylistDialog create(long playlistId) { + RenamePlaylistDialog dialog = new RenamePlaylistDialog(); + Bundle args = new Bundle(); + args.putLong("playlist_id", playlistId); + dialog.setArguments(args); + return dialog; + } + + @OnClick({R.id.action_cancel, R.id.action_rename}) + void actions(View view) { + switch (view.getId()) { + case R.id.action_cancel: + dismiss(); + break; + case R.id.action_rename: + if (!playlistName.toString().trim().equals("")) { + long playlistId = getArguments().getLong("playlist_id"); + PlaylistsUtil.renamePlaylist(getActivity(), playlistId, playlistName.toString()); + } + break; + } + dismiss(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.dialog_playlist_rename, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + int accentColor = ThemeStore.accentColor(Objects.requireNonNull(getContext())); + TintHelper.setTintAuto(playlistName, accentColor, true); + TintHelper.setTintAuto(rename, accentColor, true); + cancel.setTextColor(accentColor); + + long playlistId = getArguments().getLong("playlist_id"); + playlistName.setText(PlaylistsUtil.getNameForPlaylist(getActivity(), playlistId)); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/ScanMediaFolderChooserDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/ScanMediaFolderChooserDialog.java new file mode 100644 index 00000000..89c8d125 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/ScanMediaFolderChooserDialog.java @@ -0,0 +1 @@ +package code.name.monkey.retromusic.dialogs; import android.Manifest; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.pm.PackageManager; import android.media.MediaScannerConnection; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.app.DialogFragment; import android.view.View; import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import code.name.monkey.retromusic.R; import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener; import code.name.monkey.retromusic.ui.fragments.mainactivity.folders.FoldersFragment; import code.name.monkey.retromusic.util.PreferenceUtil; /** * @author Aidan Follestad (afollestad), modified by Karim Abou Zeid */ public class ScanMediaFolderChooserDialog extends DialogFragment implements MaterialDialog.ListCallback { String initialPath = PreferenceUtil.getInstance(getContext()).getStartDirectory().getAbsolutePath(); private File parentFolder; private File[] parentContents; private boolean canGoUp = false; public static ScanMediaFolderChooserDialog create() { return new ScanMediaFolderChooserDialog(); } private static void scanPaths(@NonNull WeakReference activityWeakReference, @NonNull Context applicationContext, @Nullable String[] toBeScanned) { Activity activity = activityWeakReference.get(); if (toBeScanned == null || toBeScanned.length < 1) { Toast.makeText(applicationContext, R.string.nothing_to_scan, Toast.LENGTH_SHORT).show(); } else { MediaScannerConnection.scanFile(applicationContext, toBeScanned, null, activity != null ? new UpdateToastMediaScannerCompletionListener(activity, toBeScanned) : null); } } 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; } private File[] listFiles() { File[] contents = parentFolder.listFiles(); List 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( getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { return new MaterialDialog.Builder(getActivity()) .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(getActivity()) .title(parentFolder.getAbsolutePath()) .items((CharSequence[]) getContentsArray()) .itemsCallback(this) .autoDismiss(false) .onPositive((dialog, which) -> { final Context applicationContext = getActivity().getApplicationContext(); final WeakReference activityWeakReference = new WeakReference<>(getActivity()); dismiss(); new FoldersFragment.ListPathsAsyncTask(getActivity(), paths -> scanPaths(activityWeakReference, applicationContext, paths)).execute(new FoldersFragment.ListPathsAsyncTask.LoadingInfo(parentFolder, FoldersFragment.AUDIO_FILE_FILTER)); }) .onNegative((materialDialog, dialogAction) -> dismiss()) .positiveText(R.string.action_scan_directory) .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()); } private static class FolderSorter implements Comparator { @Override public int compare(File lhs, File rhs) { return lhs.getName().compareTo(rhs.getName()); } } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.java new file mode 100755 index 00000000..854a06f2 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.java @@ -0,0 +1,173 @@ +package code.name.monkey.retromusic.dialogs; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.SystemClock; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.SeekBar; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.Locale; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; + +import static code.name.monkey.retromusic.Constants.ACTION_QUIT; + +public class SleepTimerDialog extends RoundedBottomSheetDialogFragment { + @BindView(R.id.seek_arc) + SeekBar seekArc; + @BindView(R.id.timer_display) + TextView timerDisplay; + @BindView(R.id.action_set) + Button setButton; + @BindView(R.id.action_cancel) + Button cancelButton; + + private int seekArcProgress; + private TimerUpdater timerUpdater; + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + timerUpdater.cancel(); + } + + @Override + public void onResume() { + super.onResume(); + if (makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE) != null) { + timerUpdater.start(); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.dialog_sleep_timer, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + timerUpdater = new TimerUpdater(); + + seekArcProgress = PreferenceUtil.getInstance(getActivity()).getLastSleepTimerValue(); + updateTimeDisplayTime(); + seekArc.setProgress(seekArcProgress); + + int accentColor = ThemeStore.accentColor(getContext()); + TintHelper.setTintAuto(seekArc, accentColor, true); + setButton.setTextColor(accentColor); + cancelButton.setTextColor(accentColor); + + seekArc.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) { + if (i < 1) { + seekArc.setProgress(1); + return; + } + seekArcProgress = i; + updateTimeDisplayTime(); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + PreferenceUtil.getInstance(getActivity()).setLastSleepTimerValue(seekArcProgress); + } + }); + } + + @OnClick({R.id.action_cancel, R.id.action_set}) + void set(View view) { + switch (view.getId()) { + case R.id.action_cancel: + if (getActivity() == null) { + return; + } + final PendingIntent previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE); + if (previous != null) { + AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); + if (am != null) { + am.cancel(previous); + } + previous.cancel(); + Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_canceled), Toast.LENGTH_SHORT).show(); + } + break; + case R.id.action_set: + if (getActivity() == null) { + return; + } + final int minutes = seekArcProgress; + PendingIntent pi = makeTimerPendingIntent(PendingIntent.FLAG_CANCEL_CURRENT); + final long nextSleepTimerElapsedTime = SystemClock.elapsedRealtime() + minutes * 60 * 1000; + PreferenceUtil.getInstance(getActivity()).setNextSleepTimerElapsedRealtime(nextSleepTimerElapsedTime); + AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); + if (am != null) { + am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextSleepTimerElapsedTime, pi); + } + Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_set, minutes), Toast.LENGTH_SHORT).show(); + break; + } + dismiss(); + } + + private void updateTimeDisplayTime() { + timerDisplay.setText(String.format(Locale.getDefault(), "%d min", seekArcProgress)); + } + + private PendingIntent makeTimerPendingIntent(int flag) { + return PendingIntent.getService(getActivity(), 0, makeTimerIntent(), flag); + } + + private Intent makeTimerIntent() { + return new Intent(getActivity(), MusicService.class) + .setAction(ACTION_QUIT); + } + + private class TimerUpdater extends CountDownTimer { + TimerUpdater() { + super(PreferenceUtil.getInstance(getActivity()).getNextSleepTimerElapsedRealTime() - SystemClock.elapsedRealtime(), 1000); + } + + @Override + public void onTick(long millisUntilFinished) { + cancelButton.setText(String.format("%s (%s)", getString(R.string.cancel_current_timer), MusicUtil.getReadableDurationString(millisUntilFinished))); + //materialDialog.setActionButton(DialogAction.NEUTRAL, materialDialog.getContext().getString(R.string.cancel_current_timer) + " (" + MusicUtil.getReadableDurationString(millisUntilFinished) + ")"); + } + + @Override + public void onFinish() { + cancelButton.setText(null); + //materialDialog.setActionButton(DialogAction.NEUTRAL, null); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.java new file mode 100644 index 00000000..a40104d8 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.java @@ -0,0 +1,117 @@ +package code.name.monkey.retromusic.dialogs; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.BottomSheetDialogFragment; +import android.text.Html; +import android.text.Spanned; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.jaudiotagger.audio.AudioFile; +import org.jaudiotagger.audio.AudioFileIO; +import org.jaudiotagger.audio.AudioHeader; +import org.jaudiotagger.audio.exceptions.CannotReadException; +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; +import org.jaudiotagger.tag.TagException; + +import java.io.File; +import java.io.IOException; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; + +/** + * @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad) + */ +public class SongDetailDialog extends RoundedBottomSheetDialogFragment { + + public static final String TAG = SongDetailDialog.class.getSimpleName(); + + @NonNull + public static SongDetailDialog create(Song song) { + SongDetailDialog dialog = new SongDetailDialog(); + Bundle args = new Bundle(); + args.putParcelable("song", song); + dialog.setArguments(args); + return dialog; + } + + private static Spanned makeTextWithTitle(@NonNull Context context, int titleResId, String text) { + return Html.fromHtml("" + context.getResources().getString(titleResId) + ": " + "" + text); + } + + private static String getFileSizeString(long sizeInBytes) { + long fileSizeInKB = sizeInBytes / 1024; + long fileSizeInMB = fileSizeInKB / 1024; + return fileSizeInMB + " MB"; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View dialogView = inflater.inflate(R.layout.dialog_file_details, container, false); + Context context = getContext(); + + final TextView fileName = dialogView.findViewById(R.id.file_name); + final TextView filePath = dialogView.findViewById(R.id.file_path); + final TextView fileSize = dialogView.findViewById(R.id.file_size); + final TextView fileFormat = dialogView.findViewById(R.id.file_format); + final TextView trackLength = dialogView.findViewById(R.id.track_length); + final TextView bitRate = dialogView.findViewById(R.id.bitrate); + final TextView samplingRate = dialogView.findViewById(R.id.sampling_rate); + + fileName.setText(makeTextWithTitle(context, R.string.label_file_name, "-")); + filePath.setText(makeTextWithTitle(context, R.string.label_file_path, "-")); + fileSize.setText(makeTextWithTitle(context, R.string.label_file_size, "-")); + fileFormat.setText(makeTextWithTitle(context, R.string.label_file_format, "-")); + trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, "-")); + bitRate.setText(makeTextWithTitle(context, R.string.label_bit_rate, "-")); + samplingRate.setText(makeTextWithTitle(context, R.string.label_sampling_rate, "-")); + + final Song song = getArguments().getParcelable("song"); + if (song != null) { + final File songFile = new File(song.data); + if (songFile.exists()) { + fileName.setText(makeTextWithTitle(context, R.string.label_file_name, songFile.getName())); + filePath.setText( + makeTextWithTitle(context, R.string.label_file_path, songFile.getAbsolutePath())); + fileSize.setText(makeTextWithTitle(context, R.string.label_file_size, + getFileSizeString(songFile.length()))); + try { + AudioFile audioFile = AudioFileIO.read(songFile); + AudioHeader audioHeader = audioFile.getAudioHeader(); + + fileFormat.setText( + makeTextWithTitle(context, R.string.label_file_format, audioHeader.getFormat())); + trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil + .getReadableDurationString(audioHeader.getTrackLength() * 1000))); + bitRate.setText(makeTextWithTitle(context, R.string.label_bit_rate, + audioHeader.getBitRate() + " kb/s")); + samplingRate.setText(makeTextWithTitle(context, R.string.label_sampling_rate, + audioHeader.getSampleRate() + " Hz")); + } catch (@NonNull CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) { + Log.e(TAG, "error while reading the song file", e); + // fallback + trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, + MusicUtil.getReadableDurationString(song.duration))); + } + } else { + // fallback + fileName.setText(makeTextWithTitle(context, R.string.label_file_name, song.title)); + trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, + MusicUtil.getReadableDurationString(song.duration))); + } + } + + return dialogView; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SongShareDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongShareDialog.java new file mode 100644 index 00000000..0454367c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongShareDialog.java @@ -0,0 +1,71 @@ +package code.name.monkey.retromusic.dialogs; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.BottomSheetDialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; + + +public class SongShareDialog extends RoundedBottomSheetDialogFragment { + @BindView(R.id.option_2) + TextView currentSong; + + @NonNull + public static SongShareDialog create(final Song song) { + final SongShareDialog dialog = new SongShareDialog(); + final Bundle args = new Bundle(); + args.putParcelable("song", song); + dialog.setArguments(args); + return dialog; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.dialog_file_share, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @SuppressLint("StringFormatInvalid") + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + final Song song = getArguments().getParcelable("song"); + currentSong.setText(getString(R.string.currently_listening_to_x_by_x, song.title, song.artistName)); + } + + @OnClick({R.id.option_2, R.id.option_1}) + void onClick(View view) { + final Song song = getArguments().getParcelable("song"); + final String currentlyListening = getString(R.string.currently_listening_to_x_by_x, song.title, song.artistName); + switch (view.getId()) { + case R.id.option_1: + startActivity( + Intent.createChooser( + MusicUtil.createShareSongFileIntent(song, getContext()), null)); + break; + case R.id.option_2: + getActivity().startActivity(Intent.createChooser( + new Intent().setAction(Intent.ACTION_SEND) + .putExtra(Intent.EXTRA_TEXT, currentlyListening) + .setType("text/plain"), null)); + break; + } + dismiss(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/ArtistGlideRequest.java b/app/src/main/java/code/name/monkey/retromusic/glide/ArtistGlideRequest.java new file mode 100644 index 00000000..5835bfcd --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/ArtistGlideRequest.java @@ -0,0 +1,140 @@ +package code.name.monkey.retromusic.glide; + +import android.content.Context; +import android.graphics.Bitmap; +import android.support.annotation.NonNull; + +import com.bumptech.glide.BitmapRequestBuilder; +import com.bumptech.glide.DrawableRequestBuilder; +import com.bumptech.glide.DrawableTypeRequest; +import com.bumptech.glide.Priority; +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.load.Key; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.resource.drawable.GlideDrawable; +import com.bumptech.glide.request.target.Target; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.glide.artistimage.ArtistImage; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.util.ArtistSignatureUtil; +import code.name.monkey.retromusic.util.CustomArtistImageUtil; + +public class ArtistGlideRequest { + + private static final int DEFAULT_ANIMATION = android.R.anim.fade_in; + private static final DiskCacheStrategy DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.SOURCE; + private static final int DEFAULT_ERROR_IMAGE = R.drawable.default_artist_art; + + private static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Artist artist, + boolean noCustomImage, boolean forceDownload) { + boolean hasCustomImage = CustomArtistImageUtil.getInstance(RetroApplication.getInstance()) + .hasCustomArtistImage(artist); + if (noCustomImage || !hasCustomImage) { + return requestManager.load(new ArtistImage(artist.getName(), forceDownload)); + } else { + return requestManager.load(CustomArtistImageUtil.getFile(artist)); + } + } + + private static Key createSignature(Artist artist) { + return ArtistSignatureUtil.getInstance(RetroApplication.getInstance()) + .getArtistSignature(artist.getName()); + } + + public static class Builder { + + final RequestManager requestManager; + final Artist artist; + boolean noCustomImage; + boolean forceDownload; + + private Builder(@NonNull RequestManager requestManager, Artist artist) { + this.requestManager = requestManager; + this.artist = artist; + } + + public static Builder from(@NonNull RequestManager requestManager, Artist artist) { + return new Builder(requestManager, artist); + } + + public PaletteBuilder generatePalette(Context context) { + return new PaletteBuilder(this, context); + } + + public BitmapBuilder asBitmap() { + return new BitmapBuilder(this); + } + + public Builder noCustomImage(boolean noCustomImage) { + this.noCustomImage = noCustomImage; + return this; + } + + public Builder forceDownload(boolean forceDownload) { + this.forceDownload = forceDownload; + return this; + } + + public DrawableRequestBuilder build() { + //noinspection unchecked + return createBaseRequest(requestManager, artist, noCustomImage, forceDownload) + .diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) + .error(DEFAULT_ERROR_IMAGE) + .animate(DEFAULT_ANIMATION) + .priority(Priority.LOW) + .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) + .signature(createSignature(artist)); + } + } + + public static class BitmapBuilder { + + private final Builder builder; + + BitmapBuilder(Builder builder) { + this.builder = builder; + } + + public BitmapRequestBuilder build() { + //noinspection unchecked + return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage, + builder.forceDownload) + .asBitmap() + .diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) + .error(DEFAULT_ERROR_IMAGE) + .animate(DEFAULT_ANIMATION) + .priority(Priority.LOW) + .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) + .signature(createSignature(builder.artist)); + } + } + + public static class PaletteBuilder { + + final Context context; + private final Builder builder; + + PaletteBuilder(Builder builder, Context context) { + this.builder = builder; + this.context = context; + } + + public BitmapRequestBuilder build() { + //noinspection unchecked + return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage, + builder.forceDownload) + .asBitmap() + .transcode(new BitmapPaletteTranscoder(context), BitmapPaletteWrapper.class) + .diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) + .error(DEFAULT_ERROR_IMAGE) + .animate(DEFAULT_ANIMATION) + .priority(Priority.LOW) + .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) + .signature(createSignature(builder.artist)); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/BlurTransformation.java b/app/src/main/java/code/name/monkey/retromusic/glide/BlurTransformation.java new file mode 100644 index 00000000..b4659b27 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/BlurTransformation.java @@ -0,0 +1,147 @@ +package code.name.monkey.retromusic.glide; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Build; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RSRuntimeException; +import android.renderscript.RenderScript; +import android.renderscript.ScriptIntrinsicBlur; +import android.support.annotation.FloatRange; +import android.support.annotation.NonNull; + +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; +import code.name.monkey.retromusic.helper.StackBlur; + +import code.name.monkey.retromusic.BuildConfig; +import code.name.monkey.retromusic.util.ImageUtil; + + +public class BlurTransformation extends BitmapTransformation { + static final float DEFAULT_BLUR_RADIUS = 5f; + + private Context context; + private float blurRadius; + private int sampling; + + private BlurTransformation(Builder builder) { + super(builder.context); + init(builder); + } + + private BlurTransformation(Builder builder, BitmapPool bitmapPool) { + super(bitmapPool); + init(builder); + } + + private void init(Builder builder) { + this.context = builder.context; + this.blurRadius = builder.blurRadius; + this.sampling = builder.sampling; + } + + @Override + protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { + int sampling; + if (this.sampling == 0) { + sampling = ImageUtil.calculateInSampleSize(toTransform.getWidth(), toTransform.getHeight(), 100); + } else { + sampling = this.sampling; + } + + int width = toTransform.getWidth(); + int height = toTransform.getHeight(); + int scaledWidth = width / sampling; + int scaledHeight = height / sampling; + + Bitmap out = pool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888); + if (out == null) { + out = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888); + } + + Canvas canvas = new Canvas(out); + canvas.scale(1 / (float) sampling, 1 / (float) sampling); + Paint paint = new Paint(); + paint.setFlags(Paint.FILTER_BITMAP_FLAG); + canvas.drawBitmap(toTransform, 0, 0, paint); + + if (Build.VERSION.SDK_INT >= 17) { + try { + final RenderScript rs = RenderScript.create(context.getApplicationContext()); + final Allocation input = Allocation.createFromBitmap(rs, out, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); + final Allocation output = Allocation.createTyped(rs, input.getType()); + final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); + + script.setRadius(blurRadius); + script.setInput(input); + script.forEach(output); + + output.copyTo(out); + + rs.destroy(); + + return out; + + } catch (RSRuntimeException e) { + // on some devices RenderScript.create() throws: android.support.v8.renderscript.RSRuntimeException: Error loading libRSSupport library + if (BuildConfig.DEBUG) e.printStackTrace(); + } + } + + return StackBlur.blur(out, blurRadius); + } + + @Override + public String getId() { + return "BlurTransformation(radius=" + blurRadius + ", sampling=" + sampling + ")"; + } + + public static class Builder { + private Context context; + private BitmapPool bitmapPool; + private float blurRadius = DEFAULT_BLUR_RADIUS; + private int sampling; + + public Builder(@NonNull Context context) { + this.context = context; + } + + /** + * @param blurRadius The radius to use. Must be between 0 and 25. Default is 5. + * @return the same Builder + */ + public Builder blurRadius(@FloatRange(from = 0.0f, to = 25.0f) float blurRadius) { + this.blurRadius = blurRadius; + return this; + } + + /** + * @param sampling The inSampleSize to use. Must be a power of 2, or 1 for no down sampling or 0 for auto detect sampling. Default is 0. + * @return the same Builder + */ + public Builder sampling(int sampling) { + this.sampling = sampling; + return this; + } + + /** + * @param bitmapPool The BitmapPool to use. + * @return the same Builder + */ + public Builder bitmapPool(BitmapPool bitmapPool) { + this.bitmapPool = bitmapPool; + return this; + } + + public BlurTransformation build() { + if (bitmapPool != null) { + return new BlurTransformation(this, bitmapPool); + } + return new BlurTransformation(this); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicColoredTarget.java b/app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicColoredTarget.java new file mode 100644 index 00000000..79fc23aa --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicColoredTarget.java @@ -0,0 +1,53 @@ +package code.name.monkey.retromusic.glide; + +import android.graphics.drawable.Drawable; +import android.widget.ImageView; + +import com.bumptech.glide.request.animation.GlideAnimation; + +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.util.PreferenceUtil; + +import static code.name.monkey.retromusic.util.RetroColorUtil.getColor; +import static code.name.monkey.retromusic.util.RetroColorUtil.getDominantColor; + + +public abstract class RetroMusicColoredTarget extends BitmapPaletteTarget { + + public RetroMusicColoredTarget(ImageView view) { + super(view); + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + onColorReady(getDefaultFooterColor()); + } + + @Override + public void onResourceReady(BitmapPaletteWrapper resource, + GlideAnimation glideAnimation) { + super.onResourceReady(resource, glideAnimation); + int defaultColor = getDefaultFooterColor(); + + int primaryColor = getColor(resource.getPalette(), defaultColor); + int dominantColor = getDominantColor(resource.getBitmap(), defaultColor); + + onColorReady(PreferenceUtil.getInstance(RetroApplication.getInstance()).isDominantColor() ? + dominantColor : primaryColor); + } + + protected int getDefaultFooterColor() { + return ATHUtil.resolveColor(getView().getContext(), R.attr.defaultFooterColor); + } + + protected int getAlbumArtistFooterColor() { + return ATHUtil.resolveColor(getView().getContext(), R.attr.cardBackgroundColor); + } + + public abstract void onColorReady(int color); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicGlideModule.java b/app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicGlideModule.java new file mode 100644 index 00000000..ae2074b1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicGlideModule.java @@ -0,0 +1,27 @@ +package code.name.monkey.retromusic.glide; + +import android.content.Context; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.GlideBuilder; +import com.bumptech.glide.module.GlideModule; +import code.name.monkey.retromusic.glide.artistimage.ArtistImage; +import code.name.monkey.retromusic.glide.artistimage.ArtistImageLoader; +import code.name.monkey.retromusic.glide.audiocover.AudioFileCover; +import code.name.monkey.retromusic.glide.audiocover.AudioFileCoverLoader; + +import java.io.InputStream; + + +public class RetroMusicGlideModule implements GlideModule { + @Override + public void applyOptions(Context context, GlideBuilder builder) { + + } + + @Override + public void registerComponents(Context context, Glide glide) { + glide.register(AudioFileCover.class, InputStream.class, new AudioFileCoverLoader.Factory()); + glide.register(ArtistImage.class, InputStream.class, new ArtistImageLoader.Factory(context)); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/SongGlideRequest.java b/app/src/main/java/code/name/monkey/retromusic/glide/SongGlideRequest.java new file mode 100644 index 00000000..24eb8e63 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/SongGlideRequest.java @@ -0,0 +1,124 @@ +package code.name.monkey.retromusic.glide; + +import android.content.Context; +import android.graphics.Bitmap; +import android.support.annotation.NonNull; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.audiocover.AudioFileCover; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import com.bumptech.glide.BitmapRequestBuilder; +import com.bumptech.glide.DrawableRequestBuilder; +import com.bumptech.glide.DrawableTypeRequest; +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.load.Key; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.resource.drawable.GlideDrawable; +import com.bumptech.glide.signature.MediaStoreSignature; + + +public class SongGlideRequest { + + static final DiskCacheStrategy DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.NONE; + static final int DEFAULT_ANIMATION = android.R.anim.fade_in; + static final int DEFAULT_ERROR_IMAGE = R.drawable.default_album_art; + + static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Song song, + boolean ignoreMediaStore) { + if (ignoreMediaStore) { + return requestManager.load(new AudioFileCover(song.data)); + } else { + return requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(song.albumId)); + } + } + + static Key createSignature(Song song) { + return new MediaStoreSignature("", song.dateModified, 0); + } + + public static class Builder { + + final RequestManager requestManager; + final Song song; + boolean ignoreMediaStore; + + private Builder(@NonNull RequestManager requestManager, Song song) { + this.requestManager = requestManager; + this.song = song; + } + + public static Builder from(@NonNull RequestManager requestManager, Song song) { + return new Builder(requestManager, song); + } + + public PaletteBuilder generatePalette(Context context) { + return new PaletteBuilder(this, context); + } + + public BitmapBuilder asBitmap() { + return new BitmapBuilder(this); + } + + public Builder checkIgnoreMediaStore(Context context) { + return ignoreMediaStore(PreferenceUtil.getInstance(context).ignoreMediaStoreArtwork()); + } + + Builder ignoreMediaStore(boolean ignoreMediaStore) { + this.ignoreMediaStore = ignoreMediaStore; + return this; + } + + public DrawableRequestBuilder build() { + //noinspection unchecked + return createBaseRequest(requestManager, song, ignoreMediaStore) + .diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) + .error(DEFAULT_ERROR_IMAGE) + .animate(DEFAULT_ANIMATION) + .signature(createSignature(song)); + } + } + + public static class BitmapBuilder { + + private final Builder builder; + + BitmapBuilder(Builder builder) { + this.builder = builder; + } + + public BitmapRequestBuilder build() { + //noinspection unchecked + return createBaseRequest(builder.requestManager, builder.song, builder.ignoreMediaStore) + .asBitmap() + .diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) + .error(DEFAULT_ERROR_IMAGE) + .animate(DEFAULT_ANIMATION) + .signature(createSignature(builder.song)); + } + } + + public static class PaletteBuilder { + + final Context context; + private final Builder builder; + + PaletteBuilder(Builder builder, Context context) { + this.builder = builder; + this.context = context; + } + + public BitmapRequestBuilder build() { + //noinspection unchecked + return createBaseRequest(builder.requestManager, builder.song, builder.ignoreMediaStore) + .asBitmap() + .transcode(new BitmapPaletteTranscoder(context), BitmapPaletteWrapper.class) + .diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) + .error(DEFAULT_ERROR_IMAGE) + .animate(DEFAULT_ANIMATION) + .signature(createSignature(builder.song)); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImage.java b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImage.java new file mode 100644 index 00000000..ad858466 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImage.java @@ -0,0 +1,12 @@ +package code.name.monkey.retromusic.glide.artistimage; + + +public class ArtistImage { + public final String artistName; + public final boolean skipOkHttpCache; + + public ArtistImage(String artistName, boolean skipOkHttpCache) { + this.artistName = artistName; + this.skipOkHttpCache = skipOkHttpCache; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageFetcher.java b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageFetcher.java new file mode 100644 index 00000000..5e65535d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageFetcher.java @@ -0,0 +1,83 @@ +package code.name.monkey.retromusic.glide.artistimage; + +import android.content.Context; + +import com.bumptech.glide.Priority; +import com.bumptech.glide.load.data.DataFetcher; +import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.load.model.ModelLoader; +import code.name.monkey.retromusic.rest.LastFMRestClient; +import code.name.monkey.retromusic.rest.model.LastFmArtist; + +import code.name.monkey.retromusic.util.LastFMUtil; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.RetroUtil; + +import java.io.IOException; +import java.io.InputStream; + +import retrofit2.Response; + + +public class ArtistImageFetcher implements DataFetcher { + public static final String TAG = ArtistImageFetcher.class.getSimpleName(); + private final LastFMRestClient lastFMRestClient; + private final ArtistImage model; + private final int width; + private final int height; + private Context context; + private ModelLoader urlLoader; + private volatile boolean isCancelled; + private DataFetcher urlFetcher; + + public ArtistImageFetcher(Context context, LastFMRestClient lastFMRestClient, ArtistImage model, ModelLoader urlLoader, int width, int height) { + this.context = context; + this.lastFMRestClient = lastFMRestClient; + this.model = model; + this.urlLoader = urlLoader; + this.width = width; + this.height = height; + } + + @Override + public String getId() { + // makes sure we never ever return null here + return String.valueOf(model.artistName); + } + + @Override + public InputStream loadData(Priority priority) throws Exception { + if (!MusicUtil.isArtistNameUnknown(model.artistName) && RetroUtil.isAllowedToDownloadMetadata(context)) { + Response response = lastFMRestClient.getApiService().getArtistInfo(model.artistName, null, model.skipOkHttpCache ? "no-cache" : null).execute(); + + if (!response.isSuccessful()) { + throw new IOException("Request failed with code: " + response.code()); + } + + LastFmArtist lastFmArtist = response.body(); + + if (isCancelled) return null; + + GlideUrl url = new GlideUrl(LastFMUtil.getLargestArtistImageUrl(lastFmArtist.getArtist().getImage())); + urlFetcher = urlLoader.getResourceFetcher(url, width, height); + + return urlFetcher.loadData(priority); + } + return null; + } + + @Override + public void cleanup() { + if (urlFetcher != null) { + urlFetcher.cleanup(); + } + } + + @Override + public void cancel() { + isCancelled = true; + if (urlFetcher != null) { + urlFetcher.cancel(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.java b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.java new file mode 100644 index 00000000..09392ced --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.java @@ -0,0 +1,68 @@ +package code.name.monkey.retromusic.glide.artistimage; + +import android.content.Context; + +import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader; +import com.bumptech.glide.load.data.DataFetcher; +import com.bumptech.glide.load.model.GenericLoaderFactory; +import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.load.model.ModelLoader; +import com.bumptech.glide.load.model.ModelLoaderFactory; +import com.bumptech.glide.load.model.stream.StreamModelLoader; +import code.name.monkey.retromusic.rest.LastFMRestClient; + +import java.io.InputStream; +import java.util.concurrent.TimeUnit; + +import okhttp3.OkHttpClient; + + + +public class ArtistImageLoader implements StreamModelLoader { + // we need these very low values to make sure our artist image loading calls doesn't block the image loading queue + private static final int TIMEOUT = 500; + + private Context context; + private LastFMRestClient lastFMClient; + private ModelLoader urlLoader; + + public ArtistImageLoader(Context context, LastFMRestClient lastFMRestClient, ModelLoader urlLoader) { + this.context = context; + this.lastFMClient = lastFMRestClient; + this.urlLoader = urlLoader; + } + + @Override + public DataFetcher getResourceFetcher(ArtistImage model, int width, int height) { + return new ArtistImageFetcher(context, lastFMClient, model, urlLoader, width, height); + } + + public static class Factory implements ModelLoaderFactory { + private LastFMRestClient lastFMClient; + private OkHttpUrlLoader.Factory okHttpFactory; + + public Factory(Context context) { + okHttpFactory = new OkHttpUrlLoader.Factory(new OkHttpClient.Builder() + .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS) + .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS) + .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS) + .build()); + lastFMClient = new LastFMRestClient(LastFMRestClient.createDefaultOkHttpClientBuilder(context) + .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS) + .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS) + .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS) + .build()); + } + + @Override + public ModelLoader build(Context context, GenericLoaderFactory factories) { + return new ArtistImageLoader(context, lastFMClient, okHttpFactory.build(context, factories)); + } + + @Override + public void teardown() { + okHttpFactory.teardown(); + } + } +} + diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCover.java b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCover.java new file mode 100644 index 00000000..3a163bc1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCover.java @@ -0,0 +1,10 @@ +package code.name.monkey.retromusic.glide.audiocover; + + +public class AudioFileCover { + public final String filePath; + + public AudioFileCover(String filePath) { + this.filePath = filePath; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverFetcher.java b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverFetcher.java new file mode 100644 index 00000000..8985da7c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverFetcher.java @@ -0,0 +1,95 @@ +package code.name.monkey.retromusic.glide.audiocover; + +import android.media.MediaMetadataRetriever; + +import com.bumptech.glide.Priority; +import com.bumptech.glide.load.data.DataFetcher; + +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; +import org.jaudiotagger.audio.mp3.MP3File; +import org.jaudiotagger.tag.TagException; +import org.jaudiotagger.tag.images.Artwork; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + + +public class AudioFileCoverFetcher implements DataFetcher { + private static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg", "cover.png", "album.png", "folder.png"}; + private final AudioFileCover model; + private FileInputStream stream; + + public AudioFileCoverFetcher(AudioFileCover model) { + this.model = model; + } + + @Override + public String getId() { + // makes sure we never ever return null here + return String.valueOf(model.filePath); + } + + @Override + public InputStream loadData(Priority priority) throws Exception { + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + try { + retriever.setDataSource(model.filePath); + byte[] picture = retriever.getEmbeddedPicture(); + if (picture != null) { + return new ByteArrayInputStream(picture); + } else { + return fallback(model.filePath); + } + } finally { + retriever.release(); + } + } + + private InputStream fallback(String path) throws FileNotFoundException { + // Method 1: use embedded high resolution album art if there is any + try { + MP3File mp3File = new MP3File(path); + if (mp3File.hasID3v2Tag()) { + Artwork art = mp3File.getTag().getFirstArtwork(); + if (art != null) { + byte[] imageData = art.getBinaryData(); + return new ByteArrayInputStream(imageData); + } + } + // If there are any exceptions, we ignore them and continue to the other fallback method + } catch (ReadOnlyFileException | InvalidAudioFrameException | TagException | IOException ignored) { + } + + // Method 2: look for album art in external files + File parent = new File(path).getParentFile(); + for (String fallback : FALLBACKS) { + File cover = new File(parent, fallback); + if (cover.exists()) { + return stream = new FileInputStream(cover); + } + } + return null; + } + + @Override + public void cleanup() { + // already cleaned up in loadData and ByteArrayInputStream will be GC'd + if (stream != null) { + try { + stream.close(); + } catch (IOException ignore) { + // can't do much about it + } + } + } + + @Override + public void cancel() { + // cannot cancel + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverLoader.java b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverLoader.java new file mode 100644 index 00000000..2b02c9b3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverLoader.java @@ -0,0 +1,32 @@ +package code.name.monkey.retromusic.glide.audiocover; + +import android.content.Context; + +import com.bumptech.glide.load.data.DataFetcher; +import com.bumptech.glide.load.model.GenericLoaderFactory; +import com.bumptech.glide.load.model.ModelLoader; +import com.bumptech.glide.load.model.ModelLoaderFactory; +import com.bumptech.glide.load.model.stream.StreamModelLoader; + +import java.io.InputStream; + + +public class AudioFileCoverLoader implements StreamModelLoader { + + @Override + public DataFetcher getResourceFetcher(AudioFileCover model, int width, int height) { + return new AudioFileCoverFetcher(model); + } + + public static class Factory implements ModelLoaderFactory { + @Override + public ModelLoader build(Context context, GenericLoaderFactory factories) { + return new AudioFileCoverLoader(); + } + + @Override + public void teardown() { + } + } +} + diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteResource.java b/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteResource.java new file mode 100644 index 00000000..201e43b7 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteResource.java @@ -0,0 +1,34 @@ +package code.name.monkey.retromusic.glide.palette; + +import com.bumptech.glide.load.engine.Resource; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.util.Util; + + +public class BitmapPaletteResource implements Resource { + + private final BitmapPaletteWrapper bitmapPaletteWrapper; + private final BitmapPool bitmapPool; + + public BitmapPaletteResource(BitmapPaletteWrapper bitmapPaletteWrapper, BitmapPool bitmapPool) { + this.bitmapPaletteWrapper = bitmapPaletteWrapper; + this.bitmapPool = bitmapPool; + } + + @Override + public BitmapPaletteWrapper get() { + return bitmapPaletteWrapper; + } + + @Override + public int getSize() { + return Util.getBitmapByteSize(bitmapPaletteWrapper.getBitmap()); + } + + @Override + public void recycle() { + if (!bitmapPool.put(bitmapPaletteWrapper.getBitmap())) { + bitmapPaletteWrapper.getBitmap().recycle(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteTarget.java b/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteTarget.java new file mode 100644 index 00000000..662db217 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteTarget.java @@ -0,0 +1,17 @@ +package code.name.monkey.retromusic.glide.palette; + +import android.widget.ImageView; +import com.bumptech.glide.request.target.ImageViewTarget; + +public class BitmapPaletteTarget extends ImageViewTarget { + + public BitmapPaletteTarget(ImageView view) { + super(view); + } + + @Override + protected void setResource(BitmapPaletteWrapper bitmapPaletteWrapper) { + view.setImageBitmap(bitmapPaletteWrapper.getBitmap()); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteTranscoder.java b/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteTranscoder.java new file mode 100644 index 00000000..ad5cf47a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteTranscoder.java @@ -0,0 +1,34 @@ +package code.name.monkey.retromusic.glide.palette; + +import android.content.Context; +import android.graphics.Bitmap; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.Resource; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; +import code.name.monkey.retromusic.util.RetroColorUtil; + +public class BitmapPaletteTranscoder implements ResourceTranscoder { + private final BitmapPool bitmapPool; + + public BitmapPaletteTranscoder(Context context) { + this(Glide.get(context).getBitmapPool()); + } + + public BitmapPaletteTranscoder(BitmapPool bitmapPool) { + this.bitmapPool = bitmapPool; + } + + @Override + public Resource transcode(Resource bitmapResource) { + Bitmap bitmap = bitmapResource.get(); + BitmapPaletteWrapper bitmapPaletteWrapper = new BitmapPaletteWrapper(bitmap, RetroColorUtil.generatePalette(bitmap)); + return new BitmapPaletteResource(bitmapPaletteWrapper, bitmapPool); + } + + @Override + public String getId() { + return "BitmapPaletteTranscoder.code.name.monkey.retromusic.glide.palette"; + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteWrapper.java b/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteWrapper.java new file mode 100644 index 00000000..e7c53bea --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/palette/BitmapPaletteWrapper.java @@ -0,0 +1,22 @@ +package code.name.monkey.retromusic.glide.palette; + +import android.graphics.Bitmap; +import android.support.v7.graphics.Palette; + +public class BitmapPaletteWrapper { + private final Bitmap mBitmap; + private final Palette mPalette; + + public BitmapPaletteWrapper(Bitmap bitmap, Palette palette) { + mBitmap = bitmap; + mPalette = palette; + } + + public Bitmap getBitmap() { + return mBitmap; + } + + public Palette getPalette() { + return mPalette; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/EqualizerHelper.java b/app/src/main/java/code/name/monkey/retromusic/helper/EqualizerHelper.java new file mode 100644 index 00000000..12f98ba4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/EqualizerHelper.java @@ -0,0 +1,171 @@ +package code.name.monkey.retromusic.helper; + +import android.media.audiofx.BassBoost; +import android.media.audiofx.Equalizer; +import android.media.audiofx.Virtualizer; +import android.util.Log; + +import code.name.monkey.retromusic.interfaces.EqualizerInterface; + +/** + * @author Hemanth S (h4h13). + */ + +public class EqualizerHelper implements EqualizerInterface { + private static final String TAG = "EqualizerHelper"; + private static volatile EqualizerHelper ourInstance; + private Equalizer mEqualizer; + private BassBoost mBassBoost; + private Virtualizer mVirtualizer; + + private int mMaxLevel, mMinLevel; + private boolean isRunning = false; + + private EqualizerHelper() { + + //Prevent form the reflection api. + if (ourInstance != null) { + throw new RuntimeException("Use getInstance() method to get the single instance of this class."); + } + + int i = MusicPlayerRemote.getAudioSessionId(); + + mEqualizer = new Equalizer(100, i); + if (mEqualizer == null) { + Log.i(TAG, "onCreate: Equalizer is null"); + return; + } + mEqualizer.setEnabled(true); + + + mBassBoost = new BassBoost(100, i); + if (mBassBoost == null) { + Log.i(TAG, "onCreate: BassBoost is null"); + return; + } + + mVirtualizer = new Virtualizer(100, i); + if (mVirtualizer == null) { + Log.i(TAG, "onCreate: Virtualizer is null"); + return; + } + + mMaxLevel = (int) mEqualizer.getBandLevelRange()[1]; + mMinLevel = (int) mEqualizer.getBandLevelRange()[0]; + + Log.i(TAG, "onCreate: " + mMaxLevel + " " + mMinLevel); + isRunning = true; + } + + public static EqualizerHelper getInstance() { + //Double check locking pattern + if (ourInstance == null) {//Check for the first time + + synchronized (EqualizerHelper.class) {//Check for the second time. + + //if there is no instance available... create new one + if (ourInstance == null) { + ourInstance = new EqualizerHelper(); + } + } + } + return ourInstance; + } + + //Make singleton from serialize and deserialize operation. + protected EqualizerHelper readResolve() { + return getInstance(); + } + + @Override + public Equalizer getEqualizer() { + return mEqualizer; + } + + @Override + public BassBoost getBassBoost() { + return mBassBoost; + } + + @Override + public Virtualizer getVirtualizer() { + return mVirtualizer; + } + + @Override + public int getBandLevelLow() { + return mMinLevel; + } + + @Override + public int getBandLevelHigh() { + return mMaxLevel; + } + + @Override + public int getNumberOfBands() { + return (int) mEqualizer.getNumberOfBands(); + } + + @Override + public int getCenterFreq(int band) { + return (int) mEqualizer.getCenterFreq((short) band); + } + + + @Override + public int getBandLevel(int band) { + return (int) mEqualizer.getBandLevel((short) band); + } + + @Override + public void setBandLevel(int band, int level) { + mEqualizer.setBandLevel((short) band, (short) level); + } + + @Override + public boolean isBassBoostEnabled() { + return mBassBoost.getEnabled(); + } + + @Override + public void setBassBoostEnabled(boolean isEnabled) { + mBassBoost.setEnabled(isEnabled); + } + + @Override + public int getBassBoostStrength() { + return (int) mBassBoost.getRoundedStrength(); + } + + @Override + public void setBassBoostStrength(int strength) { + mBassBoost.setStrength((short) strength); + } + + @Override + public boolean isVirtualizerEnabled() { + return mVirtualizer.getEnabled(); + } + + @Override + public void setVirtualizerEnabled(boolean isEnabled) { + mVirtualizer.setEnabled(isEnabled); + } + + @Override + public int getVirtualizerStrength() { + return mVirtualizer.getRoundedStrength(); + } + + @Override + public void setVirtualizerStrength(int strength) { + mVirtualizer.setStrength((short) strength); + } + + @Override + public boolean isRunning() { + return isRunning; + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/HorizontalAdapterHelper.java b/app/src/main/java/code/name/monkey/retromusic/helper/HorizontalAdapterHelper.java new file mode 100644 index 00000000..fd1ae91a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/HorizontalAdapterHelper.java @@ -0,0 +1,36 @@ +package code.name.monkey.retromusic.helper; + +import android.content.Context; +import android.view.ViewGroup; +import code.name.monkey.retromusic.R; + + +public class HorizontalAdapterHelper { + + public static final int LAYOUT_RES = R.layout.item_image; + + public static final int TYPE_FIRST = 1; + public static final int TYPE_MIDDLE = 2; + public static final int TYPE_LAST = 3; + + public static void applyMarginToLayoutParams(Context context, + ViewGroup.MarginLayoutParams layoutParams, int viewType) { + int listMargin = context.getResources() + .getDimensionPixelSize(R.dimen.now_playing_top_margin); + if (viewType == TYPE_FIRST) { + layoutParams.leftMargin = listMargin; + } else if (viewType == TYPE_LAST) { + layoutParams.rightMargin = listMargin; + } + } + + public static int getItemViewtype(int position, int itemCount) { + if (position == 0) { + return TYPE_FIRST; + } else if (position == itemCount - 1) { + return TYPE_LAST; + } else { + return TYPE_MIDDLE; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/M3UConstants.java b/app/src/main/java/code/name/monkey/retromusic/helper/M3UConstants.java new file mode 100644 index 00000000..e6ffdf39 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/M3UConstants.java @@ -0,0 +1,8 @@ +package code.name.monkey.retromusic.helper; + +public interface M3UConstants { + String EXTENSION = "m3u"; + String HEADER = "#EXTM3U"; + String ENTRY = "#EXTINF:"; + String DURATION_SEPARATOR = ","; +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.java b/app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.java new file mode 100644 index 00000000..5e9416eb --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.java @@ -0,0 +1,58 @@ +package code.name.monkey.retromusic.helper; + +import android.content.Context; +import android.support.annotation.NonNull; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; + +import code.name.monkey.retromusic.loaders.PlaylistSongsLoader; +import code.name.monkey.retromusic.model.AbsCustomPlaylist; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.Song; +import io.reactivex.Observable; +import io.reactivex.ObservableEmitter; + +public class M3UWriter implements M3UConstants { + public static final String TAG = M3UWriter.class.getSimpleName(); + + public static Observable write(@NonNull Context context, + @NonNull File dir, @NonNull Playlist playlist) { + if (!dir.exists()) //noinspection ResultOfMethodCallIgnored + dir.mkdirs(); + File file = new File(dir, playlist.name.concat("." + EXTENSION)); + + if (playlist instanceof AbsCustomPlaylist) { + return Observable.create(e -> { + ((AbsCustomPlaylist) playlist).getSongs(context).subscribe(songs -> { + saveSongsToFile(file, e, songs); + }); + }); + } else + return Observable.create(e -> + PlaylistSongsLoader.getPlaylistSongList(context, playlist.id) + .subscribe(songs -> { + saveSongsToFile(file, e, songs); + })); + } + + private static void saveSongsToFile(File file, ObservableEmitter e, ArrayList songs) throws IOException { + if (songs.size() > 0) { + BufferedWriter bw = new BufferedWriter(new FileWriter(file)); + bw.write(HEADER); + for (Song song : songs) { + bw.newLine(); + bw.write(ENTRY + song.duration + DURATION_SEPARATOR + song.artistName + " - " + song.title); + bw.newLine(); + bw.write(song.data); + } + + bw.close(); + } + e.onNext(file); + e.onComplete(); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.java b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.java new file mode 100644 index 00000000..ccd21773 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.java @@ -0,0 +1,480 @@ +package code.name.monkey.retromusic.helper; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.content.ServiceConnection; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.os.IBinder; +import android.provider.DocumentsContract; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.util.ArrayList; +import java.util.Random; +import java.util.WeakHashMap; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.util.PreferenceUtil; +import io.reactivex.schedulers.Schedulers; + + +public class MusicPlayerRemote { + + public static final String TAG = MusicPlayerRemote.class.getSimpleName(); + private static final WeakHashMap mConnectionMap = new WeakHashMap<>(); + @Nullable + public static MusicService musicService; + + public static ServiceToken bindToService(@NonNull final Context context, + final ServiceConnection callback) { + Activity realActivity = ((Activity) context).getParent(); + if (realActivity == null) { + realActivity = (Activity) context; + } + + final ContextWrapper contextWrapper = new ContextWrapper(realActivity); + contextWrapper.startService(new Intent(contextWrapper, MusicService.class)); + + final ServiceBinder binder = new ServiceBinder(callback); + + if (contextWrapper.bindService(new Intent().setClass(contextWrapper, MusicService.class), binder, Context.BIND_AUTO_CREATE)) { + mConnectionMap.put(contextWrapper, binder); + return new ServiceToken(contextWrapper); + } + return null; + } + + public static void unbindFromService(@Nullable final ServiceToken token) { + if (token == null) { + return; + } + final ContextWrapper mContextWrapper = token.mWrappedContext; + final ServiceBinder mBinder = mConnectionMap.remove(mContextWrapper); + if (mBinder == null) { + return; + } + mContextWrapper.unbindService(mBinder); + if (mConnectionMap.isEmpty()) { + musicService = null; + } + } + + @Nullable + private static String getFilePathFromUri(Context context, Uri uri) { + Cursor cursor = null; + final String column = "_data"; + final String[] projection = { + column + }; + + try { + cursor = context.getContentResolver().query(uri, projection, null, null, + null); + if (cursor != null && cursor.moveToFirst()) { + final int column_index = cursor.getColumnIndexOrThrow(column); + return cursor.getString(column_index); + } + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + } finally { + if (cursor != null) + cursor.close(); + } + return null; + } + + /** + * Async + */ + public static void playSongAt(final int position) { + if (musicService != null) { + musicService.playSongAt(position); + } + } + + public static void pauseSong() { + if (musicService != null) { + musicService.pause(); + } + } + + /** + * Async + */ + public static void playNextSong() { + if (musicService != null) { + musicService.playNextSong(true); + } + } + + /** + * Async + */ + public static void playPreviousSong() { + if (musicService != null) { + musicService.playPreviousSong(true); + } + } + + /** + * Async + */ + public static void back() { + if (musicService != null) { + musicService.back(true); + } + } + + public static boolean isPlaying() { + return musicService != null && musicService.isPlaying(); + } + + public static void resumePlaying() { + if (musicService != null) { + musicService.play(); + } + } + + /** + * Async + */ + public static void openQueue(final ArrayList queue, final int startPosition, final boolean startPlaying) { + if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) { + musicService.openQueue(queue, startPosition, startPlaying); + if (PreferenceUtil.getInstance(musicService).isShuffleModeOn()) + setShuffleMode(MusicService.SHUFFLE_MODE_NONE); + } + } + + /** + * Async + */ + public static void openAndShuffleQueue(final ArrayList queue, boolean startPlaying) { + int startPosition = 0; + if (!queue.isEmpty()) { + startPosition = new Random().nextInt(queue.size()); + } + + if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) { + openQueue(queue, startPosition, startPlaying); + setShuffleMode(MusicService.SHUFFLE_MODE_SHUFFLE); + } + } + + private static boolean tryToHandleOpenPlayingQueue(final ArrayList queue, final int startPosition, final boolean startPlaying) { + if (getPlayingQueue() == queue) { + if (startPlaying) { + playSongAt(startPosition); + } else { + setPosition(startPosition); + } + return true; + } + return false; + } + + public static Song getCurrentSong() { + if (musicService != null) { + return musicService.getCurrentSong(); + } + return Song.EMPTY_SONG; + } + + public static int getPosition() { + if (musicService != null) { + return musicService.getPosition(); + } + return -1; + } + + /** + * Async + */ + public static void setPosition(final int position) { + if (musicService != null) { + musicService.setPosition(position); + } + } + + public static ArrayList getPlayingQueue() { + if (musicService != null) { + return musicService.getPlayingQueue(); + } + return new ArrayList<>(); + } + + public static int getSongProgressMillis() { + if (musicService != null) { + return musicService.getSongProgressMillis(); + } + return -1; + } + + public static int getSongDurationMillis() { + if (musicService != null) { + return musicService.getSongDurationMillis(); + } + return -1; + } + + public static long getQueueDurationMillis(int position) { + if (musicService != null) { + return musicService.getQueueDurationMillis(position); + } + return -1; + } + + public static int seekTo(int millis) { + if (musicService != null) { + return musicService.seek(millis); + } + return -1; + } + + public static int getRepeatMode() { + if (musicService != null) { + return musicService.getRepeatMode(); + } + return MusicService.REPEAT_MODE_NONE; + } + + public static int getShuffleMode() { + if (musicService != null) { + return musicService.getShuffleMode(); + } + return MusicService.SHUFFLE_MODE_NONE; + } + + public static boolean cycleRepeatMode() { + if (musicService != null) { + musicService.cycleRepeatMode(); + return true; + } + return false; + } + + public static boolean toggleShuffleMode() { + if (musicService != null) { + musicService.toggleShuffle(); + return true; + } + return false; + } + + public static boolean setShuffleMode(final int shuffleMode) { + if (musicService != null) { + musicService.setShuffleMode(shuffleMode); + return true; + } + return false; + } + + public static boolean playNext(Song song) { + if (musicService != null) { + if (getPlayingQueue().size() > 0) { + musicService.addSong(getPosition() + 1, song); + } else { + ArrayList queue = new ArrayList<>(); + queue.add(song); + openQueue(queue, 0, false); + } + Toast.makeText(musicService, musicService.getResources().getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show(); + return true; + } + return false; + } + + public static boolean playNext(@NonNull ArrayList songs) { + if (musicService != null) { + if (getPlayingQueue().size() > 0) { + musicService.addSongs(getPosition() + 1, songs); + } else { + openQueue(songs, 0, false); + } + final String toast = songs.size() == 1 ? musicService.getResources().getString(R.string.added_title_to_playing_queue) : musicService.getResources().getString(R.string.added_x_titles_to_playing_queue, songs.size()); + Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show(); + return true; + } + return false; + } + + public static boolean enqueue(Song song) { + if (musicService != null) { + if (getPlayingQueue().size() > 0) { + musicService.addSong(song); + } else { + ArrayList queue = new ArrayList<>(); + queue.add(song); + openQueue(queue, 0, false); + } + Toast.makeText(musicService, musicService.getResources().getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show(); + return true; + } + return false; + } + + public static boolean enqueue(@NonNull ArrayList songs) { + if (musicService != null) { + if (getPlayingQueue().size() > 0) { + musicService.addSongs(songs); + } else { + openQueue(songs, 0, false); + } + final String toast = songs.size() == 1 ? musicService.getResources().getString(R.string.added_title_to_playing_queue) : musicService.getResources().getString(R.string.added_x_titles_to_playing_queue, songs.size()); + Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show(); + return true; + } + return false; + } + + public static boolean removeFromQueue(@NonNull Song song) { + if (musicService != null) { + musicService.removeSong(song); + return true; + } + return false; + } + + public static boolean removeFromQueue(int position) { + if (musicService != null && position >= 0 && position < getPlayingQueue().size()) { + musicService.removeSong(position); + return true; + } + return false; + } + + public static boolean moveSong(int from, int to) { + if (musicService != null && from >= 0 && to >= 0 && from < getPlayingQueue().size() && to < getPlayingQueue().size()) { + musicService.moveSong(from, to); + return true; + } + return false; + } + + public static boolean clearQueue() { + if (musicService != null) { + musicService.clearQueue(); + return true; + } + return false; + } + + public static int getAudioSessionId() { + if (musicService != null) { + return musicService.getAudioSessionId(); + } + return -1; + } + + public static void playFromUri(Uri uri) { + if (musicService != null) { + ArrayList songs = null; + if (uri.getScheme() != null && uri.getAuthority() != null) { + if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) { + String songId = null; + if (uri.getAuthority().equals("com.android.providers.media.documents")) { + songId = getSongIdFromMediaProvider(uri); + } else if (uri.getAuthority().equals("media")) { + songId = uri.getLastPathSegment(); + } + if (songId != null) { + /* songs = SongLoader.getSongs(SongLoader.makeSongCursor( + musicService, + MediaStore.Audio.AudioColumns._ID + "=?", + new String[]{songId} + ));*/ + songs = SongLoader.getSongs(SongLoader.makeSongCursor( + musicService, + MediaStore.Audio.AudioColumns._ID + "=?", + new String[]{songId})) + .subscribeOn(Schedulers.io()).blockingFirst(); + } + } + } + if (songs == null) { + File songFile = null; + if (uri.getAuthority() != null && uri.getAuthority().equals("com.android.externalstorage.documents")) { + songFile = new File(Environment.getExternalStorageDirectory(), uri.getPath().split(":", 2)[1]); + } + if (songFile == null) { + String path = getFilePathFromUri(musicService, uri); + if (path != null) + songFile = new File(path); + } + if (songFile == null && uri.getPath() != null) { + songFile = new File(uri.getPath()); + } + if (songFile != null) { + songs = SongLoader.getSongs(SongLoader.makeSongCursor( + musicService, + MediaStore.Audio.AudioColumns.DATA + "=?", + new String[]{songFile.getAbsolutePath()} + )).blockingFirst(); + } + } + if (songs != null && !songs.isEmpty()) { + openQueue(songs, 0, true); + } else { + //TODO the file is not listed in the media store + } + } + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + private static String getSongIdFromMediaProvider(Uri uri) { + return DocumentsContract.getDocumentId(uri).split(":")[1]; + } + + public static boolean isServiceConnected() { + return musicService != null; + } + + + public static final class ServiceBinder implements ServiceConnection { + private final ServiceConnection mCallback; + + ServiceBinder(final ServiceConnection callback) { + mCallback = callback; + } + + @Override + public void onServiceConnected(final ComponentName className, final IBinder service) { + MusicService.MusicBinder binder = (MusicService.MusicBinder) service; + musicService = binder.getService(); + if (mCallback != null) { + mCallback.onServiceConnected(className, service); + } + } + + @Override + public void onServiceDisconnected(final ComponentName className) { + if (mCallback != null) { + mCallback.onServiceDisconnected(className); + } + musicService = null; + } + } + + public static final class ServiceToken { + ContextWrapper mWrappedContext; + + ServiceToken(final ContextWrapper context) { + mWrappedContext = context; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/MusicProgressViewUpdateHelper.java b/app/src/main/java/code/name/monkey/retromusic/helper/MusicProgressViewUpdateHelper.java new file mode 100644 index 00000000..f3f886c2 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/MusicProgressViewUpdateHelper.java @@ -0,0 +1,71 @@ +package code.name.monkey.retromusic.helper; + +import android.os.Handler; +import android.os.Message; +import android.support.annotation.NonNull; + + +public class MusicProgressViewUpdateHelper extends Handler { + private static final int CMD_REFRESH_PROGRESS_VIEWS = 1; + + private static final int MIN_INTERVAL = 20; + private static final int UPDATE_INTERVAL_PLAYING = 1000; + private static final int UPDATE_INTERVAL_PAUSED = 500; + + private Callback callback; + private int intervalPlaying; + private int intervalPaused; + + public void start() { + queueNextRefresh(1); + } + + public void stop() { + removeMessages(CMD_REFRESH_PROGRESS_VIEWS); + } + + public MusicProgressViewUpdateHelper(Callback callback) { + this.callback = callback; + this.intervalPlaying = UPDATE_INTERVAL_PLAYING; + this.intervalPaused = UPDATE_INTERVAL_PAUSED; + } + + public MusicProgressViewUpdateHelper(Callback callback, int intervalPlaying, int intervalPaused) { + this.callback = callback; + this.intervalPlaying = intervalPlaying; + this.intervalPaused = intervalPaused; + } + + @Override + public void handleMessage(@NonNull Message msg) { + super.handleMessage(msg); + if (msg.what == CMD_REFRESH_PROGRESS_VIEWS) { + queueNextRefresh(refreshProgressViews()); + } + } + + private int refreshProgressViews() { + final int progressMillis = MusicPlayerRemote.getSongProgressMillis(); + final int totalMillis = MusicPlayerRemote.getSongDurationMillis(); + + callback.onUpdateProgressViews(progressMillis, totalMillis); + + if (!MusicPlayerRemote.isPlaying()) { + return intervalPaused; + } + + final int remainingMillis = intervalPlaying - progressMillis % intervalPlaying; + + return Math.max(MIN_INTERVAL, remainingMillis); + } + + private void queueNextRefresh(final long delay) { + final Message message = obtainMessage(CMD_REFRESH_PROGRESS_VIEWS); + removeMessages(CMD_REFRESH_PROGRESS_VIEWS); + sendMessageDelayed(message, delay); + } + + public interface Callback { + void onUpdateProgressViews(int progress, int total); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/PlayPauseButtonOnClickHandler.java b/app/src/main/java/code/name/monkey/retromusic/helper/PlayPauseButtonOnClickHandler.java new file mode 100644 index 00000000..4d69a5a4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/PlayPauseButtonOnClickHandler.java @@ -0,0 +1,15 @@ +package code.name.monkey.retromusic.helper; + +import android.view.View; + + +public class PlayPauseButtonOnClickHandler implements View.OnClickListener { + @Override + public void onClick(View v) { + if (MusicPlayerRemote.isPlaying()) { + MusicPlayerRemote.pauseSong(); + } else { + MusicPlayerRemote.resumePlaying(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/SearchQueryHelper.java b/app/src/main/java/code/name/monkey/retromusic/helper/SearchQueryHelper.java new file mode 100644 index 00000000..fb8c99e1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/SearchQueryHelper.java @@ -0,0 +1,91 @@ +package code.name.monkey.retromusic.helper; + +import android.app.SearchManager; +import android.content.Context; +import android.os.Bundle; +import android.provider.MediaStore; +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.model.Song; + + +public class SearchQueryHelper { + private static final String TITLE_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.TITLE + ") = ?"; + private static final String ALBUM_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ALBUM + ") = ?"; + private static final String ARTIST_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ARTIST + ") = ?"; + private static final String AND = " AND "; + private static ArrayList songs = new ArrayList<>(); + + public static ArrayList getSongs() { + return songs; + } + + public static void setSongs(ArrayList songs) { + SearchQueryHelper.songs = songs; + } + + @NonNull + public static ArrayList getSongs(@NonNull final Context context, @NonNull final Bundle extras) { + final String query = extras.getString(SearchManager.QUERY, null); + final String artistName = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST, null); + final String albumName = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM, null); + final String titleName = extras.getString(MediaStore.EXTRA_MEDIA_TITLE, null); + + ArrayList songs = new ArrayList<>(); + if (artistName != null && albumName != null && titleName != null) { + songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), albumName.toLowerCase(), titleName.toLowerCase()})).blockingFirst(); + } + if (!songs.isEmpty()) { + return songs; + } + if (artistName != null && titleName != null) { + songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), titleName.toLowerCase()})).blockingFirst(); + } + if (!songs.isEmpty()) { + return songs; + } + if (albumName != null && titleName != null) { + songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{albumName.toLowerCase(), titleName.toLowerCase()})).blockingFirst(); + } + if (!songs.isEmpty()) { + return songs; + } + if (artistName != null) { + songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, new String[]{artistName.toLowerCase()})).blockingFirst(); + } + if (!songs.isEmpty()) { + return songs; + } + if (albumName != null) { + songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, new String[]{albumName.toLowerCase()})).blockingFirst(); + } + if (!songs.isEmpty()) { + return songs; + } + if (titleName != null) { + songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, new String[]{titleName.toLowerCase()})).blockingFirst(); + } + if (!songs.isEmpty()) { + return songs; + } + songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, new String[]{query.toLowerCase()})).blockingFirst(); + + if (!songs.isEmpty()) { + return songs; + } + songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, new String[]{query.toLowerCase()})).blockingFirst(); + if (!songs.isEmpty()) { + return songs; + } + songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, new String[]{query.toLowerCase()})).blockingFirst(); + if (!songs.isEmpty()) { + return songs; + } + return new ArrayList(); + } + + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/ShuffleHelper.java b/app/src/main/java/code/name/monkey/retromusic/helper/ShuffleHelper.java new file mode 100644 index 00000000..5e7b4182 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/ShuffleHelper.java @@ -0,0 +1,25 @@ +package code.name.monkey.retromusic.helper; + +import android.support.annotation.NonNull; + +import code.name.monkey.retromusic.model.Song; + +import java.util.Collections; +import java.util.List; + + +public class ShuffleHelper { + + public static void makeShuffleList(@NonNull List listToShuffle, final int current) { + if (listToShuffle.isEmpty()) return; + if (current >= 0) { + Song song = listToShuffle.remove(current); + Collections.shuffle(listToShuffle); + listToShuffle.add(0, song); + } else { + Collections.shuffle(listToShuffle); + } + } + + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/SortOrder.java b/app/src/main/java/code/name/monkey/retromusic/helper/SortOrder.java new file mode 100644 index 00000000..da99cfc4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/SortOrder.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2012 Andrew Neal 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 + * http://www.apache.org/licenses/LICENSE-2.0 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 code.name.monkey.retromusic.helper; + +import android.provider.MediaStore; + +/** + * Holds all of the sort orders for each list type. + * + * @author Andrew Neal (andrewdneal@gmail.com) + */ +public final class SortOrder { + + /** + * This class is never instantiated + */ + public SortOrder() { + } + + /** + * Artist sort order entries. + */ + public interface ArtistSortOrder { + + /* Artist sort order A-Z */ + String ARTIST_A_Z = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER; + + /* Artist sort order Z-A */ + String ARTIST_Z_A = ARTIST_A_Z + " DESC"; + + /* Artist sort order number of songs */ + String ARTIST_NUMBER_OF_SONGS = MediaStore.Audio.Artists.NUMBER_OF_TRACKS + + " DESC"; + + /* Artist sort order number of albums */ + String ARTIST_NUMBER_OF_ALBUMS = MediaStore.Audio.Artists.NUMBER_OF_ALBUMS + + " DESC"; + } + + /** + * Album sort order entries. + */ + public interface AlbumSortOrder { + + /* Album sort order A-Z */ + String ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER; + + /* Album sort order Z-A */ + String ALBUM_Z_A = ALBUM_A_Z + " DESC"; + + /* Album sort order songs */ + String ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Albums.NUMBER_OF_SONGS + + " DESC"; + + /* Album sort order artist */ + String ALBUM_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER + + ", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER; + + /* Album sort order year */ + String ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC"; + } + + /** + * Song sort order entries. + */ + public interface SongSortOrder { + + /* Song sort order A-Z */ + String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER; + + /* Song sort order Z-A */ + String SONG_Z_A = SONG_A_Z + " DESC"; + + /* Song sort order artist */ + String SONG_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER; + + /* Song sort order album */ + String SONG_ALBUM = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER; + + /* Song sort order year */ + String SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"; + + /* Song sort order duration */ + String SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"; + + /* Song sort order date */ + String SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC"; + } + + /** + * Album song sort order entries. + */ + public interface AlbumSongSortOrder { + + /* Album song sort order A-Z */ + String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER; + + /* Album song sort order Z-A */ + String SONG_Z_A = SONG_A_Z + " DESC"; + + /* Album song sort order track list */ + String SONG_TRACK_LIST = MediaStore.Audio.Media.TRACK + ", " + + MediaStore.Audio.Media.DEFAULT_SORT_ORDER; + + /* Album song sort order duration */ + String SONG_DURATION = SongSortOrder.SONG_DURATION; + } + + /** + * Artist song sort order entries. + */ + public interface ArtistSongSortOrder { + + /* Artist song sort order A-Z */ + String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER; + + /* Artist song sort order Z-A */ + String SONG_Z_A = SONG_A_Z + " DESC"; + + /* Artist song sort order album */ + String SONG_ALBUM = MediaStore.Audio.Media.ALBUM; + + /* Artist song sort order year */ + String SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"; + + /* Artist song sort order duration */ + String SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"; + + /* Artist song sort order date */ + String SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC"; + } + + /** + * Artist album sort order entries. + */ + public interface ArtistAlbumSortOrder { + + /* Artist album sort order A-Z */ + String ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER; + + /* Artist album sort order Z-A */ + String ALBUM_Z_A = ALBUM_A_Z + " DESC"; + + /* Artist album sort order year */ + String ALBUM_YEAR = MediaStore.Audio.Media.YEAR + + " DESC"; + + /* Artist album sort order year */ + String ALBUM_YEAR_ASC = MediaStore.Audio.Media.YEAR + + " ASC"; + } + + /** + * Genre sort order entries. + */ + public interface GenreSortOrder { + + /* Genre sort order A-Z */ + String GENRE_A_Z = MediaStore.Audio.Genres.DEFAULT_SORT_ORDER; + + /* Genre sort order Z-A */ + String ALBUM_Z_A = GENRE_A_Z + " DESC"; + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/StackBlur.java b/app/src/main/java/code/name/monkey/retromusic/helper/StackBlur.java new file mode 100644 index 00000000..3e812e8a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/StackBlur.java @@ -0,0 +1,333 @@ +package code.name.monkey.retromusic.helper; + +import android.graphics.Bitmap; + +import java.util.ArrayList; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Blur using Java code. + *

    + * This is a compromise between Gaussian Blur and Box blur + * It creates much better looking blurs than Box Blur, but is + * 7x faster than my Gaussian Blur implementation. + *

    + * I called it Stack Blur because this describes best how this + * filter works internally: it creates a kind of moving stack + * of colors whilst scanning through the image. Thereby it + * just has to add one new block of color to the right side + * of the stack and remove the leftmost color. The remaining + * colors on the topmost layer of the stack are either added on + * or reduced by one, depending on if they are on the right or + * on the left side of the stack. + * + * @author Enrique López Mañas + * http://www.neo-tech.es + *

    + * Author of the original algorithm: Mario Klingemann + *

    + * Based heavily on http://vitiy.info/Code/stackblur.cpp + * See http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/ + * @copyright: Enrique López Mañas + * @license: Apache License 2.0 + */ +public class StackBlur { + + static final int EXECUTOR_THREADS = Runtime.getRuntime().availableProcessors(); + static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(EXECUTOR_THREADS); + + private static final short[] stackblur_mul = { + 512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, + 454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512, + 482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, + 437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512, + 497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, + 320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456, + 446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335, + 329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512, + 505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405, + 399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328, + 324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271, + 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456, + 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388, + 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335, + 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292, + 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259 + }; + + private static final byte[] stackblur_shr = { + 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, + 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 + }; + + public static Bitmap blur(Bitmap original, float radius) { + int w = original.getWidth(); + int h = original.getHeight(); + int[] currentPixels = new int[w * h]; + original.getPixels(currentPixels, 0, w, 0, 0, w, h); + int cores = EXECUTOR_THREADS; + + ArrayList horizontal = new ArrayList(cores); + ArrayList vertical = new ArrayList(cores); + for (int i = 0; i < cores; i++) { + horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1)); + vertical.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 2)); + } + + try { + EXECUTOR.invokeAll(horizontal); + } catch (InterruptedException e) { + return null; + } + + try { + EXECUTOR.invokeAll(vertical); + } catch (InterruptedException e) { + return null; + } + + return Bitmap.createBitmap(currentPixels, w, h, Bitmap.Config.ARGB_8888); + } + + private static void blurIteration(int[] src, int w, int h, int radius, int cores, int core, int step) { + int x, y, xp, yp, i; + int sp; + int stack_start; + int stack_i; + + int src_i; + int dst_i; + + long sum_r, sum_g, sum_b, + sum_in_r, sum_in_g, sum_in_b, + sum_out_r, sum_out_g, sum_out_b; + + int wm = w - 1; + int hm = h - 1; + int div = (radius * 2) + 1; + int mul_sum = stackblur_mul[radius]; + byte shr_sum = stackblur_shr[radius]; + int[] stack = new int[div]; + + if (step == 1) { + int minY = core * h / cores; + int maxY = (core + 1) * h / cores; + + for (y = minY; y < maxY; y++) { + sum_r = sum_g = sum_b = + sum_in_r = sum_in_g = sum_in_b = + sum_out_r = sum_out_g = sum_out_b = 0; + + src_i = w * y; // start of line (0,y) + + for (i = 0; i <= radius; i++) { + stack_i = i; + stack[stack_i] = src[src_i]; + sum_r += ((src[src_i] >>> 16) & 0xff) * (i + 1); + sum_g += ((src[src_i] >>> 8) & 0xff) * (i + 1); + sum_b += (src[src_i] & 0xff) * (i + 1); + sum_out_r += ((src[src_i] >>> 16) & 0xff); + sum_out_g += ((src[src_i] >>> 8) & 0xff); + sum_out_b += (src[src_i] & 0xff); + } + + + for (i = 1; i <= radius; i++) { + if (i <= wm) src_i += 1; + stack_i = i + radius; + stack[stack_i] = src[src_i]; + sum_r += ((src[src_i] >>> 16) & 0xff) * (radius + 1 - i); + sum_g += ((src[src_i] >>> 8) & 0xff) * (radius + 1 - i); + sum_b += (src[src_i] & 0xff) * (radius + 1 - i); + sum_in_r += ((src[src_i] >>> 16) & 0xff); + sum_in_g += ((src[src_i] >>> 8) & 0xff); + sum_in_b += (src[src_i] & 0xff); + } + + + sp = radius; + xp = radius; + if (xp > wm) xp = wm; + src_i = xp + y * w; // img.pix_ptr(xp, y); + dst_i = y * w; // img.pix_ptr(0, y); + for (x = 0; x < w; x++) { + src[dst_i] = (int) + ((src[dst_i] & 0xFFFFFFFF) | + ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16) | + ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8) | + ((((sum_b * mul_sum) >>> shr_sum) & 0xff))); + dst_i += 1; + + sum_r -= sum_out_r; + sum_g -= sum_out_g; + sum_b -= sum_out_b; + + stack_start = sp + div - radius; + if (stack_start >= div) stack_start -= div; + stack_i = stack_start; + + sum_out_r -= ((stack[stack_i] >>> 16) & 0xff); + sum_out_g -= ((stack[stack_i] >>> 8) & 0xff); + sum_out_b -= (stack[stack_i] & 0xff); + + if (xp < wm) { + src_i += 1; + ++xp; + } + + stack[stack_i] = src[src_i]; + + sum_in_r += ((src[src_i] >>> 16) & 0xff); + sum_in_g += ((src[src_i] >>> 8) & 0xff); + sum_in_b += (src[src_i] & 0xff); + sum_r += sum_in_r; + sum_g += sum_in_g; + sum_b += sum_in_b; + + ++sp; + if (sp >= div) sp = 0; + stack_i = sp; + + sum_out_r += ((stack[stack_i] >>> 16) & 0xff); + sum_out_g += ((stack[stack_i] >>> 8) & 0xff); + sum_out_b += (stack[stack_i] & 0xff); + sum_in_r -= ((stack[stack_i] >>> 16) & 0xff); + sum_in_g -= ((stack[stack_i] >>> 8) & 0xff); + sum_in_b -= (stack[stack_i] & 0xff); + } + + } + } + + // step 2 + else if (step == 2) { + int minX = core * w / cores; + int maxX = (core + 1) * w / cores; + + for (x = minX; x < maxX; x++) { + sum_r = sum_g = sum_b = + sum_in_r = sum_in_g = sum_in_b = + sum_out_r = sum_out_g = sum_out_b = 0; + + src_i = x; // x,0 + for (i = 0; i <= radius; i++) { + stack_i = i; + stack[stack_i] = src[src_i]; + sum_r += ((src[src_i] >>> 16) & 0xff) * (i + 1); + sum_g += ((src[src_i] >>> 8) & 0xff) * (i + 1); + sum_b += (src[src_i] & 0xff) * (i + 1); + sum_out_r += ((src[src_i] >>> 16) & 0xff); + sum_out_g += ((src[src_i] >>> 8) & 0xff); + sum_out_b += (src[src_i] & 0xff); + } + for (i = 1; i <= radius; i++) { + if (i <= hm) src_i += w; // +stride + + stack_i = i + radius; + stack[stack_i] = src[src_i]; + sum_r += ((src[src_i] >>> 16) & 0xff) * (radius + 1 - i); + sum_g += ((src[src_i] >>> 8) & 0xff) * (radius + 1 - i); + sum_b += (src[src_i] & 0xff) * (radius + 1 - i); + sum_in_r += ((src[src_i] >>> 16) & 0xff); + sum_in_g += ((src[src_i] >>> 8) & 0xff); + sum_in_b += (src[src_i] & 0xff); + } + + sp = radius; + yp = radius; + if (yp > hm) yp = hm; + src_i = x + yp * w; // img.pix_ptr(x, yp); + dst_i = x; // img.pix_ptr(x, 0); + for (y = 0; y < h; y++) { + src[dst_i] = (int) + ((src[dst_i] & 0xFFFFFFFF) | + ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16) | + ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8) | + ((((sum_b * mul_sum) >>> shr_sum) & 0xff))); + dst_i += w; + + sum_r -= sum_out_r; + sum_g -= sum_out_g; + sum_b -= sum_out_b; + + stack_start = sp + div - radius; + if (stack_start >= div) stack_start -= div; + stack_i = stack_start; + + sum_out_r -= ((stack[stack_i] >>> 16) & 0xff); + sum_out_g -= ((stack[stack_i] >>> 8) & 0xff); + sum_out_b -= (stack[stack_i] & 0xff); + + if (yp < hm) { + src_i += w; // stride + ++yp; + } + + stack[stack_i] = src[src_i]; + + sum_in_r += ((src[src_i] >>> 16) & 0xff); + sum_in_g += ((src[src_i] >>> 8) & 0xff); + sum_in_b += (src[src_i] & 0xff); + sum_r += sum_in_r; + sum_g += sum_in_g; + sum_b += sum_in_b; + + ++sp; + if (sp >= div) sp = 0; + stack_i = sp; + + sum_out_r += ((stack[stack_i] >>> 16) & 0xff); + sum_out_g += ((stack[stack_i] >>> 8) & 0xff); + sum_out_b += (stack[stack_i] & 0xff); + sum_in_r -= ((stack[stack_i] >>> 16) & 0xff); + sum_in_g -= ((stack[stack_i] >>> 8) & 0xff); + sum_in_b -= (stack[stack_i] & 0xff); + } + } + } + + } + + private static class BlurTask implements Callable { + private final int[] _src; + private final int _w; + private final int _h; + private final int _radius; + private final int _totalCores; + private final int _coreIndex; + private final int _round; + + public BlurTask(int[] src, int w, int h, int radius, int totalCores, int coreIndex, int round) { + _src = src; + _w = w; + _h = h; + _radius = radius; + _totalCores = totalCores; + _coreIndex = coreIndex; + _round = round; + } + + @Override + public Void call() throws Exception { + blurIteration(_src, _w, _h, _radius, _totalCores, _coreIndex, _round); + return null; + } + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/StopWatch.java b/app/src/main/java/code/name/monkey/retromusic/helper/StopWatch.java new file mode 100644 index 00000000..896f68ac --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/StopWatch.java @@ -0,0 +1,82 @@ +package code.name.monkey.retromusic.helper; + +/** + * Simple thread safe stop watch. + * + * @author Karim Abou Zeid (kabouzeid) + */ +public class StopWatch { + + /** + * The time the stop watch was last started. + */ + private long startTime; + + /** + * The time elapsed before the current {@link #startTime}. + */ + private long previousElapsedTime; + + /** + * Whether the stop watch is currently running or not. + */ + private boolean isRunning; + + /** + * Starts or continues the stop watch. + * + * @see #pause() + * @see #reset() + */ + public void start() { + synchronized (this) { + startTime = System.currentTimeMillis(); + isRunning = true; + } + } + + /** + * Pauses the stop watch. It can be continued later from {@link #start()}. + * + * @see #start() + * @see #reset() + */ + public void pause() { + synchronized (this) { + previousElapsedTime += System.currentTimeMillis() - startTime; + isRunning = false; + } + } + + /** + * Stops and resets the stop watch to zero milliseconds. + * + * @see #start() + * @see #pause() + */ + public void reset() { + synchronized (this) { + startTime = 0; + previousElapsedTime = 0; + isRunning = false; + } + } + + /** + * @return the total elapsed time in milliseconds + */ + public final long getElapsedTime() { + synchronized (this) { + long currentElapsedTime = 0; + if (isRunning) { + currentElapsedTime = System.currentTimeMillis() - startTime; + } + return previousElapsedTime + currentElapsedTime; + } + } + + @Override + public String toString() { + return String.format("%d millis", getElapsedTime()); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.java b/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.java new file mode 100644 index 00000000..0c71de2d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.java @@ -0,0 +1,50 @@ +package code.name.monkey.retromusic.helper.menu; + +import android.app.Activity; +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatActivity; +import android.view.MenuItem; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.loaders.GenreLoader; +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; + +/** + * @author Hemanth S (h4h13). + */ + +public class GenreMenuHelper { + public static boolean handleMenuClick(@NonNull AppCompatActivity activity, + @NonNull Genre genre, + @NonNull MenuItem item) { + switch (item.getItemId()) { + case R.id.action_play: + MusicPlayerRemote.openQueue(getGenreSongs(activity, genre), 0, true); + return true; + case R.id.action_play_next: + MusicPlayerRemote.playNext(getGenreSongs(activity, genre)); + return true; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(getGenreSongs(activity, genre)) + .show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + return true; + case R.id.action_add_to_current_playing: + MusicPlayerRemote.enqueue(getGenreSongs(activity, genre)); + return true; + } + return false; + } + + @NonNull + private static ArrayList getGenreSongs(@NonNull Activity activity, + @NonNull Genre genre) { + ArrayList songs; + songs = GenreLoader.getSongs(activity, genre.id).blockingFirst(); + return songs; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.java b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.java new file mode 100644 index 00000000..a6944221 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.java @@ -0,0 +1,91 @@ +package code.name.monkey.retromusic.helper.menu; + +import android.app.Activity; +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatActivity; +import android.view.MenuItem; +import android.widget.Toast; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog; +import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog; +import code.name.monkey.retromusic.dialogs.RenamePlaylistDialog; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.loaders.PlaylistSongsLoader; +import code.name.monkey.retromusic.misc.WeakContextAsyncTask; +import code.name.monkey.retromusic.model.AbsCustomPlaylist; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.PlaylistsUtil; + + +public class PlaylistMenuHelper { + + public static boolean handleMenuClick(@NonNull AppCompatActivity activity, + @NonNull final Playlist playlist, @NonNull MenuItem item) { + switch (item.getItemId()) { + case R.id.action_play: + MusicPlayerRemote.openQueue(getPlaylistSongs(activity, playlist), 9, true); + return true; + case R.id.action_play_next: + MusicPlayerRemote.playNext(getPlaylistSongs(activity, playlist)); + return true; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(getPlaylistSongs(activity, playlist)) + .show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + return true; + case R.id.action_add_to_current_playing: + MusicPlayerRemote.enqueue(getPlaylistSongs(activity, playlist)); + return true; + case R.id.action_rename_playlist: + RenamePlaylistDialog.create(playlist.id) + .show(activity.getSupportFragmentManager(), "RENAME_PLAYLIST"); + return true; + case R.id.action_delete_playlist: + DeletePlaylistDialog.create(playlist) + .show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST"); + return true; + case R.id.action_save_playlist: + new SavePlaylistAsyncTask(activity).execute(playlist); + return true; + } + return false; + } + + @NonNull + private static ArrayList getPlaylistSongs(@NonNull Activity activity, + @NonNull Playlist playlist) { + ArrayList songs; + if (playlist instanceof AbsCustomPlaylist) { + songs = ((AbsCustomPlaylist) playlist).getSongs(activity).blockingFirst(); + } else { + songs = PlaylistSongsLoader.getPlaylistSongList(activity, playlist).blockingFirst(); + } + return songs; + } + + private static class SavePlaylistAsyncTask extends WeakContextAsyncTask { + SavePlaylistAsyncTask(Context context) { + super(context); + } + + @Override + protected String doInBackground(Playlist... params) { + return String.format(RetroApplication.getInstance().getApplicationContext().getString(R.string + .saved_playlist_to), PlaylistsUtil.savePlaylist(RetroApplication.getInstance().getApplicationContext(), params[0]).blockingFirst()); + } + + @Override + protected void onPostExecute(String string) { + super.onPostExecute(string); + Context context = getContext(); + if (context != null) { + Toast.makeText(context, string, Toast.LENGTH_LONG).show(); + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.java b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.java new file mode 100644 index 00000000..5d182886 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.java @@ -0,0 +1,93 @@ +package code.name.monkey.retromusic.helper.menu; + +import android.content.Intent; +import android.support.annotation.NonNull; +import android.support.v4.app.FragmentActivity; +import android.support.v7.app.AppCompatActivity; +import android.view.MenuItem; +import android.view.View; +import android.widget.PopupMenu; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog; +import code.name.monkey.retromusic.dialogs.DeleteSongsDialog; +import code.name.monkey.retromusic.dialogs.SongDetailDialog; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.interfaces.PaletteColorHolder; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.activities.tageditor.AbsTagEditorActivity; +import code.name.monkey.retromusic.ui.activities.tageditor.SongTagEditorActivity; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.NavigationUtil; + + +public class SongMenuHelper { + public static final int MENU_RES = R.menu.menu_item_song; + + public static boolean handleMenuClick(@NonNull FragmentActivity activity, @NonNull Song song, int menuItemId) { + switch (menuItemId) { + case R.id.action_set_as_ringtone: + MusicUtil.setRingtone(activity, song.id); + return true; + case R.id.action_share: + activity.startActivity(Intent.createChooser(MusicUtil.createShareSongFileIntent(song, activity), null)); + return true; + case R.id.action_delete_from_device: + DeleteSongsDialog.create(song).show(activity.getSupportFragmentManager(), "DELETE_SONGS"); + return true; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(song).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + return true; + case R.id.action_play_next: + MusicPlayerRemote.playNext(song); + return true; + case R.id.action_add_to_current_playing: + MusicPlayerRemote.enqueue(song); + return true; + case R.id.action_tag_editor: + Intent tagEditorIntent = new Intent(activity, SongTagEditorActivity.class); + tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id); + if (activity instanceof PaletteColorHolder) + tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_PALETTE, ((PaletteColorHolder) activity).getPaletteColor()); + activity.startActivity(tagEditorIntent); + return true; + case R.id.action_details: + SongDetailDialog.create(song).show(activity.getSupportFragmentManager(), "SONG_DETAILS"); + return true; + case R.id.action_go_to_album: + NavigationUtil.goToAlbum(activity, song.albumId); + return true; + case R.id.action_go_to_artist: + NavigationUtil.goToArtist(activity, song.artistId); + return true; + } + return false; + } + + public static abstract class OnClickSongMenu implements View.OnClickListener, PopupMenu.OnMenuItemClickListener { + private AppCompatActivity activity; + + protected OnClickSongMenu(@NonNull AppCompatActivity activity) { + this.activity = activity; + } + + public int getMenuRes() { + return MENU_RES; + } + + @Override + public void onClick(View v) { + PopupMenu popupMenu = new PopupMenu(activity, v); + popupMenu.inflate(getMenuRes()); + popupMenu.setOnMenuItemClickListener(this); + popupMenu.show(); + } + + @Override + public boolean onMenuItemClick(MenuItem item) { + return handleMenuClick(activity, getSong(), item.getItemId()); + } + + public abstract Song getSong(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.java b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.java new file mode 100644 index 00000000..cb305243 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.java @@ -0,0 +1,35 @@ +package code.name.monkey.retromusic.helper.menu; + +import android.support.annotation.NonNull; +import android.support.v4.app.FragmentActivity; + +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog; +import code.name.monkey.retromusic.dialogs.DeleteSongsDialog; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; + + + +public class SongsMenuHelper { + public static boolean handleMenuClick(@NonNull FragmentActivity activity, @NonNull ArrayList songs, int menuItemId) { + switch (menuItemId) { + case R.id.action_play_next: + MusicPlayerRemote.playNext(songs); + return true; + case R.id.action_add_to_current_playing: + MusicPlayerRemote.enqueue(songs); + return true; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(songs).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + return true; + case R.id.action_delete_from_device: + DeleteSongsDialog.create(songs).show(activity.getSupportFragmentManager(), "DELETE_SONGS"); + return true; + } + return false; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/interfaces/CabHolder.java b/app/src/main/java/code/name/monkey/retromusic/interfaces/CabHolder.java new file mode 100644 index 00000000..76ba6f35 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/interfaces/CabHolder.java @@ -0,0 +1,12 @@ +package code.name.monkey.retromusic.interfaces; + +import android.support.annotation.NonNull; + +import com.afollestad.materialcab.MaterialCab; + + +public interface CabHolder { + + @NonNull + MaterialCab openCab(final int menuRes, final MaterialCab.Callback callback); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/interfaces/EqualizerInterface.java b/app/src/main/java/code/name/monkey/retromusic/interfaces/EqualizerInterface.java new file mode 100644 index 00000000..88143418 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/interfaces/EqualizerInterface.java @@ -0,0 +1,49 @@ +package code.name.monkey.retromusic.interfaces; + +import android.media.audiofx.BassBoost; +import android.media.audiofx.Equalizer; +import android.media.audiofx.Virtualizer; + +/** + * @author Hemanth S (h4h13). + */ + +public interface EqualizerInterface { + int getBandLevelLow(); + + int getBandLevelHigh(); + + int getNumberOfBands(); + + int getCenterFreq(int band); + + int getBandLevel(int band); + + void setBandLevel(int band, int level); + + boolean isBassBoostEnabled(); + + void setBassBoostEnabled(boolean isEnabled); + + int getBassBoostStrength(); + + void setBassBoostStrength(int strength); + + boolean isVirtualizerEnabled(); + + void setVirtualizerEnabled(boolean isEnabled); + + int getVirtualizerStrength(); + + void setVirtualizerStrength(int strength); + + boolean isRunning(); + + Equalizer getEqualizer(); + + BassBoost getBassBoost(); + + Virtualizer getVirtualizer(); + + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/interfaces/LoaderIds.java b/app/src/main/java/code/name/monkey/retromusic/interfaces/LoaderIds.java new file mode 100644 index 00000000..e7792818 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/interfaces/LoaderIds.java @@ -0,0 +1,6 @@ +package code.name.monkey.retromusic.interfaces; + + +public interface LoaderIds { + int FOLDERS_FRAGMENT = 5; +} diff --git a/app/src/main/java/code/name/monkey/retromusic/interfaces/MainActivityFragmentCallbacks.java b/app/src/main/java/code/name/monkey/retromusic/interfaces/MainActivityFragmentCallbacks.java new file mode 100644 index 00000000..fd165510 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/interfaces/MainActivityFragmentCallbacks.java @@ -0,0 +1,13 @@ +package code.name.monkey.retromusic.interfaces; + +import android.support.v4.app.Fragment; + +/** + * Created by hemanths on 14/08/17. + */ + +public interface MainActivityFragmentCallbacks { + boolean handleBackPress(); + + //void selectedFragment(Fragment fragment); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/interfaces/MusicServiceEventListener.java b/app/src/main/java/code/name/monkey/retromusic/interfaces/MusicServiceEventListener.java new file mode 100644 index 00000000..ea609019 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/interfaces/MusicServiceEventListener.java @@ -0,0 +1,20 @@ +package code.name.monkey.retromusic.interfaces; + + +public interface MusicServiceEventListener { + void onServiceConnected(); + + void onServiceDisconnected(); + + void onQueueChanged(); + + void onPlayingMetaChanged(); + + void onPlayStateChanged(); + + void onRepeatModeChanged(); + + void onShuffleModeChanged(); + + void onMediaStoreChanged(); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/interfaces/PaletteColorHolder.java b/app/src/main/java/code/name/monkey/retromusic/interfaces/PaletteColorHolder.java new file mode 100644 index 00000000..406ddf60 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/interfaces/PaletteColorHolder.java @@ -0,0 +1,12 @@ +package code.name.monkey.retromusic.interfaces; + +import android.support.annotation.ColorInt; + +/** + * @author Aidan Follestad (afollestad) + */ +public interface PaletteColorHolder { + + @ColorInt + int getPaletteColor(); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/AlbumLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/AlbumLoader.java new file mode 100644 index 00000000..fb12d1dc --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/AlbumLoader.java @@ -0,0 +1,104 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.provider.MediaStore.Audio.AudioColumns; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.PreferenceUtil; +import io.reactivex.Observable; +import java.util.ArrayList; + +/** + * Created by hemanths on 11/08/17. + */ + +public class AlbumLoader { + + public static Observable> getAllAlbums(@NonNull Context context) { + Observable> songs = SongLoader.getSongs(SongLoader.makeSongCursor( + context, + null, + null, + getSongLoaderSortOrder(context)) + ); + + return splitIntoAlbums(songs); + } + + @NonNull + public static Observable> getAlbums(@NonNull final Context context, + String query) { + Observable> songs = SongLoader.getSongs(SongLoader.makeSongCursor( + context, + AudioColumns.ALBUM + " LIKE ?", + new String[]{"%" + query + "%"}, + getSongLoaderSortOrder(context)) + ); + return splitIntoAlbums(songs); + } + + @NonNull + public static Observable getAlbum(@NonNull final Context context, int albumId) { + return Observable.create(e -> { + Observable> songs = SongLoader.getSongs(SongLoader + .makeSongCursor(context, AudioColumns.ALBUM_ID + "=?", + new String[]{String.valueOf(albumId)}, getSongLoaderSortOrder(context))); + songs.subscribe(songs1 -> { + e.onNext(new Album(songs1)); + e.onComplete(); + }); + }); + } + + @NonNull + public static Observable> splitIntoAlbums( + @Nullable final Observable> songs) { + return Observable.create(e -> { + ArrayList albums = new ArrayList<>(); + if (songs != null) { + songs.subscribe(songs1 -> { + for (Song song : songs1) { + getOrCreateAlbum(albums, song.albumId).subscribe(album -> album.songs.add(song)); + } + }); + } + e.onNext(albums); + e.onComplete(); + }); + } + + @NonNull + public static ArrayList splitIntoAlbums(@Nullable final ArrayList songs) { + ArrayList albums = new ArrayList<>(); + if (songs != null) { + for (Song song : songs) { + getOrCreateAlbum(albums, song.albumId).subscribe(album -> album.songs.add(song)); + } + } + return albums; + } + + private static Observable getOrCreateAlbum(ArrayList albums, int albumId) { + return Observable.create(e -> { + for (Album album : albums) { + if (!album.songs.isEmpty() && album.songs.get(0).albumId == albumId) { + e.onNext(album); + e.onComplete(); + return; + } + } + Album album = new Album(); + albums.add(album); + e.onNext(album); + e.onComplete(); + }); + } + + public static String getSongLoaderSortOrder(Context context) { + return PreferenceUtil.getInstance(context).getAlbumSortOrder() + ", " + + //PreferenceUtil.getInstance(context).getAlbumSongSortOrder() + "," + + PreferenceUtil.getInstance(context).getAlbumDetailSongSortOrder(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/ArtistLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/ArtistLoader.java new file mode 100644 index 00000000..500c98a2 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/ArtistLoader.java @@ -0,0 +1,119 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.provider.MediaStore.Audio.AudioColumns; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.util.PreferenceUtil; +import io.reactivex.Observable; + +public class ArtistLoader { + public static String getSongLoaderSortOrder(Context context) { + return PreferenceUtil.getInstance(context).getArtistSortOrder() + ", " + + PreferenceUtil.getInstance(context).getArtistAlbumSortOrder() + ", " + + PreferenceUtil.getInstance(context).getAlbumDetailSongSortOrder() + ", " + + PreferenceUtil.getInstance(context).getArtistDetailSongSortOrder(); + } + + @NonNull + public static Observable getArtist(@NonNull final Context context, int artistId) { + return Observable.create(e -> SongLoader.getSongs(SongLoader.makeSongCursor( + context, + AudioColumns.ARTIST_ID + "=?", + new String[]{String.valueOf(artistId)}, + getSongLoaderSortOrder(context))) + .subscribe(songs -> { + Artist artist = new Artist(AlbumLoader.splitIntoAlbums(songs)); + e.onNext(artist); + e.onComplete(); + })); + } + + @NonNull + public static Observable> getAllArtists(@NonNull final Context context) { + return Observable.create(e -> SongLoader + .getSongs(SongLoader.makeSongCursor( + context, + null, + null, + getSongLoaderSortOrder(context)) + ).subscribe(songs -> { + e.onNext(splitIntoArtists(AlbumLoader.splitIntoAlbums(songs))); + e.onComplete(); + })); + + } + + @NonNull + public static Observable> getArtists(@NonNull final Context context, String query) { + return Observable.create(e -> SongLoader.getSongs(SongLoader.makeSongCursor( + context, + AudioColumns.ARTIST + " LIKE ?", + new String[]{"%" + query + "%"}, + getSongLoaderSortOrder(context)) + ).subscribe(songs -> { + e.onNext(splitIntoArtists(AlbumLoader.splitIntoAlbums(songs))); + e.onComplete(); + })); + } + + @NonNull + public static ArrayList splitIntoArtists(@Nullable final ArrayList albums) { + ArrayList artists = new ArrayList<>(); + if (albums != null) { + for (Album album : albums) { + getOrCreateArtist(artists, album.getArtistId()).albums.add(album); + } + } + return artists; + } + + private static Artist getOrCreateArtist(ArrayList artists, int artistId) { + for (Artist artist : artists) { + if (!artist.albums.isEmpty() && !artist.albums.get(0).songs.isEmpty() && artist.albums.get(0).songs.get(0).artistId == artistId) { + return artist; + } + } + Artist album = new Artist(); + artists.add(album); + return album; + } + + public static Observable> splitIntoArtists(Observable> albums) { + return Observable.create(e -> { + ArrayList artists = new ArrayList<>(); + albums.subscribe(localAlbums -> { + if (localAlbums != null) { + for (Album album : localAlbums) { + getOrCreateArtist(artists, album.getArtistId()).albums.add(album); + } + } + e.onNext(artists); + e.onComplete(); + }); + }); + } + + /* public static Observable> getAllArtists(Context context) { + return getArtistsForCursor(makeArtistCursor(context, null, null)); + } + + public static Observable getArtist(Context context, long id) { + return getArtist(makeArtistCursor(context, "_id=?", new String[]{String.valueOf(id)})); + } + + public static Observable> getArtists(Context context, String paramString) { + return getArtistsForCursor(makeArtistCursor(context, "artist LIKE ?", new String[]{"%" + paramString + "%"})); + } + + private static Cursor makeArtistCursor(Context context, String selection, String[] paramArrayOfString) { + final String artistSortOrder = PreferenceUtil.getInstance(context).getArtistSortOrder(); + Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, new String[]{"_id", "artist", "number_of_albums", "number_of_tracks"}, selection, paramArrayOfString, artistSortOrder); + return cursor; + }*/ +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/ArtistSongLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/ArtistSongLoader.java new file mode 100644 index 00000000..e4344ee7 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/ArtistSongLoader.java @@ -0,0 +1,37 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.database.Cursor; +import android.provider.MediaStore; +import android.support.annotation.NonNull; + +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.util.PreferenceUtil; +import io.reactivex.Observable; + + +public class ArtistSongLoader extends SongLoader { + + @NonNull + public static Observable> getArtistSongList(@NonNull final Context context, final int artistId) { + return getSongs(makeArtistSongCursor(context, artistId)); + } + + public static Cursor makeArtistSongCursor(@NonNull final Context context, final int artistId) { + try { + return makeSongCursor( + context, + MediaStore.Audio.AudioColumns.ARTIST_ID + "=?", + new String[]{ + String.valueOf(artistId) + }, + PreferenceUtil.getInstance(context).getArtistSongSortOrder() + ); + } catch (SecurityException e) { + return null; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/GenreLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/GenreLoader.java new file mode 100644 index 00000000..5ca28f20 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/GenreLoader.java @@ -0,0 +1,133 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.BaseColumns; +import android.provider.MediaStore.Audio.Genres; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.PreferenceUtil; +import io.reactivex.Observable; + +public class GenreLoader { + + @NonNull + public static Observable> getAllGenres(@NonNull final Context context) { + return getGenresFromCursor(context, makeGenreCursor(context)); + } + + @NonNull + public static Observable> getSongs(@NonNull final Context context, final int genreId) { + // The genres table only stores songs that have a genre specified, + // so we need to get songs without a genre a different way. + if (genreId == -1) { + return getSongsWithNoGenre(context); + } + + return SongLoader.getSongs(makeGenreSongCursor(context, genreId)); + } + + @NonNull + private static Genre getGenreFromCursor(@NonNull Context context, @NonNull final Cursor cursor) { + final int id = cursor.getInt(0); + final String name = cursor.getString(1); + final int songCount = getSongs(context, id).blockingFirst().size(); + return new Genre(id, name, songCount); + + } + + @NonNull + private static Observable> getSongsWithNoGenre(@NonNull final Context context) { + String selection = BaseColumns._ID + " NOT IN " + + "(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)"; + return SongLoader.getSongs(SongLoader.makeSongCursor(context, selection, null)); + } + + private static boolean hasSongsWithNoGenre(@NonNull final Context context) { + final Cursor allSongsCursor = SongLoader.makeSongCursor(context, null, null); + final Cursor allSongsWithGenreCursor = makeAllSongsWithGenreCursor(context); + + if (allSongsCursor == null || allSongsWithGenreCursor == null) { + return false; + } + + final boolean hasSongsWithNoGenre = allSongsCursor.getCount() > allSongsWithGenreCursor.getCount(); + allSongsCursor.close(); + allSongsWithGenreCursor.close(); + return hasSongsWithNoGenre; + } + + @Nullable + private static Cursor makeAllSongsWithGenreCursor(@NonNull final Context context) { + try { + return context.getContentResolver().query( + Uri.parse("content://media/external/audio/genres/all/members"), + new String[]{Genres.Members.AUDIO_ID}, null, null, null); + } catch (SecurityException e) { + return null; + } + } + + @Nullable + private static Cursor makeGenreSongCursor(@NonNull final Context context, int genreId) { + try { + return context.getContentResolver().query( + Genres.Members.getContentUri("external", genreId), + SongLoader.BASE_PROJECTION, SongLoader.BASE_SELECTION, null, PreferenceUtil.getInstance(context).getSongSortOrder()); + } catch (SecurityException e) { + return null; + } + } + + @NonNull + private static Observable> getGenresFromCursor(@NonNull final Context context, @Nullable final Cursor cursor) { + return Observable.create(e -> { + final ArrayList genres = new ArrayList<>(); + if (cursor != null) { + if (cursor.moveToFirst()) { + do { + Genre genre = getGenreFromCursor(context, cursor); + if (genre.songCount > 0) { + genres.add(genre); + } else { + // try to remove the empty genre from the media store + try { + context.getContentResolver().delete(Genres.EXTERNAL_CONTENT_URI, Genres._ID + " == " + genre.id, null); + } catch (Exception ex) { + ex.printStackTrace(); + // nothing we can do then + } + } + } while (cursor.moveToNext()); + } + cursor.close(); + } + e.onNext(genres); + e.onComplete(); + }); + } + + + @Nullable + private static Cursor makeGenreCursor(@NonNull final Context context) { + final String[] projection = new String[]{ + Genres._ID, + Genres.NAME + }; + + try { + return context.getContentResolver().query( + Genres.EXTERNAL_CONTENT_URI, + projection, null, null, PreferenceUtil.getInstance(context).getGenreSortOrder()); + } catch (SecurityException e) { + return null; + } + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/GenreSongsLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/GenreSongsLoader.java new file mode 100644 index 00000000..11422e4d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/GenreSongsLoader.java @@ -0,0 +1,78 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.database.Cursor; +import android.provider.MediaStore; +import android.provider.MediaStore.Audio.AudioColumns; +import android.support.annotation.NonNull; + +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Observable; + +/** + * @author Hemanth S (h4h13). + */ + +public class GenreSongsLoader { + + public static Observable> getGenreSongsList(@NonNull Context context, @NonNull int genreId) { + return Observable.create(e -> { + ArrayList list = new ArrayList<>(); + Cursor cursor = makeGenreSongCursor(context, genreId); + if (cursor != null && cursor.moveToFirst()) { + do { + list.add(getGenreSongFromCursorImpl(cursor)); + } while (cursor.moveToNext()); + } + if (cursor != null) { + cursor.close(); + } + e.onNext((ArrayList) (List) list); + e.onComplete(); + }); + } + + @NonNull + private static Song getGenreSongFromCursorImpl(@NonNull Cursor cursor) { + final int id = cursor.getInt(0); + final String title = cursor.getString(1); + final int trackNumber = cursor.getInt(2); + final int year = cursor.getInt(3); + final long duration = cursor.getLong(4); + final String data = cursor.getString(5); + final int dateModified = cursor.getInt(6); + final int albumId = cursor.getInt(7); + final String albumName = cursor.getString(8); + final int artistId = cursor.getInt(9); + final String artistName = cursor.getString(10); + + return new Song(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName); + } + + private static Cursor makeGenreSongCursor(Context context, long genreId) { + try { + return context.getContentResolver().query( + MediaStore.Audio.Genres.Members.getContentUri("external", genreId), + new String[]{ + MediaStore.Audio.Playlists.Members.AUDIO_ID,// 0 + AudioColumns.TITLE,// 1 + AudioColumns.TRACK,// 2 + AudioColumns.YEAR,// 3 + AudioColumns.DURATION,// 4 + AudioColumns.DATA,// 5 + AudioColumns.DATE_MODIFIED,// 6 + AudioColumns.ALBUM_ID,// 7 + AudioColumns.ALBUM,// 8 + AudioColumns.ARTIST_ID,// 9 + AudioColumns.ARTIST,// 10 + }, SongLoader.BASE_SELECTION, null, + MediaStore.Audio.Genres.Members.DEFAULT_SORT_ORDER); + } catch (SecurityException e) { + return null; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/HomeLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/HomeLoader.java new file mode 100644 index 00000000..783f39ad --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/HomeLoader.java @@ -0,0 +1,60 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.support.annotation.NonNull; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist; +import code.name.monkey.retromusic.model.smartplaylist.HistoryPlaylist; +import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist; +import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist; +import io.reactivex.Observable; +import java.util.ArrayList; + +public class HomeLoader { + + public static Observable> getRecentAndTopThings( + @NonNull Context context) { + ArrayList objects = new ArrayList<>(); + return Observable.create(e -> { + + new HistoryPlaylist(context).getSongs(context).subscribe(songs -> { + if (!songs.isEmpty()) { + objects.add(new HistoryPlaylist(context)); + } + }); + new LastAddedPlaylist(context).getSongs(context).subscribe(songs -> { + if (!songs.isEmpty()) { + objects.add(new LastAddedPlaylist(context)); + } + }); + new MyTopTracksPlaylist(context).getSongs(context).subscribe(songs -> { + if (!songs.isEmpty()) { + objects.add(new MyTopTracksPlaylist(context)); + } + }); + + e.onNext(objects); + e.onComplete(); + }); + } + + public static Observable> getHomeLoader(@NonNull Context context) { + ArrayList playlists = new ArrayList<>(); + PlaylistLoader.getAllPlaylists(context) + .subscribe(playlists1 -> { + if (playlists1.size() > 0) { + for (Playlist playlist : playlists1) { + PlaylistSongsLoader.getPlaylistSongList(context, playlist) + .subscribe(songs -> { + if (songs.size() > 0) { + playlists.add(playlist); + } + }); + } + } + }); + return Observable.just(playlists); + } + + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/LastAddedSongsLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/LastAddedSongsLoader.java new file mode 100644 index 00000000..0e664c2d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/LastAddedSongsLoader.java @@ -0,0 +1,47 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.database.Cursor; +import android.provider.MediaStore; + +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.util.PreferenceUtil; +import io.reactivex.Observable; +import io.reactivex.annotations.NonNull; + +/** + * Created by hemanths on 16/08/17. + */ + +public class LastAddedSongsLoader { + + @NonNull + public static Observable> getLastAddedSongs(@NonNull Context context) { + return SongLoader.getSongs(makeLastAddedCursor(context)); + } + + public static Cursor makeLastAddedCursor(@NonNull final Context context) { + long cutoff = PreferenceUtil.getInstance(context).getLastAddedCutoff(); + + return SongLoader.makeSongCursor( + context, + MediaStore.Audio.Media.DATE_ADDED + ">?", + new String[]{String.valueOf(cutoff)}, + MediaStore.Audio.Media.DATE_ADDED + " DESC"); + } + + @NonNull + public static Observable> getLastAddedAlbums(@NonNull Context context) { + return AlbumLoader.splitIntoAlbums(getLastAddedSongs(context)); + } + + @NonNull + public static Observable> getLastAddedArtists(@NonNull Context context) { + return ArtistLoader.splitIntoArtists(getLastAddedAlbums(context)); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/PlaylistLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/PlaylistLoader.java new file mode 100644 index 00000000..70ed160b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/PlaylistLoader.java @@ -0,0 +1,118 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.BaseColumns; +import android.provider.MediaStore; +import android.provider.MediaStore.Audio.PlaylistsColumns; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import code.name.monkey.retromusic.model.Playlist; + +import java.util.ArrayList; + +import io.reactivex.Observable; + +/** + * Created by hemanths on 16/08/17. + */ + +public class PlaylistLoader { + @Nullable + public static Cursor makePlaylistCursor(@NonNull final Context context, final String selection, final String[] values) { + try { + return context.getContentResolver().query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, + new String[]{ + /* 0 */ + BaseColumns._ID, + /* 1 */ + PlaylistsColumns.NAME + }, selection, values, MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER); + } catch (SecurityException e) { + return null; + } + } + + @NonNull + public static Observable getPlaylist(@Nullable final Cursor cursor) { + return Observable.create(e -> { + Playlist playlist = new Playlist(); + + if (cursor != null && cursor.moveToFirst()) { + playlist = getPlaylistFromCursorImpl(cursor); + } + if (cursor != null) + cursor.close(); + + e.onNext(playlist); + e.onComplete(); + }); + + + } + + @NonNull + public static Observable getPlaylist(@NonNull final Context context, final String playlistName) { + return getPlaylist(makePlaylistCursor( + context, + PlaylistsColumns.NAME + "=?", + new String[]{ + playlistName + } + )); + } + + @NonNull + public static Observable getPlaylist(@NonNull final Context context, final int playlistId) { + return getPlaylist(makePlaylistCursor( + context, + BaseColumns._ID + "=?", + new String[]{ + String.valueOf(playlistId) + } + )); + } + + @NonNull + private static Playlist getPlaylistFromCursorImpl(@NonNull final Cursor cursor) { + + final int id = cursor.getInt(0); + final String name = cursor.getString(1); + return new Playlist(id, name); + } + + + @NonNull + public static Observable> getAllPlaylists(@Nullable final Cursor cursor) { + return Observable.create(e -> { + ArrayList playlists = new ArrayList<>(); + + if (cursor != null && cursor.moveToFirst()) { + do { + playlists.add(getPlaylistFromCursorImpl(cursor)); + } while (cursor.moveToNext()); + } + if (cursor != null) + cursor.close(); + + e.onNext(playlists); + e.onComplete(); + }); + } + + @NonNull + public static Observable> getAllPlaylists(@NonNull final Context context) { + return getAllPlaylists(makePlaylistCursor(context, null, null)); + } + + public static void deletePlaylists(Context context, long playlistId) { + Uri localUri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI; + StringBuilder localStringBuilder = new StringBuilder(); + localStringBuilder.append("_id IN ("); + localStringBuilder.append((playlistId)); + localStringBuilder.append(")"); + context.getContentResolver().delete(localUri, localStringBuilder.toString(), null); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/PlaylistSongsLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/PlaylistSongsLoader.java new file mode 100644 index 00000000..3c373b60 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/PlaylistSongsLoader.java @@ -0,0 +1,95 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.database.Cursor; +import android.provider.MediaStore; +import android.provider.MediaStore.Audio.AudioColumns; + +import code.name.monkey.retromusic.model.AbsCustomPlaylist; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.PlaylistSong; +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.annotations.NonNull; + +/** + * Created by hemanths on 16/08/17. + */ + +public class PlaylistSongsLoader { + + @NonNull + public static Observable> getPlaylistSongList(@NonNull Context context, Playlist playlist) { + if (playlist instanceof AbsCustomPlaylist) { + return ((AbsCustomPlaylist) playlist).getSongs(context); + } else { + //noinspection unchecked + return getPlaylistSongList(context, playlist.id); + } + } + + @NonNull + public static Observable> getPlaylistSongList(@NonNull Context context, final int playlistId) { + return Observable.create(e -> { + ArrayList songs = new ArrayList<>(); + Cursor cursor = makePlaylistSongCursor(context, playlistId); + + if (cursor != null && cursor.moveToFirst()) { + do { + songs.add(getPlaylistSongFromCursorImpl(cursor, playlistId)); + } while (cursor.moveToNext()); + } + if (cursor != null) { + cursor.close(); + } + e.onNext((ArrayList) (List) songs); + e.onComplete(); + }); + } + + @NonNull + private static PlaylistSong getPlaylistSongFromCursorImpl(@NonNull Cursor cursor, int playlistId) { + final int id = cursor.getInt(0); + final String title = cursor.getString(1); + final int trackNumber = cursor.getInt(2); + final int year = cursor.getInt(3); + final long duration = cursor.getLong(4); + final String data = cursor.getString(5); + final int dateModified = cursor.getInt(6); + final int albumId = cursor.getInt(7); + final String albumName = cursor.getString(8); + final int artistId = cursor.getInt(9); + final String artistName = cursor.getString(10); + final int idInPlaylist = cursor.getInt(11); + + return new PlaylistSong(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName, playlistId, idInPlaylist); + } + + public static Cursor makePlaylistSongCursor(@NonNull final Context context, final int playlistId) { + try { + return context.getContentResolver().query( + MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId), + new String[]{ + MediaStore.Audio.Playlists.Members.AUDIO_ID,// 0 + AudioColumns.TITLE,// 1 + AudioColumns.TRACK,// 2 + AudioColumns.YEAR,// 3 + AudioColumns.DURATION,// 4 + AudioColumns.DATA,// 5 + AudioColumns.DATE_MODIFIED,// 6 + AudioColumns.ALBUM_ID,// 7 + AudioColumns.ALBUM,// 8 + AudioColumns.ARTIST_ID,// 9 + AudioColumns.ARTIST,// 10 + MediaStore.Audio.Playlists.Members._ID // 11 + }, SongLoader.BASE_SELECTION, null, + MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER); + } catch (SecurityException e) { + return null; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.java new file mode 100644 index 00000000..f8bbf7a8 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.java @@ -0,0 +1,44 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.text.TextUtils; +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import io.reactivex.Observable; + +public class SearchLoader { + + public static Observable> searchAll(@NonNull Context context, @NonNull String query) { + ArrayList results = new ArrayList<>(); + return Observable.create(e -> { + if (!TextUtils.isEmpty(query)) { + SongLoader.getSongs(context, query) + .subscribe(songs -> { + if (!songs.isEmpty()) { + results.add(context.getResources().getString(R.string.songs)); + results.addAll(songs); + } + }); + + ArtistLoader.getArtists(context, query) + .subscribe(artists -> { + if (!artists.isEmpty()) { + results.add(context.getResources().getString(R.string.artists)); + results.addAll(artists); + } + }); + AlbumLoader.getAlbums(context, query) + .subscribe(albums -> { + if (!albums.isEmpty()) { + results.add(context.getResources().getString(R.string.albums)); + results.addAll(albums); + } + }); + } + e.onNext(results); + e.onComplete(); + }); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/SongLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/SongLoader.java new file mode 100644 index 00000000..45e3ed07 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/SongLoader.java @@ -0,0 +1,191 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.database.Cursor; +import android.provider.BaseColumns; +import android.provider.MediaStore; +import android.provider.MediaStore.Audio.AudioColumns; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.helper.ShuffleHelper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.providers.BlacklistStore; +import code.name.monkey.retromusic.util.PreferenceUtil; +import io.reactivex.Observable; + +/** + * Created by hemanths on 10/08/17. + */ + +public class SongLoader { + + protected static final String BASE_SELECTION = + AudioColumns.IS_MUSIC + "=1" + " AND " + AudioColumns.TITLE + " != ''"; + protected static final String[] BASE_PROJECTION = new String[]{ + BaseColumns._ID,// 0 + AudioColumns.TITLE,// 1 + AudioColumns.TRACK,// 2 + AudioColumns.YEAR,// 3 + AudioColumns.DURATION,// 4 + AudioColumns.DATA,// 5 + AudioColumns.DATE_MODIFIED,// 6 + AudioColumns.ALBUM_ID,// 7 + AudioColumns.ALBUM,// 8 + AudioColumns.ARTIST_ID,// 9 + AudioColumns.ARTIST,// 10 + }; + + @NonNull + public static Observable> getAllSongs(@NonNull Context context) { + Cursor cursor = makeSongCursor(context, null, null); + return getSongs(cursor); + } + + @NonNull + public static Observable> getSongs(@NonNull final Context context, + final String query) { + Cursor cursor = makeSongCursor(context, AudioColumns.TITLE + " LIKE ?", + new String[]{"%" + query + "%"}); + return getSongs(cursor); + } + + @NonNull + public static Observable> getSongs(@Nullable final Cursor cursor) { + return Observable.create(e -> { + ArrayList songs = new ArrayList<>(); + if (cursor != null && cursor.moveToFirst()) { + do { + songs.add(getSongFromCursorImpl(cursor)); + } while (cursor.moveToNext()); + } + + if (cursor != null) { + cursor.close(); + } + e.onNext(songs); + e.onComplete(); + }); + } + + @NonNull + private static Song getSongFromCursorImpl(@NonNull Cursor cursor) { + final int id = cursor.getInt(0); + final String title = cursor.getString(1); + final int trackNumber = cursor.getInt(2); + final int year = cursor.getInt(3); + final long duration = cursor.getLong(4); + final String data = cursor.getString(5); + final long dateModified = cursor.getLong(6); + final int albumId = cursor.getInt(7); + final String albumName = cursor.getString(8); + final int artistId = cursor.getInt(9); + final String artistName = cursor.getString(10); + + return new Song(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, + artistId, artistName); + } + + @Nullable + public static Cursor makeSongCursor(@NonNull final Context context, + @Nullable final String selection, final String[] selectionValues) { + return makeSongCursor(context, selection, selectionValues, + PreferenceUtil.getInstance(context).getSongSortOrder()); + } + + @Nullable + public static Cursor makeSongCursor(@NonNull final Context context, @Nullable String selection, + String[] selectionValues, final String sortOrder) { + if (selection != null && !selection.trim().equals("")) { + selection = BASE_SELECTION + " AND " + selection; + } else { + selection = BASE_SELECTION; + } + + // Blacklist + ArrayList paths = BlacklistStore.getInstance(context).getPaths(); + if (!paths.isEmpty()) { + selection = generateBlacklistSelection(selection, paths.size()); + selectionValues = addBlacklistSelectionValues(selectionValues, paths); + } + + try { + return context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + BASE_PROJECTION, selection, selectionValues, sortOrder); + } catch (SecurityException e) { + return null; + } + } + + private static String generateBlacklistSelection(String selection, int pathCount) { + StringBuilder newSelection = new StringBuilder( + selection != null && !selection.trim().equals("") ? selection + " AND " : ""); + newSelection.append(AudioColumns.DATA + " NOT LIKE ?"); + for (int i = 0; i < pathCount - 1; i++) { + newSelection.append(" AND " + AudioColumns.DATA + " NOT LIKE ?"); + } + return newSelection.toString(); + } + + private static String[] addBlacklistSelectionValues(String[] selectionValues, + ArrayList paths) { + if (selectionValues == null) { + selectionValues = new String[0]; + } + String[] newSelectionValues = new String[selectionValues.length + paths.size()]; + System.arraycopy(selectionValues, 0, newSelectionValues, 0, selectionValues.length); + for (int i = selectionValues.length; i < newSelectionValues.length; i++) { + newSelectionValues[i] = paths.get(i - selectionValues.length) + "%"; + } + return newSelectionValues; + } + + @NonNull + public static Observable getSong(@Nullable Cursor cursor) { + return Observable.create(e -> { + Song song; + if (cursor != null && cursor.moveToFirst()) { + song = getSongFromCursorImpl(cursor); + } else { + song = Song.EMPTY_SONG; + } + if (cursor != null) { + cursor.close(); + } + e.onNext(song); + e.onComplete(); + }); + } + + @NonNull + public static Observable getSong(@NonNull final Context context, final int queryId) { + Cursor cursor = makeSongCursor(context, AudioColumns._ID + "=?", + new String[]{String.valueOf(queryId)}); + return getSong(cursor); + } + + public static Observable> suggestSongs(@NonNull Context context) { + return Observable.create(observer -> { + SongLoader.getAllSongs(context) + .subscribe(songs -> { + ArrayList list = new ArrayList<>(); + if (songs.isEmpty()) { + observer.onNext(new ArrayList<>()); + observer.onComplete(); + return; + } + ShuffleHelper.makeShuffleList(songs, -1); + if (songs.size() > 10) { + list.addAll(songs.subList(0, 10)); + } else { + list.addAll(songs); + } + observer.onNext(list); + observer.onComplete(); + }); + }); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/SortedCursor.java b/app/src/main/java/code/name/monkey/retromusic/loaders/SortedCursor.java new file mode 100644 index 00000000..06ab0d27 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/SortedCursor.java @@ -0,0 +1,169 @@ +/* +* Copyright (C) 2014 The CyanogenMod Project +* +* 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 +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* 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 code.name.monkey.retromusic.loaders; + +import android.database.AbstractCursor; +import android.database.Cursor; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +/** + * This cursor basically wraps a song cursor and is given a list of the order of the ids of the + * contents of the cursor. It wraps the Cursor and simulates the internal cursor being sorted + * by moving the point to the appropriate spot + */ +public class SortedCursor extends AbstractCursor { + // cursor to wrap + private final Cursor mCursor; + // the map of external indices to internal indices + private ArrayList mOrderedPositions; + // this contains the ids that weren't found in the underlying cursor + private ArrayList mMissingValues; + // this contains the mapped cursor positions and afterwards the extra ids that weren't found + private HashMap mMapCursorPositions; + + /** + * @param cursor to wrap + * @param order the list of unique ids in sorted order to display + * @param columnName the column name of the id to look up in the internal cursor + */ + public SortedCursor(@NonNull final Cursor cursor, @Nullable final String[] order, final String columnName) { + mCursor = cursor; + mMissingValues = buildCursorPositionMapping(order, columnName); + } + + /** + * This function populates mOrderedPositions with the cursor positions in the order based + * on the order passed in + * + * @param order the target order of the internal cursor + * @return returns the ids that aren't found in the underlying cursor + */ + @NonNull + private ArrayList buildCursorPositionMapping(@Nullable final String[] order, final String columnName) { + ArrayList missingValues = new ArrayList<>(); + + mOrderedPositions = new ArrayList<>(mCursor.getCount()); + + mMapCursorPositions = new HashMap<>(mCursor.getCount()); + final int valueColumnIndex = mCursor.getColumnIndex(columnName); + + if (mCursor.moveToFirst()) { + // first figure out where each of the ids are in the cursor + do { + mMapCursorPositions.put(mCursor.getString(valueColumnIndex), mCursor.getPosition()); + } while (mCursor.moveToNext()); + + if (order != null) { + // now create the ordered positions to map to the internal cursor given the + // external sort order + for (final String value : order) { + if (mMapCursorPositions.containsKey(value)) { + mOrderedPositions.add(mMapCursorPositions.get(value)); + mMapCursorPositions.remove(value); + } else { + missingValues.add(value); + } + } + } + + mCursor.moveToFirst(); + } + + return missingValues; + } + + /** + * @return the list of ids that weren't found in the underlying cursor + */ + public ArrayList getMissingValues() { + return mMissingValues; + } + + /** + * @return the list of ids that were in the underlying cursor but not part of the ordered list + */ + @NonNull + public Collection getExtraValues() { + return mMapCursorPositions.keySet(); + } + + @Override + public void close() { + mCursor.close(); + + super.close(); + } + + @Override + public int getCount() { + return mOrderedPositions.size(); + } + + @Override + public String[] getColumnNames() { + return mCursor.getColumnNames(); + } + + @Override + public String getString(int column) { + return mCursor.getString(column); + } + + @Override + public short getShort(int column) { + return mCursor.getShort(column); + } + + @Override + public int getInt(int column) { + return mCursor.getInt(column); + } + + @Override + public long getLong(int column) { + return mCursor.getLong(column); + } + + @Override + public float getFloat(int column) { + return mCursor.getFloat(column); + } + + @Override + public double getDouble(int column) { + return mCursor.getDouble(column); + } + + @Override + public boolean isNull(int column) { + return mCursor.isNull(column); + } + + @Override + public boolean onMove(int oldPosition, int newPosition) { + if (newPosition >= 0 && newPosition < getCount()) { + mCursor.moveToPosition(mOrderedPositions.get(newPosition)); + return true; + } + + return false; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/SortedLongCursor.java b/app/src/main/java/code/name/monkey/retromusic/loaders/SortedLongCursor.java new file mode 100644 index 00000000..aea82900 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/SortedLongCursor.java @@ -0,0 +1,169 @@ +/* +* Copyright (C) 2014 The CyanogenMod Project +* +* 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 +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* 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 code.name.monkey.retromusic.loaders; + +import android.database.AbstractCursor; +import android.database.Cursor; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +/** + * This cursor basically wraps a song cursor and is given a list of the order of the ids of the + * contents of the cursor. It wraps the Cursor and simulates the internal cursor being sorted + * by moving the point to the appropriate spot + */ +public class SortedLongCursor extends AbstractCursor { + // cursor to wrap + private final Cursor mCursor; + // the map of external indices to internal indices + private ArrayList mOrderedPositions; + // this contains the ids that weren't found in the underlying cursor + private ArrayList mMissingIds; + // this contains the mapped cursor positions and afterwards the extra ids that weren't found + private HashMap mMapCursorPositions; + + /** + * @param cursor to wrap + * @param order the list of unique ids in sorted order to display + * @param columnName the column name of the id to look up in the internal cursor + */ + public SortedLongCursor(final Cursor cursor, final long[] order, final String columnName) { + + mCursor = cursor; + mMissingIds = buildCursorPositionMapping(order, columnName); + } + + /** + * This function populates mOrderedPositions with the cursor positions in the order based + * on the order passed in + * + * @param order the target order of the internal cursor + * @return returns the ids that aren't found in the underlying cursor + */ + @NonNull + private ArrayList buildCursorPositionMapping(@Nullable final long[] order, final String columnName) { + ArrayList missingIds = new ArrayList<>(); + + mOrderedPositions = new ArrayList<>(mCursor.getCount()); + + mMapCursorPositions = new HashMap<>(mCursor.getCount()); + final int idPosition = mCursor.getColumnIndex(columnName); + + if (mCursor.moveToFirst()) { + // first figure out where each of the ids are in the cursor + do { + mMapCursorPositions.put(mCursor.getLong(idPosition), mCursor.getPosition()); + } while (mCursor.moveToNext()); + + // now create the ordered positions to map to the internal cursor given the + // external sort order + for (int i = 0; order != null && i < order.length; i++) { + final long id = order[i]; + if (mMapCursorPositions.containsKey(id)) { + mOrderedPositions.add(mMapCursorPositions.get(id)); + mMapCursorPositions.remove(id); + } else { + missingIds.add(id); + } + } + + mCursor.moveToFirst(); + } + + return missingIds; + } + + /** + * @return the list of ids that weren't found in the underlying cursor + */ + public ArrayList getMissingIds() { + return mMissingIds; + } + + /** + * @return the list of ids that were in the underlying cursor but not part of the ordered list + */ + @NonNull + public Collection getExtraIds() { + return mMapCursorPositions.keySet(); + } + + @Override + public void close() { + mCursor.close(); + + super.close(); + } + + @Override + public int getCount() { + return mOrderedPositions.size(); + } + + @Override + public String[] getColumnNames() { + return mCursor.getColumnNames(); + } + + @Override + public String getString(int column) { + return mCursor.getString(column); + } + + @Override + public short getShort(int column) { + return mCursor.getShort(column); + } + + @Override + public int getInt(int column) { + return mCursor.getInt(column); + } + + @Override + public long getLong(int column) { + return mCursor.getLong(column); + } + + @Override + public float getFloat(int column) { + return mCursor.getFloat(column); + } + + @Override + public double getDouble(int column) { + return mCursor.getDouble(column); + } + + @Override + public boolean isNull(int column) { + return mCursor.isNull(column); + } + + @Override + public boolean onMove(int oldPosition, int newPosition) { + if (newPosition >= 0 && newPosition < getCount()) { + mCursor.moveToPosition(mOrderedPositions.get(newPosition)); + return true; + } + + return false; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/TopAndRecentlyPlayedTracksLoader.java b/app/src/main/java/code/name/monkey/retromusic/loaders/TopAndRecentlyPlayedTracksLoader.java new file mode 100644 index 00000000..1bf59552 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/TopAndRecentlyPlayedTracksLoader.java @@ -0,0 +1,158 @@ +package code.name.monkey.retromusic.loaders; + +import android.content.Context; +import android.database.Cursor; +import android.provider.BaseColumns; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.providers.HistoryStore; +import code.name.monkey.retromusic.providers.SongPlayCountStore; +import io.reactivex.Observable; +import java.util.ArrayList; + +/** + * Created by hemanths on 16/08/17. + */ + +public class TopAndRecentlyPlayedTracksLoader { + + private static final int NUMBER_OF_TOP_TRACKS = 99; + + @NonNull + public static Observable> getRecentlyPlayedTracks(@NonNull Context context) { + return SongLoader.getSongs(makeRecentTracksCursorAndClearUpDatabase(context)); + } + + @NonNull + public static Observable> getTopTracks(@NonNull Context context) { + return SongLoader.getSongs(makeTopTracksCursorAndClearUpDatabase(context)); + } + + @Nullable + private static Cursor makeRecentTracksCursorAndClearUpDatabase(@NonNull final Context context) { + SortedLongCursor retCursor = makeRecentTracksCursorImpl(context); + + // clean up the databases with any ids not found + if (retCursor != null) { + ArrayList missingIds = retCursor.getMissingIds(); + if (missingIds != null && missingIds.size() > 0) { + for (long id : missingIds) { + HistoryStore.getInstance(context).removeSongId(id); + } + } + } + return retCursor; + } + + @Nullable + private static Cursor makeTopTracksCursorAndClearUpDatabase(@NonNull final Context context) { + SortedLongCursor retCursor = makeTopTracksCursorImpl(context); + + // clean up the databases with any ids not found + if (retCursor != null) { + ArrayList missingIds = retCursor.getMissingIds(); + if (missingIds != null && missingIds.size() > 0) { + for (long id : missingIds) { + SongPlayCountStore.getInstance(context).removeItem(id); + } + } + } + return retCursor; + } + + @Nullable + private static SortedLongCursor makeRecentTracksCursorImpl(@NonNull final Context context) { + // first get the top results ids from the internal database + Cursor songs = HistoryStore.getInstance(context).queryRecentIds(); + + try { + return makeSortedCursor(context, songs, + songs.getColumnIndex(HistoryStore.RecentStoreColumns.ID)); + } finally { + if (songs != null) { + songs.close(); + } + } + } + + @Nullable + private static SortedLongCursor makeTopTracksCursorImpl(@NonNull final Context context) { + // first get the top results ids from the internal database + Cursor songs = SongPlayCountStore.getInstance(context) + .getTopPlayedResults(NUMBER_OF_TOP_TRACKS); + + try { + return makeSortedCursor(context, songs, + songs.getColumnIndex(SongPlayCountStore.SongPlayCountColumns.ID)); + } finally { + if (songs != null) { + songs.close(); + } + } + } + + @Nullable + private static SortedLongCursor makeSortedCursor(@NonNull final Context context, + @Nullable final Cursor cursor, final int idColumn) { + + if (cursor != null && cursor.moveToFirst()) { + // create the list of ids to select against + StringBuilder selection = new StringBuilder(); + selection.append(BaseColumns._ID); + selection.append(" IN ("); + + // this tracks the order of the ids + long[] order = new long[cursor.getCount()]; + + long id = cursor.getLong(idColumn); + selection.append(id); + order[cursor.getPosition()] = id; + + while (cursor.moveToNext()) { + selection.append(","); + + id = cursor.getLong(idColumn); + order[cursor.getPosition()] = id; + selection.append(String.valueOf(id)); + } + + selection.append(")"); + + // get a list of songs with the data given the selection statement + Cursor songCursor = SongLoader.makeSongCursor(context, selection.toString(), null); + if (songCursor != null) { + // now return the wrapped TopTracksCursor to handle sorting given order + return new SortedLongCursor(songCursor, order, BaseColumns._ID); + } + } + + return null; + } + + @NonNull + public static Observable> getTopAlbums(@NonNull Context context) { + return Observable.create(e -> { + getTopTracks(context).subscribe(songs -> { + if (songs.size() > 0) { + e.onNext(AlbumLoader.splitIntoAlbums(songs)); + } + e.onComplete(); + }); + }); + } + + @NonNull + public static Observable> getTopArtists(@NonNull Context context) { + return Observable.create(e -> { + getTopAlbums(context).subscribe(albums -> { + if (albums.size() > 0) { + e.onNext(ArtistLoader.splitIntoArtists(albums)); + } + e.onComplete(); + }); + }); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/lyrics/KogouLyricsFetcher.java b/app/src/main/java/code/name/monkey/retromusic/lyrics/KogouLyricsFetcher.java new file mode 100644 index 00000000..02ded432 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/lyrics/KogouLyricsFetcher.java @@ -0,0 +1,69 @@ +package code.name.monkey.retromusic.lyrics; + +import android.os.Handler; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.rest.KogouClient; +import code.name.monkey.retromusic.rest.model.KuGouSearchLyricResult; +import code.name.monkey.retromusic.util.LyricUtil; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; +import java.io.File; + +/** + * @author Hemanth S (h4h13). + */ + +public class KogouLyricsFetcher { + + private KogouClient mKogouClient; + private Song mSong; + private KogouLyricsCallback mCallback; + + public KogouLyricsFetcher(KogouLyricsCallback callback) { + mCallback = callback; + mKogouClient = new KogouClient(); + } + + public void loadLyrics(Song song, String duration) { + mSong = song; + mKogouClient.getApiService() + .searchLyric(mSong.title, duration) + .subscribe(this::parseKugouResult, + throwable -> mCallback.onNoLyrics()); + } + + private void parseKugouResult(KuGouSearchLyricResult kuGouSearchLyricResult) { + if (kuGouSearchLyricResult != null && kuGouSearchLyricResult.status == 200 & + kuGouSearchLyricResult.candidates != null && + kuGouSearchLyricResult.candidates.size() != 0) { + KuGouSearchLyricResult.Candidates candidates = kuGouSearchLyricResult.candidates.get(0); + loadLyricsFile(candidates); + } else { + mCallback.onNoLyrics(); + } + } + + private void loadLyricsFile(KuGouSearchLyricResult.Candidates candidates) { + mKogouClient.getApiService().getRawLyric(candidates.id, candidates.accesskey) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeOn(Schedulers.io()) + .subscribe(kuGouRawLyric -> { + if (kuGouRawLyric == null) { + mCallback.onNoLyrics(); + return; + } + String rawLyric = LyricUtil.decryptBASE64(kuGouRawLyric.content); + LyricUtil.writeLrcToLoc(mSong.title, mSong.artistName, rawLyric); + new Handler().postDelayed( + () -> mCallback.onLyrics(LyricUtil.getLocalLyricFile(mSong.title, mSong.artistName)), + 1); + }); + } + + public interface KogouLyricsCallback { + + void onNoLyrics(); + + void onLyrics(File file); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/lyrics/LyricsEngine.java b/app/src/main/java/code/name/monkey/retromusic/lyrics/LyricsEngine.java new file mode 100644 index 00000000..52884ce8 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/lyrics/LyricsEngine.java @@ -0,0 +1,6 @@ +package code.name.monkey.retromusic.lyrics; + +public interface LyricsEngine { + String getLyrics(String artistName, String songTitle); + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/lyrics/LyricsWikiEngine.java b/app/src/main/java/code/name/monkey/retromusic/lyrics/LyricsWikiEngine.java new file mode 100644 index 00000000..fde1fa5b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/lyrics/LyricsWikiEngine.java @@ -0,0 +1,143 @@ +package code.name.monkey.retromusic.lyrics; + +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; +import org.jsoup.nodes.TextNode; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringWriter; +import java.net.URL; + +import javax.net.ssl.HttpsURLConnection; + +public class LyricsWikiEngine implements LyricsEngine { + + private static final String TAG = LyricsWikiEngine.class.getSimpleName(); + + // Reads an InputStream and converts it to a String. + private static String readIt(InputStream stream) throws IOException { + Reader reader = new InputStreamReader(stream, "UTF-8"); + StringWriter sw = new StringWriter(); + char[] buffer = new char[4096]; + int count; + while ((count = reader.read(buffer)) != -1) { + sw.write(buffer, 0, count); + } + + return sw.toString(); + } + + @Override + public String getLyrics(String artistName, String songTitle) { + try { + + String lyricsUrl = makeApiCall(artistName, songTitle); + if (lyricsUrl == null) { // no URL in API answer or no correct answer at all + return null; + } + + return parseFullLyricsPage(lyricsUrl); + + } catch (IOException e) { + Log.w(TAG, "Couldn't connect to lyrics wiki REST endpoints", e); + return null; + } catch (JSONException e) { + Log.w(TAG, "Couldn't transform API answer to JSON entity", e); + return null; + } + } + + /** + * First call + */ + private String makeApiCall(String artistName, String songTitle) throws IOException, JSONException { + HttpsURLConnection apiCall = null; + try { + // build query + // e.g. https://lyrics.wikia.com/api.php?func=getSong&artist=The%20Beatle&song=Girl&fmt=realjson + Uri link = new Uri.Builder() + .scheme("https") + .authority("lyrics.wikia.com") + .path("api.php") + .appendQueryParameter("func", "getSong") + .appendQueryParameter("fmt", "realjson") + .appendQueryParameter("artist", artistName) + .appendQueryParameter("song", songTitle) + .build(); + + // construct an http request + apiCall = (HttpsURLConnection) new URL(link.toString()).openConnection(); + apiCall.setReadTimeout(10_000); + apiCall.setConnectTimeout(15_000); + + // execute + apiCall.connect(); + int response = apiCall.getResponseCode(); + if (response != HttpsURLConnection.HTTP_OK) { + // redirects are handled internally, this is clearly an error + return null; + } + + InputStream is = apiCall.getInputStream(); + String reply = readIt(is); + JSONObject getSongAnswer = new JSONObject(reply); + + return getLyricsUrl(getSongAnswer); + } finally { + if (apiCall != null) { + apiCall.disconnect(); + } + } + } + + /** + * Second call + */ + private String parseFullLyricsPage(String lyricsUrl) throws IOException { + Document page = Jsoup.parse(new URL(lyricsUrl), 10_000); + Element lyricsBox = page.select("div.lyricbox").first(); + if (lyricsBox == null) { // no lyrics frame on page + return null; + } + + // remove unneeded elements + lyricsBox.select("div.rtMatcher").remove(); + lyricsBox.select("div.lyricsbreak").remove(); + lyricsBox.select("script").remove(); + + StringBuilder builder = new StringBuilder(); + for (Node curr : lyricsBox.childNodes()) { + if (curr instanceof TextNode) { + builder.append(((TextNode) curr).text()); + } else { + builder.append("\n"); + } + } + return builder.toString(); + } + + private String getLyricsUrl(JSONObject getSongAnswer) { + try { + String pageId = getSongAnswer.getString("page_id"); + if (TextUtils.isEmpty(pageId)) { + return null; // empty page_id means page wasn't created + } + return getSongAnswer.getString("url"); + } catch (JSONException e) { + Log.w(TAG, "Unknown format of getSong API call answer", e); + return null; + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/lyrics/ParseLyrics.java b/app/src/main/java/code/name/monkey/retromusic/lyrics/ParseLyrics.java new file mode 100644 index 00000000..17f88814 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/lyrics/ParseLyrics.java @@ -0,0 +1,38 @@ +package code.name.monkey.retromusic.lyrics; + +import android.os.AsyncTask; +import android.text.TextUtils; + +/** + * @author Hemanth S (h4h13). + */ + +public class ParseLyrics extends AsyncTask { + private LyricsCallback mLyricsCallback; + + public ParseLyrics(LyricsCallback lyricsCallback) { + mLyricsCallback = lyricsCallback; + } + + @Override + protected String doInBackground(String... strings) { + LyricsEngine lyricsEngine = new LyricsWikiEngine(); + return lyricsEngine.getLyrics(strings[1], strings[0]); + } + + @Override + protected void onPostExecute(String s) { + super.onPostExecute(s); + if (TextUtils.isEmpty(s)) { + mLyricsCallback.onError(); + return; + } + mLyricsCallback.onShowLyrics(s); + } + + public interface LyricsCallback { + void onShowLyrics(String lyrics); + + void onError(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/lyrics/QueryResult.java b/app/src/main/java/code/name/monkey/retromusic/lyrics/QueryResult.java new file mode 100644 index 00000000..aa70f50c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/lyrics/QueryResult.java @@ -0,0 +1,23 @@ +package code.name.monkey.retromusic.lyrics; + +public class QueryResult { + public static final String ITEM_LRC = "lrc"; + public static final String ATTRIBUTE_ID = "id"; + public static final String ATTRIBUTE_ARTIST = "artist"; + public static final String ATTRIBUTE_TITLE = "title"; + + public final int mId; + public final String mArtist; + public final String mTitle; + + QueryResult(int id, String artist, String title) { + mId = id; + mArtist = artist; + mTitle = title; + } + + @Override + public String toString() { + return mTitle + " - " + mArtist; + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/AppBarStateChangeListener.java b/app/src/main/java/code/name/monkey/retromusic/misc/AppBarStateChangeListener.java new file mode 100644 index 00000000..0f1f8a92 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/AppBarStateChangeListener.java @@ -0,0 +1,41 @@ +package code.name.monkey.retromusic.misc; + +import android.support.design.widget.AppBarLayout; + +/** + * @author Hemanth S (h4h13). + * https://stackoverflow.com/a/33891727 + */ + +public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener { + + private State mCurrentState = State.IDLE; + + @Override + public final void onOffsetChanged(AppBarLayout appBarLayout, int i) { + if (i == 0) { + if (mCurrentState != State.EXPANDED) { + onStateChanged(appBarLayout, State.EXPANDED); + } + mCurrentState = State.EXPANDED; + } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) { + if (mCurrentState != State.COLLAPSED) { + onStateChanged(appBarLayout, State.COLLAPSED); + } + mCurrentState = State.COLLAPSED; + } else { + if (mCurrentState != State.IDLE) { + onStateChanged(appBarLayout, State.IDLE); + } + mCurrentState = State.IDLE; + } + } + + public abstract void onStateChanged(AppBarLayout appBarLayout, State state); + + public enum State { + EXPANDED, + COLLAPSED, + IDLE + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/CustomFragmentStatePagerAdapter.java b/app/src/main/java/code/name/monkey/retromusic/misc/CustomFragmentStatePagerAdapter.java new file mode 100644 index 00000000..ee733845 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/CustomFragmentStatePagerAdapter.java @@ -0,0 +1,237 @@ +package code.name.monkey.retromusic.misc; + +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +import android.os.Bundle; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; + +/** + * Implementation of {@link android.support.v4.view.PagerAdapter} that + * uses a {@link Fragment} to manage each page. This class also handles + * saving and restoring of fragment's state. + *

    + *

    This version of the pager is more useful when there are a large number + * of pages, working more like a list view. When pages are not visible to + * the user, their entire fragment may be destroyed, only keeping the saved + * state of that fragment. This allows the pager to hold on to much less + * memory associated with each visited page as compared to + * {@link FragmentPagerAdapter} at the cost of potentially more overhead when + * switching between pages. + *

    + *

    When using FragmentPagerAdapter the host ViewPager must have a + * valid ID set.

    + *

    + *

    Subclasses only need to implement {@link #getItem(int)} + * and {@link #getCount()} to have a working adapter. + *

    + *

    Here is an example implementation of a pager containing fragments of + * lists: + *

    + * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentStatePagerSupport.java + * complete} + *

    + *

    The R.layout.fragment_pager resource of the top-level fragment is: + *

    + * {@sample development/samples/Support13Demos/res/layout/fragment_pager.xml + * complete} + *

    + *

    The R.layout.fragment_pager_list resource containing each + * individual fragment's layout is: + *

    + * {@sample development/samples/Support13Demos/res/layout/fragment_pager_list.xml + * complete} + */ +public abstract class CustomFragmentStatePagerAdapter extends android.support.v4.view.PagerAdapter { + public static final String TAG = CustomFragmentStatePagerAdapter.class.getSimpleName(); + private static final boolean DEBUG = false; + + private final FragmentManager mFragmentManager; + private FragmentTransaction mCurTransaction = null; + + private ArrayList mSavedState = new ArrayList(); + private ArrayList mFragments = new ArrayList(); + private Fragment mCurrentPrimaryItem = null; + + public CustomFragmentStatePagerAdapter(FragmentManager fm) { + mFragmentManager = fm; + } + + /** + * Return the Fragment associated with a specified position. + */ + public abstract Fragment getItem(int position); + + @Override + public void startUpdate(ViewGroup container) { + } + + @NonNull + @Override + public Object instantiateItem(ViewGroup container, int position) { + // If we already have this item instantiated, there is nothing + // to do. This can happen when we are restoring the entire pager + // from its saved state, where the fragment manager has already + // taken care of restoring the fragments we previously had instantiated. + if (mFragments.size() > position) { + Fragment f = mFragments.get(position); + if (f != null) { + return f; + } + } + + if (mCurTransaction == null) { + mCurTransaction = mFragmentManager.beginTransaction(); + } + + Fragment fragment = getItem(position); + if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); + if (mSavedState.size() > position) { + Fragment.SavedState fss = mSavedState.get(position); + if (fss != null) { + fragment.setInitialSavedState(fss); + } + } + while (mFragments.size() <= position) { + mFragments.add(null); + } + fragment.setMenuVisibility(false); + fragment.setUserVisibleHint(false); + mFragments.set(position, fragment); + mCurTransaction.add(container.getId(), fragment); + + return fragment; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + Fragment fragment = (Fragment) object; + + if (mCurTransaction == null) { + mCurTransaction = mFragmentManager.beginTransaction(); + } + if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object + + " v=" + ((Fragment) object).getView()); + while (mSavedState.size() <= position) { + mSavedState.add(null); + } + mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment)); + mFragments.set(position, null); + + mCurTransaction.remove(fragment); + } + + @Override + public void setPrimaryItem(ViewGroup container, int position, Object object) { + Fragment fragment = (Fragment) object; + if (fragment != mCurrentPrimaryItem) { + if (mCurrentPrimaryItem != null) { + mCurrentPrimaryItem.setMenuVisibility(false); + mCurrentPrimaryItem.setUserVisibleHint(false); + } + if (fragment != null) { + fragment.setMenuVisibility(true); + fragment.setUserVisibleHint(true); + } + mCurrentPrimaryItem = fragment; + } + } + + @Override + public void finishUpdate(ViewGroup container) { + if (mCurTransaction != null) { + mCurTransaction.commitAllowingStateLoss(); + mCurTransaction = null; + mFragmentManager.executePendingTransactions(); + } + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return ((Fragment) object).getView() == view; + } + + @Override + public Parcelable saveState() { + Bundle state = null; + if (mSavedState.size() > 0) { + state = new Bundle(); + Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()]; + mSavedState.toArray(fss); + state.putParcelableArray("states", fss); + } + for (int i = 0; i < mFragments.size(); i++) { + Fragment f = mFragments.get(i); + if (f != null && f.isAdded()) { + if (state == null) { + state = new Bundle(); + } + String key = "f" + i; + mFragmentManager.putFragment(state, key, f); + } + } + return state; + } + + @Override + public void restoreState(Parcelable state, ClassLoader loader) { + if (state != null) { + Bundle bundle = (Bundle) state; + bundle.setClassLoader(loader); + Parcelable[] fss = bundle.getParcelableArray("states"); + mSavedState.clear(); + mFragments.clear(); + if (fss != null) { + for (int i = 0; i < fss.length; i++) { + mSavedState.add((Fragment.SavedState) fss[i]); + } + } + Iterable keys = bundle.keySet(); + for (String key : keys) { + if (key.startsWith("f")) { + int index = Integer.parseInt(key.substring(1)); + Fragment f = mFragmentManager.getFragment(bundle, key); + if (f != null) { + while (mFragments.size() <= index) { + mFragments.add(null); + } + f.setMenuVisibility(false); + mFragments.set(index, f); + } else { + Log.w(TAG, "Bad fragment at key " + key); + } + } + } + } + } + + public Fragment getFragment(int position) { + if (position < mFragments.size() && position >= 0) { + return mFragments.get(position); + } + return null; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/DialogAsyncTask.java b/app/src/main/java/code/name/monkey/retromusic/misc/DialogAsyncTask.java new file mode 100644 index 00000000..8dd39943 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/DialogAsyncTask.java @@ -0,0 +1,90 @@ +package code.name.monkey.retromusic.misc; + +import android.app.Dialog; +import android.content.Context; +import android.os.Handler; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.lang.ref.WeakReference; + + +public abstract class DialogAsyncTask extends WeakContextAsyncTask { + private final int delay; + private WeakReference

    dialogWeakReference; + + private boolean supposedToBeDismissed; + + public DialogAsyncTask(Context context) { + this(context, 0); + } + + public DialogAsyncTask(Context context, int showDelay) { + super(context); + this.delay = showDelay; + dialogWeakReference = new WeakReference<>(null); + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + if (delay > 0) { + new Handler().postDelayed(this::initAndShowDialog, delay); + } else { + initAndShowDialog(); + } + } + + private void initAndShowDialog() { + Context context = getContext(); + if (!supposedToBeDismissed && context != null) { + Dialog dialog = createDialog(context); + dialogWeakReference = new WeakReference<>(dialog); + dialog.show(); + } + } + + @SuppressWarnings("unchecked") + @Override + protected void onProgressUpdate(Progress... values) { + super.onProgressUpdate(values); + Dialog dialog = getDialog(); + if (dialog != null) { + onProgressUpdate(dialog, values); + } + } + + @SuppressWarnings("unchecked") + protected void onProgressUpdate(@NonNull Dialog dialog, Progress... values) { + } + + @Nullable + protected Dialog getDialog() { + return dialogWeakReference.get(); + } + + @Override + protected void onCancelled(Result result) { + super.onCancelled(result); + tryToDismiss(); + } + + @Override + protected void onPostExecute(Result result) { + super.onPostExecute(result); + tryToDismiss(); + } + + private void tryToDismiss() { + supposedToBeDismissed = true; + try { + Dialog dialog = getDialog(); + if (dialog != null) + dialog.dismiss(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + protected abstract Dialog createDialog(@NonNull Context context); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/LagTracker.java b/app/src/main/java/code/name/monkey/retromusic/misc/LagTracker.java new file mode 100755 index 00000000..da7e7f64 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/LagTracker.java @@ -0,0 +1,62 @@ +package code.name.monkey.retromusic.misc; + +import android.util.Log; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class LagTracker { + private static Map mMap; + private static LagTracker mSingleton; + private boolean mEnabled = true; + + private LagTracker() { + mMap = new HashMap(); + } + + public static LagTracker get() { + if (mSingleton == null) { + mSingleton = new LagTracker(); + } + return mSingleton; + } + + private void print(String str, long j) { + long toMillis = TimeUnit.NANOSECONDS.toMillis(j); + Log.d("LagTracker", "[" + str + " completed in]: " + j + " ns (" + toMillis + "ms, " + TimeUnit.NANOSECONDS.toSeconds(j) + "s)"); + } + + public LagTracker disable() { + this.mEnabled = false; + return this; + } + + public LagTracker enable() { + this.mEnabled = true; + return this; + } + + public void end(String str) { + long nanoTime = System.nanoTime(); + if (this.mEnabled) { + if (mMap.containsKey(str)) { + print(str, nanoTime - mMap.get(str).longValue()); + mMap.remove(str); + return; + } + throw new IllegalStateException("No start time found for " + str); + } else if (!mMap.isEmpty()) { + mMap.clear(); + } + } + + public void start(String str) { + long nanoTime = System.nanoTime(); + if (this.mEnabled) { + mMap.put(str, Long.valueOf(nanoTime)); + } else if (!mMap.isEmpty()) { + mMap.clear(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/ScrollAwareFABBehavior.java b/app/src/main/java/code/name/monkey/retromusic/misc/ScrollAwareFABBehavior.java new file mode 100644 index 00000000..a189d20c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/ScrollAwareFABBehavior.java @@ -0,0 +1,110 @@ +package code.name.monkey.retromusic.misc; + +import android.content.Context; +import android.os.Handler; +import android.support.annotation.NonNull; +import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.view.ViewCompat; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.animation.LinearInterpolator; + +/*Don't delete even if its not showing not using*/ +public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior { + private static final String TAG = "ScrollingFABBehavior"; + Handler mHandler; + + public ScrollAwareFABBehavior(Context context, AttributeSet attrs) { + super(); + } + + @Override + public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, + @NonNull FloatingActionButton child, + @NonNull View target) { + super.onStopNestedScroll(coordinatorLayout, child, target); + + if (mHandler == null) + mHandler = new Handler(); + + + mHandler.postDelayed(() -> { + child.animate().translationY(0).setInterpolator(new LinearInterpolator()).start(); + Log.d("FabAnim", "startHandler()"); + }, 1000); + + } + + @Override + public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, + @NonNull FloatingActionButton child, + @NonNull View target, + int dxConsumed, + int dyConsumed, + int dxUnconsumed, + int dyUnconsumed) { + super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); + + //child -> Floating Action Button + if (dyConsumed > 0) { + Log.d("Scrolling", "Up"); + CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) child.getLayoutParams(); + int fab_bottomMargin = layoutParams.bottomMargin; + child.animate().translationY(child.getHeight() + fab_bottomMargin).setInterpolator(new LinearInterpolator()).start(); + } else if (dyConsumed < 0) { + Log.d("Scrolling", "down"); + child.animate().translationY(0).setInterpolator(new LinearInterpolator()).start(); + } + } + + @Override + public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, + @NonNull FloatingActionButton child, + @NonNull View directTargetChild, + @NonNull View target, + int nestedScrollAxes) { + if (mHandler != null) { + mHandler.removeMessages(0); + Log.d("Scrolling", "stopHandler()"); + } + return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL; + } +} +/*extends FloatingActionButton.Behavior { + + public ScrollAwareFABBehavior(Context context, AttributeSet attrs) { + super(); + } + + + @Override + public boolean onStartNestedScroll(@NonNull final CoordinatorLayout coordinatorLayout, + @NonNull final FloatingActionButton child, + @NonNull final View directTargetChild, + @NonNull final View target, + final int nestedScrollAxes) { + // Ensure we react to vertical scrolling + return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL + || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); + } + + @Override + public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, + @NonNull FloatingActionButton child, + @NonNull View target, + int dxConsumed, + int dyConsumed, + int dxUnconsumed, + int dyUnconsumed) { + super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, + dyUnconsumed); + + if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) { + child.hide(); + } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) { + child.show(); + } + } +}*/ \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/SimpleAnimatorListener.java b/app/src/main/java/code/name/monkey/retromusic/misc/SimpleAnimatorListener.java new file mode 100644 index 00000000..2f405577 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/SimpleAnimatorListener.java @@ -0,0 +1,26 @@ +package code.name.monkey.retromusic.misc; + +import android.animation.Animator; + + +public abstract class SimpleAnimatorListener implements Animator.AnimatorListener { + @Override + public void onAnimationStart(Animator animation) { + + } + + @Override + public void onAnimationEnd(Animator animation) { + + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/SimpleOnSeekbarChangeListener.java b/app/src/main/java/code/name/monkey/retromusic/misc/SimpleOnSeekbarChangeListener.java new file mode 100644 index 00000000..44a39f6e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/SimpleOnSeekbarChangeListener.java @@ -0,0 +1,21 @@ +package code.name.monkey.retromusic.misc; + +import android.widget.SeekBar; + + +public abstract class SimpleOnSeekbarChangeListener implements SeekBar.OnSeekBarChangeListener { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/UpdateToastMediaScannerCompletionListener.java b/app/src/main/java/code/name/monkey/retromusic/misc/UpdateToastMediaScannerCompletionListener.java new file mode 100644 index 00000000..d9e3496a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/UpdateToastMediaScannerCompletionListener.java @@ -0,0 +1,50 @@ +package code.name.monkey.retromusic.misc; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.media.MediaScannerConnection; +import android.net.Uri; +import android.widget.Toast; + +import java.lang.ref.WeakReference; + +import code.name.monkey.retromusic.R; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public class UpdateToastMediaScannerCompletionListener implements MediaScannerConnection.OnScanCompletedListener { + private final String[] toBeScanned; + private final String scannedFiles; + private final String couldNotScanFiles; + private final WeakReference activityWeakReference; + private int scanned = 0; + private int failed = 0; + private Toast toast; + + @SuppressLint("ShowToast") + public UpdateToastMediaScannerCompletionListener(Activity activity, String[] toBeScanned) { + this.toBeScanned = toBeScanned; + scannedFiles = activity.getString(R.string.scanned_files); + couldNotScanFiles = activity.getString(R.string.could_not_scan_files); + toast = Toast.makeText(activity.getApplicationContext(), "", Toast.LENGTH_SHORT); + activityWeakReference = new WeakReference<>(activity); + } + + @Override + public void onScanCompleted(final String path, final Uri uri) { + Activity activity = activityWeakReference.get(); + if (activity != null) { + activity.runOnUiThread(() -> { + if (uri == null) { + failed++; + } else { + scanned++; + } + String text = " " + String.format(scannedFiles, scanned, toBeScanned.length) + (failed > 0 ? " " + String.format(couldNotScanFiles, failed) : ""); + toast.setText(text); + toast.show(); + }); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/WeakContextAsyncTask.java b/app/src/main/java/code/name/monkey/retromusic/misc/WeakContextAsyncTask.java new file mode 100644 index 00000000..c637d128 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/WeakContextAsyncTask.java @@ -0,0 +1 @@ +package code.name.monkey.retromusic.misc; import android.content.Context; import android.os.AsyncTask; import android.support.annotation.Nullable; import java.lang.ref.WeakReference; public abstract class WeakContextAsyncTask extends AsyncTask { private WeakReference contextWeakReference; public WeakContextAsyncTask(Context context) { contextWeakReference = new WeakReference<>(context); } @Nullable protected Context getContext() { return contextWeakReference.get(); } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/WrappedAsyncTaskLoader.java b/app/src/main/java/code/name/monkey/retromusic/misc/WrappedAsyncTaskLoader.java new file mode 100644 index 00000000..c0345087 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/WrappedAsyncTaskLoader.java @@ -0,0 +1,72 @@ + +package code.name.monkey.retromusic.misc; + +import android.content.Context; +import android.support.v4.content.AsyncTaskLoader; + +/** + * Issue + * 14944 + * + * @author Alexander Blom + */ +public abstract class WrappedAsyncTaskLoader extends AsyncTaskLoader { + + private D mData; + + /** + * Constructor of WrappedAsyncTaskLoader + * + * @param context The {@link Context} to use. + */ + public WrappedAsyncTaskLoader(Context context) { + super(context); + } + + /** + * {@inheritDoc} + */ + @Override + public void deliverResult(D data) { + if (!isReset()) { + this.mData = data; + super.deliverResult(data); + } else { + // An asynchronous query came in while the loader is stopped + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void onStartLoading() { + super.onStartLoading(); + if (this.mData != null) { + deliverResult(this.mData); + } else if (takeContentChanged() || this.mData == null) { + forceLoad(); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void onStopLoading() { + super.onStopLoading(); + // Attempt to cancel the current load task if possible + cancelLoad(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void onReset() { + super.onReset(); + // Ensure the loader is stopped + onStopLoading(); + this.mData = null; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/AbsCustomPlaylist.java b/app/src/main/java/code/name/monkey/retromusic/model/AbsCustomPlaylist.java new file mode 100644 index 00000000..55ca34f7 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/AbsCustomPlaylist.java @@ -0,0 +1,28 @@ +package code.name.monkey.retromusic.model; + +import android.content.Context; +import android.os.Parcel; +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +import io.reactivex.Observable; + + + +public abstract class AbsCustomPlaylist extends Playlist { + public AbsCustomPlaylist(int id, String name) { + super(id, name); + } + + public AbsCustomPlaylist() { + } + + public AbsCustomPlaylist(Parcel in) { + super(in); + } + + @NonNull + public abstract Observable> getSongs(Context context); +} + diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Album.java b/app/src/main/java/code/name/monkey/retromusic/model/Album.java new file mode 100644 index 00000000..93bf4c45 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/Album.java @@ -0,0 +1,103 @@ +package code.name.monkey.retromusic.model; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import java.util.ArrayList; + + +public class Album implements Parcelable { + + public static final Creator CREATOR = new Creator() { + public Album createFromParcel(Parcel source) { + return new Album(source); + } + + public Album[] newArray(int size) { + return new Album[size]; + } + }; + public final ArrayList songs; + + public Album(ArrayList songs) { + this.songs = songs; + } + + public Album() { + this.songs = new ArrayList<>(); + } + + protected Album(Parcel in) { + this.songs = in.createTypedArrayList(Song.CREATOR); + } + + public int getId() { + return safeGetFirstSong().albumId; + } + + public String getTitle() { + return safeGetFirstSong().albumName; + } + + public int getArtistId() { + return safeGetFirstSong().artistId; + } + + public String getArtistName() { + return safeGetFirstSong().artistName; + } + + public int getYear() { + return safeGetFirstSong().year; + } + + public long getDateModified() { + return safeGetFirstSong().dateModified; + } + + public int getSongCount() { + return songs.size(); + } + + @NonNull + public Song safeGetFirstSong() { + return songs.isEmpty() ? Song.EMPTY_SONG : songs.get(0); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Album that = (Album) o; + + return songs != null ? songs.equals(that.songs) : that.songs == null; + + } + + @Override + public int hashCode() { + return songs != null ? songs.hashCode() : 0; + } + + @Override + public String toString() { + return "Album{" + + "songs=" + songs + + '}'; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeTypedList(songs); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Artist.java b/app/src/main/java/code/name/monkey/retromusic/model/Artist.java new file mode 100644 index 00000000..08e41e4b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/Artist.java @@ -0,0 +1,110 @@ +package code.name.monkey.retromusic.model; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.util.MusicUtil; + + +public class Artist implements Parcelable { + public static final String UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist"; + public final ArrayList albums; + + public Artist(ArrayList albums) { + this.albums = albums; + } + + public Artist() { + this.albums = new ArrayList<>(); + } + + public int getId() { + return safeGetFirstAlbum().getArtistId(); + } + + public String getName() { + String name = safeGetFirstAlbum().getArtistName(); + if (MusicUtil.isArtistNameUnknown(name)) { + return UNKNOWN_ARTIST_DISPLAY_NAME; + } + return name; + } + + public int getSongCount() { + int songCount = 0; + for (Album album : albums) { + songCount += album.getSongCount(); + } + return songCount; + } + + public int getAlbumCount() { + return albums.size(); + } + + public ArrayList getSongs() { + ArrayList songs = new ArrayList<>(); + for (Album album : albums) { + songs.addAll(album.songs); + } + return songs; + } + + @NonNull + public Album safeGetFirstAlbum() { + return albums.isEmpty() ? new Album() : albums.get(0); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Artist artist = (Artist) o; + + return albums != null ? albums.equals(artist.albums) : artist.albums == null; + + } + + @Override + public int hashCode() { + return albums != null ? albums.hashCode() : 0; + } + + @Override + public String toString() { + return "Artist{" + + "albums=" + albums + + '}'; + } + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeTypedList(this.albums); + } + + protected Artist(Parcel in) { + this.albums = in.createTypedArrayList(Album.CREATOR); + } + + public static final Creator CREATOR = new Creator() { + @Override + public Artist createFromParcel(Parcel source) { + return new Artist(source); + } + + @Override + public Artist[] newArray(int size) { + return new Artist[size]; + } + }; +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.java b/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.java new file mode 100644 index 00000000..44287d37 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.java @@ -0,0 +1,56 @@ +package code.name.monkey.retromusic.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import code.name.monkey.retromusic.R; + + +public class CategoryInfo implements Parcelable { + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public CategoryInfo createFromParcel(Parcel source) { + return new CategoryInfo(source); + } + + public CategoryInfo[] newArray(int size) { + return new CategoryInfo[size]; + } + }; + public Category category; + public boolean visible; + + public CategoryInfo(Category category, boolean visible) { + this.category = category; + this.visible = visible; + } + + + private CategoryInfo(Parcel source) { + category = (Category) source.readSerializable(); + visible = source.readInt() == 1; + } + + @Override + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeSerializable(category); + dest.writeInt(visible ? 1 : 0); + } + + public enum Category { + SONGS(R.string.songs), + ALBUMS(R.string.albums), + ARTISTS(R.string.artists), + GENRES(R.string.genres), + PLAYLISTS(R.string.playlists); + + public final int stringRes; + + Category(int stringRes) { + this.stringRes = stringRes; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Genre.java b/app/src/main/java/code/name/monkey/retromusic/model/Genre.java new file mode 100644 index 00000000..9522536d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/Genre.java @@ -0,0 +1,86 @@ +package code.name.monkey.retromusic.model; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @author Hemanth S (h4h13). + */ + +public class Genre implements Parcelable { + + public static final Creator CREATOR = new Creator() { + @Override + public Genre createFromParcel(Parcel in) { + return new Genre(in); + } + + @Override + public Genre[] newArray(int size) { + return new Genre[size]; + } + }; + public final int id; + public final String name; + public final int songCount; + + public Genre(final int id, final String name, int songCount) { + this.id = id; + this.name = name; + this.songCount = songCount; + } + + + // For unknown genre + public Genre(final String name, final int songCount) { + this.id = -1; + this.name = name; + this.songCount = songCount; + } + + protected Genre(Parcel in) { + id = in.readInt(); + name = in.readString(); + songCount = in.readInt(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(id); + dest.writeString(name); + dest.writeInt(songCount); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Genre genre = (Genre) o; + + if (id != genre.id) return false; + return name != null ? name.equals(genre.name) : genre.name == null; + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + (name != null ? name.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Genre{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } + + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Home.java b/app/src/main/java/code/name/monkey/retromusic/model/Home.java new file mode 100755 index 00000000..0004c32d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/Home.java @@ -0,0 +1,50 @@ +package code.name.monkey.retromusic.model; + +import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist; + +import java.util.ArrayList; + + +/** + * Created by BlackFootSanji on 5/22/2017. + */ + +public class Home { + public String sectionTitle; + public ArrayList list; + public AbsSmartPlaylist playlist; + + public Home(String sectionTitle, AbsSmartPlaylist playlist) { + this.sectionTitle = sectionTitle; + this.playlist = playlist; + } + + public Home(String sectionTitle, ArrayList list) { + this.sectionTitle = sectionTitle; + this.list = list; + } + + public Home(AbsSmartPlaylist playlist) { + this.playlist = playlist; + } + + public AbsSmartPlaylist getPlaylist() { + return playlist; + } + + @Override + public String toString() { + return "Home{" + + "sectionTitle='" + sectionTitle + '\'' + + ", songs=" + list + + '}'; + } + + public String getSectionTitle() { + return sectionTitle; + } + + public ArrayList getList() { + return list; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Playlist.java b/app/src/main/java/code/name/monkey/retromusic/model/Playlist.java new file mode 100644 index 00000000..a04f3126 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/Playlist.java @@ -0,0 +1,72 @@ +package code.name.monkey.retromusic.model; + +import android.os.Parcel; +import android.os.Parcelable; + + +public class Playlist implements Parcelable { + public static final Creator CREATOR = new Creator() { + public Playlist createFromParcel(Parcel source) { + return new Playlist(source); + } + + public Playlist[] newArray(int size) { + return new Playlist[size]; + } + }; + public final int id; + public final String name; + + public Playlist(final int id, final String name) { + this.id = id; + this.name = name; + } + + public Playlist() { + this.id = -1; + this.name = ""; + } + + protected Playlist(Parcel in) { + this.id = in.readInt(); + this.name = in.readString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Playlist playlist = (Playlist) o; + + if (id != playlist.id) return false; + return name != null ? name.equals(playlist.name) : playlist.name == null; + + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + (name != null ? name.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Playlist{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(this.id); + dest.writeString(this.name); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/PlaylistSong.java b/app/src/main/java/code/name/monkey/retromusic/model/PlaylistSong.java new file mode 100644 index 00000000..80fecdff --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/PlaylistSong.java @@ -0,0 +1,76 @@ +package code.name.monkey.retromusic.model; + +import android.os.Parcel; +import android.os.Parcelable; + +public class PlaylistSong extends Song { + public static final PlaylistSong EMPTY_PLAYLIST_SONG = new PlaylistSong(-1, "", -1, -1, -1, "", -1, -1, "", -1, "", -1, -1); + + public final int playlistId; + public final int idInPlayList; + + public PlaylistSong(int id, String title, int trackNumber, int year, long duration, String data, int dateModified, int albumId, String albumName, int artistId, String artistName, final int playlistId, final int idInPlayList) { + super(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName); + this.playlistId = playlistId; + this.idInPlayList = idInPlayList; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + PlaylistSong that = (PlaylistSong) o; + + if (playlistId != that.playlistId) return false; + return idInPlayList == that.idInPlayList; + + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + playlistId; + result = 31 * result + idInPlayList; + return result; + } + + @Override + public String toString() { + return super.toString() + + "PlaylistSong{" + + "playlistId=" + playlistId + + ", idInPlayList=" + idInPlayList + + '}'; + } + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(this.playlistId); + dest.writeInt(this.idInPlayList); + } + + protected PlaylistSong(Parcel in) { + super(in); + this.playlistId = in.readInt(); + this.idInPlayList = in.readInt(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public PlaylistSong createFromParcel(Parcel source) { + return new PlaylistSong(source); + } + + public PlaylistSong[] newArray(int size) { + return new PlaylistSong[size]; + } + }; +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Song.java b/app/src/main/java/code/name/monkey/retromusic/model/Song.java new file mode 100644 index 00000000..ce7a63e1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/Song.java @@ -0,0 +1,135 @@ +package code.name.monkey.retromusic.model; + +import android.os.Parcel; +import android.os.Parcelable; + + +public class Song implements Parcelable { + public static final Song EMPTY_SONG = new Song(-1, "", -1, -1, -1, "", -1, -1, "", -1, ""); + + public final int id; + public final String title; + public final int trackNumber; + public final int year; + public final long duration; + public final String data; + public final long dateModified; + public final int albumId; + public final String albumName; + public final int artistId; + public final String artistName; + + public Song(int id, String title, int trackNumber, int year, long duration, String data, long dateModified, int albumId, String albumName, int artistId, String artistName) { + this.id = id; + this.title = title; + this.trackNumber = trackNumber; + this.year = year; + this.duration = duration; + this.data = data; + this.dateModified = dateModified; + this.albumId = albumId; + this.albumName = albumName; + this.artistId = artistId; + this.artistName = artistName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Song song = (Song) o; + + if (id != song.id) return false; + if (trackNumber != song.trackNumber) return false; + if (year != song.year) return false; + if (duration != song.duration) return false; + if (dateModified != song.dateModified) return false; + if (albumId != song.albumId) return false; + if (artistId != song.artistId) return false; + if (title != null ? !title.equals(song.title) : song.title != null) return false; + if (data != null ? !data.equals(song.data) : song.data != null) return false; + if (albumName != null ? !albumName.equals(song.albumName) : song.albumName != null) + return false; + return artistName != null ? artistName.equals(song.artistName) : song.artistName == null; + + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + (title != null ? title.hashCode() : 0); + result = 31 * result + trackNumber; + result = 31 * result + year; + result = 31 * result + (int) (duration ^ (duration >>> 32)); + result = 31 * result + (data != null ? data.hashCode() : 0); + result = 31 * result + (int) (dateModified ^ (dateModified >>> 32)); + result = 31 * result + albumId; + result = 31 * result + (albumName != null ? albumName.hashCode() : 0); + result = 31 * result + artistId; + result = 31 * result + (artistName != null ? artistName.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Song{" + + "id=" + id + + ", title='" + title + '\'' + + ", trackNumber=" + trackNumber + + ", year=" + year + + ", duration=" + duration + + ", data='" + data + '\'' + + ", dateModified=" + dateModified + + ", albumId=" + albumId + + ", albumName='" + albumName + '\'' + + ", artistId=" + artistId + + ", artistName='" + artistName + '\'' + + '}'; + } + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(this.id); + dest.writeString(this.title); + dest.writeInt(this.trackNumber); + dest.writeInt(this.year); + dest.writeLong(this.duration); + dest.writeString(this.data); + dest.writeLong(this.dateModified); + dest.writeInt(this.albumId); + dest.writeString(this.albumName); + dest.writeInt(this.artistId); + dest.writeString(this.artistName); + } + + protected Song(Parcel in) { + this.id = in.readInt(); + this.title = in.readString(); + this.trackNumber = in.readInt(); + this.year = in.readInt(); + this.duration = in.readLong(); + this.data = in.readString(); + this.dateModified = in.readLong(); + this.albumId = in.readInt(); + this.albumName = in.readString(); + this.artistId = in.readInt(); + this.artistName = in.readString(); + } + + public static final Creator CREATOR = new Creator() { + public Song createFromParcel(Parcel source) { + return new Song(source); + } + + public Song[] newArray(int size) { + return new Song[size]; + } + }; +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/lyrics/AbsSynchronizedLyrics.java b/app/src/main/java/code/name/monkey/retromusic/model/lyrics/AbsSynchronizedLyrics.java new file mode 100644 index 00000000..2ea13f5d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/lyrics/AbsSynchronizedLyrics.java @@ -0,0 +1,55 @@ +package code.name.monkey.retromusic.model.lyrics; + +import android.util.SparseArray; + +public abstract class AbsSynchronizedLyrics extends Lyrics { + private static final int TIME_OFFSET_MS = 500; // time adjustment to display line before it actually starts + + protected final SparseArray lines = new SparseArray<>(); + protected int offset = 0; + + public String getLine(int time) { + time += offset + AbsSynchronizedLyrics.TIME_OFFSET_MS; + + int lastLineTime = lines.keyAt(0); + + for (int i = 0; i < lines.size(); i++) { + int lineTime = lines.keyAt(i); + + if (time >= lineTime) { + lastLineTime = lineTime; + } else { + break; + } + } + + return lines.get(lastLineTime); + } + + public boolean isSynchronized() { + return true; + } + + public boolean isValid() { + parse(true); + return valid; + } + + @Override + public String getText() { + parse(false); + + if (valid) { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < lines.size(); i++) { + String line = lines.valueAt(i); + sb.append(line).append("\r\n"); + } + + return sb.toString().trim().replaceAll("(\r?\n){3,}", "\r\n\r\n"); + } + + return super.getText(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/lyrics/Lyrics.java b/app/src/main/java/code/name/monkey/retromusic/model/lyrics/Lyrics.java new file mode 100644 index 00000000..f80e5395 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/lyrics/Lyrics.java @@ -0,0 +1,70 @@ +package code.name.monkey.retromusic.model.lyrics; + + +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; + + +public class Lyrics { + private static final ArrayList> FORMATS = new ArrayList<>(); + + public Song song; + public String data; + + protected boolean parsed = false; + protected boolean valid = false; + + public Lyrics setData(Song song, String data) { + this.song = song; + this.data = data; + return this; + } + + public static Lyrics parse(Song song, String data) { + for (Class format : Lyrics.FORMATS) { + try { + Lyrics lyrics = format.newInstance().setData(song, data); + if (lyrics.isValid()) return lyrics.parse(false); + } catch (Exception e) { + e.printStackTrace(); + } + } + return new Lyrics().setData(song, data).parse(false); + } + + public static boolean isSynchronized(String data) { + for (Class format : Lyrics.FORMATS) { + try { + Lyrics lyrics = format.newInstance().setData(null, data); + if (lyrics.isValid()) return true; + } catch (Exception e) { + e.printStackTrace(); + } + } + return false; + } + + public Lyrics parse(boolean check) { + this.valid = true; + this.parsed = true; + return this; + } + + public boolean isSynchronized() { + return false; + } + + public boolean isValid() { + this.parse(true); + return this.valid; + } + + public String getText() { + return this.data.trim().replaceAll("(\r?\n){3,}", "\r\n\r\n"); + } + + static { + Lyrics.FORMATS.add(SynchronizedLyricsLRC.class); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/lyrics/SynchronizedLyricsLRC.java b/app/src/main/java/code/name/monkey/retromusic/model/lyrics/SynchronizedLyricsLRC.java new file mode 100644 index 00000000..f307ae89 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/lyrics/SynchronizedLyricsLRC.java @@ -0,0 +1,72 @@ +package code.name.monkey.retromusic.model.lyrics; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { + private static final Pattern LRC_LINE_PATTERN = Pattern.compile("((?:\\[.*?\\])+)(.*)"); + private static final Pattern LRC_TIME_PATTERN = Pattern.compile("\\[(\\d+):(\\d{2}(?:\\.\\d+)?)\\]"); + private static final Pattern LRC_ATTRIBUTE_PATTERN = Pattern.compile("\\[(\\D+):(.+)\\]"); + + private static final float LRC_SECONDS_TO_MS_MULTIPLIER = 1000f; + private static final int LRC_MINUTES_TO_MS_MULTIPLIER = 60000; + + @Override + public SynchronizedLyricsLRC parse(boolean check) { + if (this.parsed || this.data == null || this.data.isEmpty()) { + return this; + } + + String[] lines = this.data.split("\r?\n"); + + for (String line : lines) { + line = line.trim(); + if (line.isEmpty()) { + continue; + } + + Matcher attrMatcher = SynchronizedLyricsLRC.LRC_ATTRIBUTE_PATTERN.matcher(line); + if (attrMatcher.find()) { + try { + String attr = attrMatcher.group(1).toLowerCase().trim(); + String value = attrMatcher.group(2).toLowerCase().trim(); + switch (attr) { + case "offset": + this.offset = Integer.parseInt(value); + break; + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } else { + Matcher matcher = SynchronizedLyricsLRC.LRC_LINE_PATTERN.matcher(line); + if (matcher.find()) { + String time = matcher.group(1); + String text = matcher.group(2); + + Matcher timeMatcher = SynchronizedLyricsLRC.LRC_TIME_PATTERN.matcher(time); + while (timeMatcher.find()) { + int m = 0; + float s = 0f; + try { + m = Integer.parseInt(timeMatcher.group(1)); + s = Float.parseFloat(timeMatcher.group(2)); + } catch (NumberFormatException ex) { + ex.printStackTrace(); + } + int ms = (int) (s * LRC_SECONDS_TO_MS_MULTIPLIER) + m * LRC_MINUTES_TO_MS_MULTIPLIER; + + this.valid = true; + if (check) return this; + + this.lines.append(ms, text); + } + } + } + } + + this.parsed = true; + + return this; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/AbsSmartPlaylist.java b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/AbsSmartPlaylist.java new file mode 100644 index 00000000..c8019ad3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/AbsSmartPlaylist.java @@ -0,0 +1,63 @@ +package code.name.monkey.retromusic.model.smartplaylist; + +import android.content.Context; +import android.os.Parcel; +import android.support.annotation.DrawableRes; +import android.support.annotation.Nullable; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.AbsCustomPlaylist; + + +public abstract class AbsSmartPlaylist extends AbsCustomPlaylist { + @DrawableRes + public final int iconRes; + + public AbsSmartPlaylist(final String name, final int iconRes) { + super(-Math.abs(31 * name.hashCode() + (iconRes * name.hashCode() * 31 * 31)), name); + this.iconRes = iconRes; + } + + public AbsSmartPlaylist() { + super(); + this.iconRes = R.drawable.ic_playlist_play_white_24dp; + } + + protected AbsSmartPlaylist(Parcel in) { + super(in); + this.iconRes = in.readInt(); + } + + public abstract void clear(Context context); + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + iconRes; + return result; + } + + @Override + public boolean equals(@Nullable final Object obj) { + if (super.equals(obj)) { + if (getClass() != obj.getClass()) { + return false; + } + final AbsSmartPlaylist other = (AbsSmartPlaylist) obj; + return iconRes == other.iconRes; + } + return false; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(this.iconRes); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/HistoryPlaylist.java b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/HistoryPlaylist.java new file mode 100644 index 00000000..abec592d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/HistoryPlaylist.java @@ -0,0 +1,57 @@ +package code.name.monkey.retromusic.model.smartplaylist; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.loaders.TopAndRecentlyPlayedTracksLoader; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.providers.HistoryStore; +import io.reactivex.Observable; + + +public class HistoryPlaylist extends AbsSmartPlaylist { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public HistoryPlaylist createFromParcel(Parcel source) { + return new HistoryPlaylist(source); + } + + public HistoryPlaylist[] newArray(int size) { + return new HistoryPlaylist[size]; + } + }; + + public HistoryPlaylist(@NonNull Context context) { + super(context.getString(R.string.history), R.drawable.ic_access_time_white_24dp); + } + + protected HistoryPlaylist(Parcel in) { + super(in); + } + + @NonNull + @Override + public Observable> getSongs(@NonNull Context context) { + return TopAndRecentlyPlayedTracksLoader.getRecentlyPlayedTracks(context); + } + + @Override + public void clear(@NonNull Context context) { + HistoryStore.getInstance(context).clear(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/LastAddedPlaylist.java b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/LastAddedPlaylist.java new file mode 100644 index 00000000..3e726d63 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/LastAddedPlaylist.java @@ -0,0 +1,57 @@ +package code.name.monkey.retromusic.model.smartplaylist; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.loaders.LastAddedSongsLoader; +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; + +import io.reactivex.Observable; + + +public class LastAddedPlaylist extends AbsSmartPlaylist { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public LastAddedPlaylist createFromParcel(Parcel source) { + return new LastAddedPlaylist(source); + } + + public LastAddedPlaylist[] newArray(int size) { + return new LastAddedPlaylist[size]; + } + }; + + public LastAddedPlaylist(@NonNull Context context) { + super(context.getString(R.string.last_added), R.drawable.ic_library_add_white_24dp); + } + + protected LastAddedPlaylist(Parcel in) { + super(in); + } + + @NonNull + @Override + public Observable> getSongs(@NonNull Context context) { + return LastAddedSongsLoader.getLastAddedSongs(context); + } + + @Override + public void clear(@NonNull Context context) { + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/MyTopTracksPlaylist.java b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/MyTopTracksPlaylist.java new file mode 100644 index 00000000..2decf3f7 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/MyTopTracksPlaylist.java @@ -0,0 +1,59 @@ +package code.name.monkey.retromusic.model.smartplaylist; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.loaders.TopAndRecentlyPlayedTracksLoader; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.providers.SongPlayCountStore; + +import java.util.ArrayList; + +import io.reactivex.Observable; + + +public class MyTopTracksPlaylist extends AbsSmartPlaylist implements Parcelable { + public static final Creator CREATOR = new Creator() { + public MyTopTracksPlaylist createFromParcel(Parcel source) { + return new MyTopTracksPlaylist(source); + } + + public MyTopTracksPlaylist[] newArray(int size) { + return new MyTopTracksPlaylist[size]; + } + }; + + public MyTopTracksPlaylist(@NonNull Context context) { + super(context.getString(R.string.my_top_tracks), R.drawable.ic_trending_up_white_24dp); + } + + protected MyTopTracksPlaylist(Parcel in) { + super(in); + } + + @NonNull + @Override + public Observable> getSongs(@NonNull Context context) { + return TopAndRecentlyPlayedTracksLoader.getTopTracks(context); + } + + @Override + public void clear(@NonNull Context context) { + SongPlayCountStore.getInstance(context).clear(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/ShuffleAllPlaylist.java b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/ShuffleAllPlaylist.java new file mode 100644 index 00000000..fdada0c5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/ShuffleAllPlaylist.java @@ -0,0 +1,57 @@ +package code.name.monkey.retromusic.model.smartplaylist; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; + +import io.reactivex.Observable; + +public class ShuffleAllPlaylist extends AbsSmartPlaylist { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public ShuffleAllPlaylist createFromParcel(Parcel source) { + return new ShuffleAllPlaylist(source); + } + + public ShuffleAllPlaylist[] newArray(int size) { + return new ShuffleAllPlaylist[size]; + } + }; + + public ShuffleAllPlaylist(@NonNull Context context) { + super(context.getString(R.string.action_shuffle_all), R.drawable.ic_shuffle_white_24dp); + } + + protected ShuffleAllPlaylist(Parcel in) { + super(in); + } + + @NonNull + @Override + public Observable> getSongs(@NonNull Context context) { + return SongLoader.getAllSongs(context); + } + + @Override + public void clear(@NonNull Context context) { + // Shuffle all is not a real "Smart Playlist" + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/BasePresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/BasePresenter.java new file mode 100644 index 00000000..68a4e9f4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/BasePresenter.java @@ -0,0 +1,12 @@ +package code.name.monkey.retromusic.mvp; + +/** + * Created by hemanths on 09/08/17. + */ + +public interface BasePresenter { + + void subscribe(); + + void unsubscribe(); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/BaseView.java b/app/src/main/java/code/name/monkey/retromusic/mvp/BaseView.java new file mode 100644 index 00000000..70f08539 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/BaseView.java @@ -0,0 +1,15 @@ +package code.name.monkey.retromusic.mvp; + +/** + * Created by hemanths on 09/08/17. + */ + +public interface BaseView { + void loading(); + + void showData(T list); + + void showEmptyView(); + + void completed(); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/Presenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/Presenter.java new file mode 100644 index 00000000..73900b36 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/Presenter.java @@ -0,0 +1,27 @@ +package code.name.monkey.retromusic.mvp; + +import android.support.annotation.NonNull; + +import code.name.monkey.retromusic.Injection; +import code.name.monkey.retromusic.providers.interfaces.Repository; +import code.name.monkey.retromusic.util.schedulers.BaseSchedulerProvider; +import io.reactivex.disposables.CompositeDisposable; + +/** + * Created by hemanths on 16/08/17. + */ + +public class Presenter { + @NonNull + protected Repository repository; + @NonNull + protected CompositeDisposable disposable; + @NonNull + protected BaseSchedulerProvider schedulerProvider; + + public Presenter() { + this.repository = Injection.provideRepository(); + this.schedulerProvider = Injection.provideSchedulerProvider(); + this.disposable = new CompositeDisposable(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/AlbumContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/AlbumContract.java new file mode 100644 index 00000000..ae3a8838 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/AlbumContract.java @@ -0,0 +1,19 @@ +package code.name.monkey.retromusic.mvp.contract; + +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; +import java.util.ArrayList; + +public interface AlbumContract { + + interface AlbumView extends BaseView> { + + } + + interface Presenter extends BasePresenter { + + void loadAlbums(); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/AlbumDetailsContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/AlbumDetailsContract.java new file mode 100644 index 00000000..d22d5b0a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/AlbumDetailsContract.java @@ -0,0 +1,18 @@ +package code.name.monkey.retromusic.mvp.contract; + + +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; + +public interface AlbumDetailsContract { + + interface AlbumDetailsView extends BaseView { + + } + + interface Presenter extends BasePresenter { + + void loadAlbumSongs(int albumId); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/ArtistContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/ArtistContract.java new file mode 100644 index 00000000..b9d179c3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/ArtistContract.java @@ -0,0 +1,23 @@ +package code.name.monkey.retromusic.mvp.contract; + + +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; + +import java.util.ArrayList; + + +/** + * Created by hemanths on 16/08/17. + */ + +public interface ArtistContract { + interface ArtistView extends BaseView> { + + } + + interface Presenter extends BasePresenter { + void loadArtists(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/ArtistDetailContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/ArtistDetailContract.java new file mode 100644 index 00000000..2f8347b2 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/ArtistDetailContract.java @@ -0,0 +1,21 @@ +package code.name.monkey.retromusic.mvp.contract; + + +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; + + +/** + * Created by hemanths on 20/08/17. + */ + +public interface ArtistDetailContract { + interface ArtistsDetailsView extends BaseView { + + } + + interface Presenter extends BasePresenter { + void loadArtistById(int artistId); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/GenreContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/GenreContract.java new file mode 100644 index 00000000..d47d14f9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/GenreContract.java @@ -0,0 +1,21 @@ +package code.name.monkey.retromusic.mvp.contract; + +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; + +import java.util.ArrayList; + +/** + * @author Hemanth S (h4h13). + */ + +public interface GenreContract { + interface GenreView extends BaseView> { + + } + + interface Presenter extends BasePresenter { + void loadGenre(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/GenreDetailsContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/GenreDetailsContract.java new file mode 100644 index 00000000..7eeb5b6a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/GenreDetailsContract.java @@ -0,0 +1,20 @@ +package code.name.monkey.retromusic.mvp.contract; + +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; + +import java.util.ArrayList; + +/** + * @author Hemanth S (h4h13). + */ + +public interface GenreDetailsContract { + interface GenreDetailsView extends BaseView> { + } + + interface Presenter extends BasePresenter { + void loadGenre(int genreId); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/HomeContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/HomeContract.java new file mode 100644 index 00000000..892b0d57 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/HomeContract.java @@ -0,0 +1,44 @@ +package code.name.monkey.retromusic.mvp.contract; + +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist; +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; + +import java.util.ArrayList; + +public interface HomeContract { + + interface HomeView extends BaseView> { + + void recentArtist(ArrayList artists); + + void recentAlbum(ArrayList albums); + + void topArtists(ArrayList artists); + + void topAlbums(ArrayList albums); + + void suggestions(ArrayList songs); + + void geners(ArrayList songs); + } + + interface HomePresenter extends BasePresenter { + + void loadRecentAlbums(); + + void loadTopAlbums(); + + void loadRecentArtists(); + + void loadTopArtists(); + + void loadSuggestions(); + + void loadGenres(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/PlaylistContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/PlaylistContract.java new file mode 100644 index 00000000..7a40a5e5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/PlaylistContract.java @@ -0,0 +1,21 @@ +package code.name.monkey.retromusic.mvp.contract; + +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; + +import java.util.ArrayList; + +/** + * Created by hemanths on 19/08/17. + */ + +public interface PlaylistContract { + interface PlaylistView extends BaseView > { + + } + + interface Presenter extends BasePresenter { + void loadPlaylists(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/PlaylistSongsContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/PlaylistSongsContract.java new file mode 100644 index 00000000..48639a8f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/PlaylistSongsContract.java @@ -0,0 +1,23 @@ +package code.name.monkey.retromusic.mvp.contract; + +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; + +import java.util.ArrayList; + + +/** + * Created by hemanths on 20/08/17. + */ + +public interface PlaylistSongsContract { + interface PlaylistSongsView extends BaseView> { + + } + + interface Presenter extends BasePresenter { + void loadSongs(Playlist playlist); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/SearchContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/SearchContract.java new file mode 100644 index 00000000..2684894e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/SearchContract.java @@ -0,0 +1,21 @@ +package code.name.monkey.retromusic.mvp.contract; + +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; + +import java.util.ArrayList; + + +/** + * Created by hemanths on 20/08/17. + */ + +public interface SearchContract { + interface SearchView extends BaseView> { + + } + + interface SearchPresenter extends BasePresenter { + void search(String query); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/SongContract.java b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/SongContract.java new file mode 100644 index 00000000..2ec627e0 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/SongContract.java @@ -0,0 +1,24 @@ +package code.name.monkey.retromusic.mvp.contract; + + +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.mvp.BasePresenter; +import code.name.monkey.retromusic.mvp.BaseView; + +import java.util.ArrayList; + + +/** + * Created by hemanths on 10/08/17. + */ + +public interface SongContract { + + interface SongView extends BaseView> { + + } + + interface Presenter extends BasePresenter { + void loadSongs(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumDetailsPresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumDetailsPresenter.java new file mode 100644 index 00000000..053eef11 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumDetailsPresenter.java @@ -0,0 +1,54 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.AlbumDetailsContract; + + +/** + * Created by hemanths on 20/08/17. + */ + +public class AlbumDetailsPresenter extends Presenter implements AlbumDetailsContract.Presenter { + + @NonNull + private final int albumId; + @NonNull + private AlbumDetailsContract.AlbumDetailsView view; + + public AlbumDetailsPresenter(@NonNull AlbumDetailsContract.AlbumDetailsView view, int albumId) { + + this.view = view; + this.albumId = albumId; + } + + @Override + public void subscribe() { + loadAlbumSongs(albumId); + } + + @Override + public void unsubscribe() { + disposable.clear(); + } + + @Override + public void loadAlbumSongs(int albumId) { + disposable.add(repository.getAlbum(albumId) + .subscribeOn(schedulerProvider.computation()) + .observeOn(schedulerProvider.ui()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(this::showAlbum, + throwable -> view.showEmptyView(), + () -> view.completed())); + } + + private void showAlbum(Album album) { + if (album != null) { + view.showData(album); + } else { + view.showEmptyView(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumPresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumPresenter.java new file mode 100644 index 00000000..46bbc341 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumPresenter.java @@ -0,0 +1,49 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.AlbumContract; + + +/** + * Created by hemanths on 12/08/17. + */ + +public class AlbumPresenter extends Presenter implements AlbumContract.Presenter { + @NonNull + private AlbumContract.AlbumView view; + + + public AlbumPresenter(@NonNull AlbumContract.AlbumView view) { + this.view = view; + } + + @Override + public void subscribe() { + loadAlbums(); + } + + @Override + public void unsubscribe() { + disposable.clear(); + } + + private void showList(@NonNull ArrayList albums) { + view.showData(albums); + } + + @Override + public void loadAlbums() { + disposable.add(repository.getAllAlbums() + .subscribeOn(schedulerProvider.computation()) + .observeOn(schedulerProvider.ui()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(this::showList, + throwable -> view.showEmptyView(), + () -> view.completed())); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistDetailsPresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistDetailsPresenter.java new file mode 100644 index 00000000..22fcc390 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistDetailsPresenter.java @@ -0,0 +1,54 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; + +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.ArtistDetailContract; + + +/** + * Created by hemanths on 20/08/17. + */ + +public class ArtistDetailsPresenter extends Presenter implements ArtistDetailContract.Presenter { + + private final int artistId; + @NonNull + private final ArtistDetailContract.ArtistsDetailsView view; + + public ArtistDetailsPresenter(@NonNull ArtistDetailContract.ArtistsDetailsView view, + int artistId) { + this.view = view; + this.artistId = artistId; + } + + @Override + public void subscribe() { + loadArtistById(artistId); + } + + @Override + public void unsubscribe() { + disposable.clear(); + } + + @Override + public void loadArtistById(int artistId) { + disposable.add(repository.getArtistById(artistId) + .subscribeOn(schedulerProvider.computation()) + .observeOn(schedulerProvider.ui()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(this::showArtist, + throwable -> view.showEmptyView(), + () -> view.completed())); + } + + private void showArtist(Artist album) { + if (album != null) { + view.showData(album); + } else { + view.showEmptyView(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistPresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistPresenter.java new file mode 100644 index 00000000..613e201f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistPresenter.java @@ -0,0 +1,47 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.ArtistContract; + +public class ArtistPresenter extends Presenter implements ArtistContract.Presenter { + @NonNull + private ArtistContract.ArtistView mView; + + public ArtistPresenter(@NonNull ArtistContract.ArtistView view) { + mView = view; + } + + @Override + public void subscribe() { + loadArtists(); + } + + @Override + public void unsubscribe() { + disposable.clear(); + } + + private void showList(@NonNull ArrayList songs) { + if (songs.isEmpty()) { + mView.showEmptyView(); + } else { + mView.showData(songs); + } + } + + @Override + public void loadArtists() { + disposable.add(repository.getAllArtists() + .subscribeOn(schedulerProvider.computation()) + .observeOn(schedulerProvider.ui()) + .doOnSubscribe(disposable1 -> mView.loading()) + .subscribe(this::showList, + throwable -> mView.showEmptyView(), + () -> mView.completed())); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenreDetailsPresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenreDetailsPresenter.java new file mode 100644 index 00000000..0fd3e200 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenreDetailsPresenter.java @@ -0,0 +1,56 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.GenreDetailsContract; + + +/** + * Created by hemanths on 20/08/17. + */ + +public class GenreDetailsPresenter extends Presenter + implements GenreDetailsContract.Presenter { + private final int genreId; + @NonNull + private GenreDetailsContract.GenreDetailsView view; + + public GenreDetailsPresenter(@NonNull GenreDetailsContract.GenreDetailsView view, + int genreId) { + this.view = view; + this.genreId = genreId; + } + + @Override + public void subscribe() { + loadGenre(genreId); + } + + @Override + public void unsubscribe() { + disposable.clear(); + } + + @Override + public void loadGenre(int genreId) { + disposable.add(repository.getGenre(genreId) + .subscribeOn(schedulerProvider.computation()) + .observeOn(schedulerProvider.ui()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(this::showGenre, + throwable -> view.showEmptyView(), + () -> view.completed())); + } + + private void showGenre(ArrayList songs) { + if (songs != null) { + view.showData(songs); + } else { + view.showEmptyView(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenrePresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenrePresenter.java new file mode 100644 index 00000000..cd9d9fa2 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenrePresenter.java @@ -0,0 +1,53 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.GenreContract; + +/** + * @author Hemanth S (h4h13). + */ + +public class GenrePresenter extends Presenter + implements GenreContract.Presenter { + @NonNull + private GenreContract.GenreView view; + + public GenrePresenter( + @NonNull GenreContract.GenreView view) { + this.view = view; + } + + @Override + public void subscribe() { + loadGenre(); + } + + @Override + public void unsubscribe() { + disposable.clear(); + } + + @Override + public void loadGenre() { + disposable.add(repository.getAllGenres() + .subscribeOn(schedulerProvider.computation()) + .observeOn(schedulerProvider.ui()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(this::showList, + throwable -> view.showEmptyView(), + () -> view.completed())); + } + + private void showList(@NonNull ArrayList genres) { + if (genres.isEmpty()) { + view.showEmptyView(); + } else { + view.showData(genres); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/HomePresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/HomePresenter.java new file mode 100644 index 00000000..3511872d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/HomePresenter.java @@ -0,0 +1,128 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; + +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.HomeContract; +import code.name.monkey.retromusic.util.PreferenceUtil; + +public class HomePresenter extends Presenter implements HomeContract.HomePresenter { + + @NonNull + private HomeContract.HomeView view; + + public HomePresenter(@NonNull HomeContract.HomeView view) { + this.view = view; + } + + @Override + public void subscribe() { + + loadRecentAlbums(); + loadRecentArtists(); + + loadTopAlbums(); + loadTopArtists(); + + loadSuggestions(); + + if (PreferenceUtil.getInstance(RetroApplication.getInstance()).isGenreShown()) { + loadGenres(); + } + + } + + @Override + public void unsubscribe() { + disposable.clear(); + } + + public void loadPlaylists() { + disposable.add(repository.getAllPlaylists() + .observeOn(schedulerProvider.ui()) + .subscribeOn(schedulerProvider.io()) + .subscribe(playlists -> { + if (!playlists.isEmpty()) { + view.suggestions(playlists); + } + }, + throwable -> view.showEmptyView(), () -> view.completed())); + } + + @Override + public void loadRecentAlbums() { + disposable.add(repository.getRecentAlbums() + .observeOn(schedulerProvider.ui()) + .subscribeOn(schedulerProvider.io()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(artists -> { + if (!artists.isEmpty()) { + view.recentAlbum(artists); + } + }, + throwable -> view.showEmptyView(), () -> view.completed())); + } + + @Override + public void loadTopAlbums() { + disposable.add(repository.getTopAlbums() + .observeOn(schedulerProvider.ui()) + .subscribeOn(schedulerProvider.io()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(artists -> { + if (!artists.isEmpty()) { + view.topAlbums(artists); + } + }, + throwable -> view.showEmptyView(), () -> view.completed())); + } + + @Override + public void loadRecentArtists() { + disposable.add(repository.getRecentArtists() + .observeOn(schedulerProvider.ui()) + .subscribeOn(schedulerProvider.io()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(artists -> { + if (!artists.isEmpty()) { + view.recentArtist(artists); + } + }, + throwable -> view.showEmptyView(), () -> view.completed())); + } + + @Override + public void loadTopArtists() { + disposable.add(repository.getTopArtists() + .observeOn(schedulerProvider.ui()) + .subscribeOn(schedulerProvider.io()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(artists -> { + if (!artists.isEmpty()) { + view.topArtists(artists); + } + }, + throwable -> view.showEmptyView(), () -> view.completed())); + + } + + @Override + public void loadSuggestions() { + + } + + @Override + public void loadGenres() { + disposable.add(repository.getAllGenres() + .observeOn(schedulerProvider.ui()) + .subscribeOn(schedulerProvider.io()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(genres -> { + if (!genres.isEmpty()) { + view.geners(genres); + } + }, + throwable -> view.showEmptyView(), () -> view.completed())); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistPresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistPresenter.java new file mode 100644 index 00000000..744a055c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistPresenter.java @@ -0,0 +1,54 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.PlaylistContract; + + +/** + * Created by hemanths on 19/08/17. + */ + +public class PlaylistPresenter extends Presenter + implements PlaylistContract.Presenter { + @NonNull + private PlaylistContract.PlaylistView mView; + + public PlaylistPresenter(@NonNull PlaylistContract.PlaylistView view) { + + mView = view; + } + + @Override + public void subscribe() { + loadPlaylists(); + } + + @Override + public void unsubscribe() { + disposable.clear(); + } + + @Override + public void loadPlaylists() { + disposable.add(repository.getAllPlaylists() + .subscribeOn(schedulerProvider.computation()) + .observeOn(schedulerProvider.ui()) + .doOnSubscribe(disposable1 -> mView.loading()) + .subscribe(this::showList, + throwable -> mView.showEmptyView(), + () -> mView.completed())); + } + + private void showList(@NonNull ArrayList songs) { + if (songs.isEmpty()) { + mView.showEmptyView(); + } else { + mView.showData(songs); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistSongsPresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistSongsPresenter.java new file mode 100644 index 00000000..66b129df --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistSongsPresenter.java @@ -0,0 +1,48 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; + +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.PlaylistSongsContract; + +/** + * Created by hemanths on 20/08/17. + */ + +public class PlaylistSongsPresenter extends Presenter + implements PlaylistSongsContract.Presenter { + @NonNull + private PlaylistSongsContract.PlaylistSongsView mView; + @NonNull + private Playlist mPlaylist; + + public PlaylistSongsPresenter(@NonNull PlaylistSongsContract.PlaylistSongsView view, + @NonNull Playlist playlist) { + + mView = view; + mPlaylist = playlist; + } + + + @Override + public void subscribe() { + loadSongs(mPlaylist); + } + + @Override + public void unsubscribe() { + disposable.clear(); + } + + @Override + public void loadSongs(Playlist playlist) { + disposable.add(repository.getPlaylistSongs(playlist) + .subscribeOn(schedulerProvider.io()) + .observeOn(schedulerProvider.ui()) + .doOnSubscribe(disposable1 -> mView.loading()) + .subscribe(songs -> mView.showData(songs), + throwable -> mView.showEmptyView(), + () -> mView.completed())); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.java new file mode 100644 index 00000000..21c012ba --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.java @@ -0,0 +1,52 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.SearchContract; + +/** + * Created by hemanths on 20/08/17. + */ + +public class SearchPresenter extends Presenter implements SearchContract.SearchPresenter { + @NonNull + private SearchContract.SearchView mView; + + public SearchPresenter(@NonNull SearchContract.SearchView view) { + mView = view; + } + + @Override + public void subscribe() { + search(""); + } + + @Override + public void unsubscribe() { + disposable.clear(); + } + + private void showList(@NonNull ArrayList albums) { + if (albums.isEmpty()) { + mView.showEmptyView(); + } else { + mView.showData(albums); + } + } + + @Override + public void search(String query) { + disposable.add(repository.search(query) + .debounce(500, TimeUnit.MILLISECONDS) + .subscribeOn(schedulerProvider.computation()) + .observeOn(schedulerProvider.ui()) + .doOnSubscribe(disposable1 -> mView.loading()) + .subscribe(this::showList, + throwable -> mView.showEmptyView(), + () -> mView.completed())); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SongPresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SongPresenter.java new file mode 100644 index 00000000..d8098958 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SongPresenter.java @@ -0,0 +1,53 @@ +package code.name.monkey.retromusic.mvp.presenter; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.mvp.Presenter; +import code.name.monkey.retromusic.mvp.contract.SongContract; + +/** + * Created by hemanths on 10/08/17. + */ + +public class SongPresenter extends Presenter implements SongContract.Presenter { + + @NonNull + private SongContract.SongView view; + + + public SongPresenter(@NonNull SongContract.SongView view) { + this.view = view; + } + + @Override + public void loadSongs() { + disposable.add(repository.getAllSongs() + .subscribeOn(schedulerProvider.computation()) + .observeOn(schedulerProvider.ui()) + .doOnSubscribe(disposable1 -> view.loading()) + .subscribe(this::showList, + throwable -> view.showEmptyView(), + () -> view.completed())); + } + + @Override + public void subscribe() { + loadSongs(); + } + + private void showList(@NonNull ArrayList songs) { + if (songs.isEmpty()) { + view.showEmptyView(); + } else { + view.showData(songs); + } + } + + @Override + public void unsubscribe() { + disposable.clear(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreference.java b/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreference.java new file mode 100644 index 00000000..cc6e3e69 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreference.java @@ -0,0 +1,25 @@ +package code.name.monkey.retromusic.preferences; + +import android.content.Context; +import android.util.AttributeSet; + +import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEDialogPreference; + + +public class BlacklistPreference extends ATEDialogPreference { + public BlacklistPreference(Context context) { + super(context); + } + + public BlacklistPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public BlacklistPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public BlacklistPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.java b/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.java new file mode 100644 index 00000000..9f0a560a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.java @@ -0,0 +1,124 @@ +package code.name.monkey.retromusic.preferences; + +import android.app.Dialog; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.text.Html; +import android.view.View; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.BlacklistFolderChooserDialog; +import code.name.monkey.retromusic.providers.BlacklistStore; +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; +import java.io.File; +import java.util.ArrayList; + + +public class BlacklistPreferenceDialog extends DialogFragment implements + BlacklistFolderChooserDialog.FolderCallback { + + public static final String TAG = BlacklistPreferenceDialog.class.getSimpleName(); + + private ArrayList paths; + + public static BlacklistPreferenceDialog newInstance() { + return new BlacklistPreferenceDialog(); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + BlacklistFolderChooserDialog blacklistFolderChooserDialog = (BlacklistFolderChooserDialog) getChildFragmentManager() + .findFragmentByTag("FOLDER_CHOOSER"); + if (blacklistFolderChooserDialog != null) { + blacklistFolderChooserDialog.setCallback(this); + } + + refreshBlacklistData(); + return new MaterialDialog.Builder(getContext()) + .title(R.string.blacklist) + .positiveText(android.R.string.ok) + .neutralText(R.string.clear_action) + .negativeText(R.string.add_action) + .items(paths) + .autoDismiss(false) + .itemsCallback(new MaterialDialog.ListCallback() { + @Override + public void onSelection(MaterialDialog materialDialog, View view, int i, + final CharSequence charSequence) { + new MaterialDialog.Builder(getContext()) + .title(R.string.remove_from_blacklist) + .content(Html.fromHtml( + getString(R.string.do_you_want_to_remove_from_the_blacklist, charSequence))) + .positiveText(R.string.remove_action) + .negativeText(android.R.string.cancel) + .onPositive(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog materialDialog, + @NonNull DialogAction dialogAction) { + BlacklistStore.getInstance(getContext()) + .removePath(new File(charSequence.toString())); + refreshBlacklistData(); + } + }).show(); + } + }) + // clear + .onNeutral(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog materialDialog, + @NonNull DialogAction dialogAction) { + new MaterialDialog.Builder(getContext()) + .title(R.string.clear_blacklist) + .content(R.string.do_you_want_to_clear_the_blacklist) + .positiveText(R.string.clear_action) + .negativeText(android.R.string.cancel) + .onPositive(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog materialDialog, + @NonNull DialogAction dialogAction) { + BlacklistStore.getInstance(getContext()).clear(); + refreshBlacklistData(); + } + }).show(); + } + }) + // add + .onNegative(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog materialDialog, + @NonNull DialogAction dialogAction) { + BlacklistFolderChooserDialog dialog = BlacklistFolderChooserDialog.create(); + dialog.setCallback(BlacklistPreferenceDialog.this); + dialog.show(getChildFragmentManager(), "FOLDER_CHOOSER"); + } + }) + .onPositive(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog materialDialog, + @NonNull DialogAction dialogAction) { + dismiss(); + } + }) + .build(); + } + + private void refreshBlacklistData() { + paths = BlacklistStore.getInstance(getContext()).getPaths(); + + MaterialDialog dialog = (MaterialDialog) getDialog(); + if (dialog != null) { + String[] pathArray = new String[paths.size()]; + pathArray = paths.toArray(pathArray); + dialog.setItems((CharSequence[]) pathArray); + } + } + + @Override + public void onFolderSelection(@NonNull BlacklistFolderChooserDialog folderChooserDialog, + @NonNull File file) { + BlacklistStore.getInstance(getContext()).addPath(file); + refreshBlacklistData(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreference.java b/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreference.java new file mode 100644 index 00000000..a19e22f9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreference.java @@ -0,0 +1,25 @@ +package code.name.monkey.retromusic.preferences; + +import android.content.Context; +import android.util.AttributeSet; + +import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEDialogPreference; + + +public class NowPlayingScreenPreference extends ATEDialogPreference { + public NowPlayingScreenPreference(Context context) { + super(context); + } + + public NowPlayingScreenPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public NowPlayingScreenPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public NowPlayingScreenPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.java b/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.java new file mode 100644 index 00000000..253901f1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.java @@ -0,0 +1,165 @@ +package code.name.monkey.retromusic.preferences; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; +import com.bumptech.glide.Glide; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.ui.fragments.NowPlayingScreen; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.ViewUtil; + + +public class NowPlayingScreenPreferenceDialog extends DialogFragment implements + ViewPager.OnPageChangeListener, MaterialDialog.SingleButtonCallback { + public static final String TAG = NowPlayingScreenPreferenceDialog.class.getSimpleName(); + + private DialogAction whichButtonClicked; + private int viewPagerPosition; + + public static NowPlayingScreenPreferenceDialog newInstance() { + return new NowPlayingScreenPreferenceDialog(); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + @SuppressLint("InflateParams") View view = LayoutInflater.from(getActivity()) + .inflate(R.layout.preference_dialog_now_playing_screen, null); + ViewPager viewPager = view.findViewById(R.id.now_playing_screen_view_pager); + viewPager.setAdapter(new NowPlayingScreenAdapter(getActivity())); + viewPager.addOnPageChangeListener(this); + viewPager.setPageMargin((int) ViewUtil.convertDpToPixel(32, getResources())); + viewPager.setCurrentItem(PreferenceUtil.getInstance(getActivity()).getNowPlayingScreen().ordinal()); + + return new MaterialDialog.Builder(getActivity()) + .title(R.string.pref_title_now_playing_screen_appearance) + .positiveText(android.R.string.ok) + .negativeText(android.R.string.cancel) + .onAny(this) + .customView(view, false) + .build(); + } + + @Override + public void onClick(@NonNull MaterialDialog dialog, + @NonNull DialogAction which) { + whichButtonClicked = which; + } + + @SuppressWarnings("ConstantConditions") + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + if (whichButtonClicked == DialogAction.POSITIVE) { + NowPlayingScreen nowPlayingScreen = NowPlayingScreen.values()[viewPagerPosition]; + if (isNowPlayingThemes(nowPlayingScreen)) { + String result = getString(nowPlayingScreen.titleRes) + " theme is Pro version feature."; + Toast.makeText(getContext(), result, Toast.LENGTH_SHORT).show(); + NavigationUtil.goToProVersion(getActivity()); + } else { + PreferenceUtil.getInstance(getActivity()).setNowPlayingScreen(nowPlayingScreen); + } + } + } + + private boolean isNowPlayingThemes(NowPlayingScreen nowPlayingScreen) { + + if (nowPlayingScreen.equals(NowPlayingScreen.BLUR_CARD)) { + PreferenceUtil.getInstance(getContext()).resetCarouselEffect(); + PreferenceUtil.getInstance(getContext()).resetCircularAlbumArt(); + } + + return (nowPlayingScreen.equals(NowPlayingScreen.FULL) || + nowPlayingScreen.equals(NowPlayingScreen.CARD) || + nowPlayingScreen.equals(NowPlayingScreen.PLAIN) || + nowPlayingScreen.equals(NowPlayingScreen.BLUR) || + nowPlayingScreen.equals(NowPlayingScreen.COLOR) || + nowPlayingScreen.equals(NowPlayingScreen.SIMPLE) || + nowPlayingScreen.equals(NowPlayingScreen.TINY) || + nowPlayingScreen.equals(NowPlayingScreen.BLUR_CARD)|| + nowPlayingScreen.equals(NowPlayingScreen.ADAPTIVE)) + && !RetroApplication.isProVersion(); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + this.viewPagerPosition = position; + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + + private static class NowPlayingScreenAdapter extends PagerAdapter { + + private Context context; + + NowPlayingScreenAdapter(Context context) { + this.context = context; + } + + @NonNull + @Override + public Object instantiateItem(@NonNull ViewGroup collection, int position) { + NowPlayingScreen nowPlayingScreen = NowPlayingScreen.values()[position]; + + LayoutInflater inflater = LayoutInflater.from(context); + ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.preference_now_playing_screen_item, collection, false); + collection.addView(layout); + + ImageView image = layout.findViewById(R.id.image); + TextView title = layout.findViewById(R.id.title); + Glide.with(context).load(nowPlayingScreen.drawableResId).into(image); + title.setText(nowPlayingScreen.titleRes); + + return layout; + } + + @Override + public void destroyItem(@NonNull ViewGroup collection, + int position, + @NonNull Object view) { + collection.removeView((View) view); + } + + @Override + public int getCount() { + return NowPlayingScreen.values().length; + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { + return view == object; + } + + @Override + public CharSequence getPageTitle(int position) { + return context.getString(NowPlayingScreen.values()[position].titleRes); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/BlacklistStore.java b/app/src/main/java/code/name/monkey/retromusic/providers/BlacklistStore.java new file mode 100644 index 00000000..2382ff8a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/providers/BlacklistStore.java @@ -0,0 +1,155 @@ +package code.name.monkey.retromusic.providers; + +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.os.Environment; +import android.support.annotation.NonNull; + +import code.name.monkey.retromusic.Constants; +import code.name.monkey.retromusic.util.FileUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; + +import java.io.File; +import java.util.ArrayList; + +public class BlacklistStore extends SQLiteOpenHelper { + public static final String DATABASE_NAME = "blacklist.db"; + private static final int VERSION = 1; + private static BlacklistStore sInstance = null; + private Context context; + + public BlacklistStore(final Context context) { + super(context, DATABASE_NAME, null, VERSION); + this.context = context; + } + + @NonNull + public static synchronized BlacklistStore getInstance(@NonNull final Context context) { + if (sInstance == null) { + sInstance = new BlacklistStore(context.getApplicationContext()); + if (!PreferenceUtil.getInstance(context).initializedBlacklist()) { + // blacklisted by default + sInstance.addPathImpl(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS)); + sInstance.addPathImpl(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_NOTIFICATIONS)); + sInstance.addPathImpl(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES)); + + PreferenceUtil.getInstance(context).setInitializedBlacklist(); + } + } + return sInstance; + } + + @Override + public void onCreate(@NonNull final SQLiteDatabase db) { + db.execSQL("CREATE TABLE IF NOT EXISTS " + BlacklistStoreColumns.NAME + " (" + + BlacklistStoreColumns.PATH + " STRING NOT NULL);"); + } + + @Override + public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion, final int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + BlacklistStoreColumns.NAME); + onCreate(db); + } + + @Override + public void onDowngrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + BlacklistStoreColumns.NAME); + onCreate(db); + } + + public void addPath(File file) { + addPathImpl(file); + notifyMediaStoreChanged(); + } + + private void addPathImpl(File file) { + if (file == null || contains(file)) { + return; + } + String path = FileUtil.safeGetCanonicalPath(file); + + final SQLiteDatabase database = getWritableDatabase(); + database.beginTransaction(); + + try { + // add the entry + final ContentValues values = new ContentValues(1); + values.put(BlacklistStoreColumns.PATH, path); + database.insert(BlacklistStoreColumns.NAME, null, values); + + database.setTransactionSuccessful(); + } finally { + database.endTransaction(); + } + } + + public boolean contains(File file) { + if (file == null) { + return false; + } + String path = FileUtil.safeGetCanonicalPath(file); + + final SQLiteDatabase database = getReadableDatabase(); + Cursor cursor = database.query(BlacklistStoreColumns.NAME, + new String[]{BlacklistStoreColumns.PATH}, + BlacklistStoreColumns.PATH + "=?", + new String[]{path}, + null, null, null, null); + + boolean containsPath = cursor != null && cursor.moveToFirst(); + if (cursor != null) { + cursor.close(); + } + return containsPath; + } + + public void removePath(File file) { + final SQLiteDatabase database = getWritableDatabase(); + String path = FileUtil.safeGetCanonicalPath(file); + + database.delete(BlacklistStoreColumns.NAME, + BlacklistStoreColumns.PATH + "=?", + new String[]{path}); + + notifyMediaStoreChanged(); + } + + public void clear() { + final SQLiteDatabase database = getWritableDatabase(); + database.delete(BlacklistStoreColumns.NAME, null, null); + + notifyMediaStoreChanged(); + } + + private void notifyMediaStoreChanged() { + context.sendBroadcast(new Intent(Constants.MEDIA_STORE_CHANGED)); + } + + @NonNull + public ArrayList getPaths() { + Cursor cursor = getReadableDatabase().query(BlacklistStoreColumns.NAME, + new String[]{BlacklistStoreColumns.PATH}, + null, null, null, null, null); + + ArrayList paths = new ArrayList<>(); + if (cursor != null && cursor.moveToFirst()) { + do { + paths.add(cursor.getString(0)); + } while (cursor.moveToNext()); + } + + if (cursor != null) + cursor.close(); + return paths; + } + + public interface BlacklistStoreColumns { + String NAME = "blacklist"; + + String PATH = "path"; + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/HistoryStore.java b/app/src/main/java/code/name/monkey/retromusic/providers/HistoryStore.java new file mode 100644 index 00000000..dfb4c511 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/providers/HistoryStore.java @@ -0,0 +1,152 @@ +/* +* Copyright (C) 2014 The CyanogenMod Project +* +* 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 +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* 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 code.name.monkey.retromusic.providers; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +public class HistoryStore extends SQLiteOpenHelper { + public static final String DATABASE_NAME = "history.db"; + private static final int MAX_ITEMS_IN_DB = 100; + private static final int VERSION = 1; + @Nullable + private static HistoryStore sInstance = null; + + public HistoryStore(final Context context) { + super(context, DATABASE_NAME, null, VERSION); + } + + @NonNull + public static synchronized HistoryStore getInstance(@NonNull final Context context) { + if (sInstance == null) { + sInstance = new HistoryStore(context.getApplicationContext()); + } + return sInstance; + } + + @Override + public void onCreate(@NonNull final SQLiteDatabase db) { + db.execSQL("CREATE TABLE IF NOT EXISTS " + RecentStoreColumns.NAME + " (" + + RecentStoreColumns.ID + " LONG NOT NULL," + RecentStoreColumns.TIME_PLAYED + + " LONG NOT NULL);"); + } + + @Override + public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + RecentStoreColumns.NAME); + onCreate(db); + } + + @Override + public void onDowngrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + RecentStoreColumns.NAME); + onCreate(db); + } + + public void addSongId(final long songId) { + if (songId == -1) { + return; + } + + final SQLiteDatabase database = getWritableDatabase(); + database.beginTransaction(); + + try { + // remove previous entries + removeSongId(songId); + + // add the entry + final ContentValues values = new ContentValues(2); + values.put(RecentStoreColumns.ID, songId); + values.put(RecentStoreColumns.TIME_PLAYED, System.currentTimeMillis()); + database.insert(RecentStoreColumns.NAME, null, values); + + // if our db is too large, delete the extra items + Cursor oldest = null; + try { + oldest = database.query(RecentStoreColumns.NAME, + new String[]{RecentStoreColumns.TIME_PLAYED}, null, null, null, null, + RecentStoreColumns.TIME_PLAYED + " ASC"); + + if (oldest != null && oldest.getCount() > MAX_ITEMS_IN_DB) { + oldest.moveToPosition(oldest.getCount() - MAX_ITEMS_IN_DB); + long timeOfRecordToKeep = oldest.getLong(0); + + database.delete(RecentStoreColumns.NAME, + RecentStoreColumns.TIME_PLAYED + " < ?", + new String[]{String.valueOf(timeOfRecordToKeep)}); + + } + } finally { + if (oldest != null) { + oldest.close(); + } + } + } finally { + database.setTransactionSuccessful(); + database.endTransaction(); + } + } + + public void removeSongId(final long songId) { + final SQLiteDatabase database = getWritableDatabase(); + database.delete(RecentStoreColumns.NAME, RecentStoreColumns.ID + " = ?", new String[]{ + String.valueOf(songId) + }); + + } + + public void clear() { + final SQLiteDatabase database = getWritableDatabase(); + database.delete(RecentStoreColumns.NAME, null, null); + } + + public boolean contains(long id) { + final SQLiteDatabase database = getReadableDatabase(); + Cursor cursor = database.query(RecentStoreColumns.NAME, + new String[]{RecentStoreColumns.ID}, + RecentStoreColumns.ID + "=?", + new String[]{String.valueOf(id)}, + null, null, null, null); + + boolean containsId = cursor != null && cursor.moveToFirst(); + if (cursor != null) { + cursor.close(); + } + return containsId; + } + + public Cursor queryRecentIds() { + final SQLiteDatabase database = getReadableDatabase(); + return database.query(RecentStoreColumns.NAME, + new String[]{RecentStoreColumns.ID}, null, null, null, null, + RecentStoreColumns.TIME_PLAYED + " DESC"); + } + + public interface RecentStoreColumns { + String NAME = "recent_history"; + + String ID = "song_id"; + + String TIME_PLAYED = "time_played"; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/MusicPlaybackQueueStore.java b/app/src/main/java/code/name/monkey/retromusic/providers/MusicPlaybackQueueStore.java new file mode 100644 index 00000000..86704afd --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/providers/MusicPlaybackQueueStore.java @@ -0,0 +1,203 @@ +/* +* Copyright (C) 2014 The CyanogenMod Project +* +* 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 +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* 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 code.name.monkey.retromusic.providers; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.provider.BaseColumns; +import android.provider.MediaStore.Audio.AudioColumns; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; + +import io.reactivex.Observable; + +/** + * @author Andrew Neal, modified for Phonograph by Karim Abou Zeid + *

    + * This keeps track of the music playback and history state of the playback service + */ +public class MusicPlaybackQueueStore extends SQLiteOpenHelper { + public static final String DATABASE_NAME = "music_playback_state.db"; + public static final String PLAYING_QUEUE_TABLE_NAME = "playing_queue"; + public static final String ORIGINAL_PLAYING_QUEUE_TABLE_NAME = "original_playing_queue"; + private static final int VERSION = 3; + @Nullable + private static MusicPlaybackQueueStore sInstance = null; + + /** + * Constructor of MusicPlaybackState + * + * @param context The {@link Context} to use + */ + public MusicPlaybackQueueStore(final Context context) { + super(context, DATABASE_NAME, null, VERSION); + } + + /** + * @param context The {@link Context} to use + * @return A new instance of this class. + */ + @NonNull + public static synchronized MusicPlaybackQueueStore getInstance(@NonNull final Context context) { + if (sInstance == null) { + sInstance = new MusicPlaybackQueueStore(context.getApplicationContext()); + } + return sInstance; + } + + @Override + public void onCreate(@NonNull final SQLiteDatabase db) { + createTable(db, PLAYING_QUEUE_TABLE_NAME); + createTable(db, ORIGINAL_PLAYING_QUEUE_TABLE_NAME); + } + + private void createTable(@NonNull final SQLiteDatabase db, final String tableName) { + //noinspection StringBufferReplaceableByString + StringBuilder builder = new StringBuilder(); + builder.append("CREATE TABLE IF NOT EXISTS "); + builder.append(tableName); + builder.append("("); + + builder.append(BaseColumns._ID); + builder.append(" INT NOT NULL,"); + + builder.append(AudioColumns.TITLE); + builder.append(" STRING NOT NULL,"); + + builder.append(AudioColumns.TRACK); + builder.append(" INT NOT NULL,"); + + builder.append(AudioColumns.YEAR); + builder.append(" INT NOT NULL,"); + + builder.append(AudioColumns.DURATION); + builder.append(" LONG NOT NULL,"); + + builder.append(AudioColumns.DATA); + builder.append(" STRING NOT NULL,"); + + builder.append(AudioColumns.DATE_MODIFIED); + builder.append(" LONG NOT NULL,"); + + builder.append(AudioColumns.ALBUM_ID); + builder.append(" INT NOT NULL,"); + + builder.append(AudioColumns.ALBUM); + builder.append(" STRING NOT NULL,"); + + builder.append(AudioColumns.ARTIST_ID); + builder.append(" INT NOT NULL,"); + + builder.append(AudioColumns.ARTIST); + builder.append(" STRING NOT NULL);"); + + db.execSQL(builder.toString()); + } + + @Override + public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion, final int newVersion) { + // not necessary yet + db.execSQL("DROP TABLE IF EXISTS " + PLAYING_QUEUE_TABLE_NAME); + db.execSQL("DROP TABLE IF EXISTS " + ORIGINAL_PLAYING_QUEUE_TABLE_NAME); + onCreate(db); + } + + @Override + public void onDowngrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) { + // If we ever have downgrade, drop the table to be safe + db.execSQL("DROP TABLE IF EXISTS " + PLAYING_QUEUE_TABLE_NAME); + db.execSQL("DROP TABLE IF EXISTS " + ORIGINAL_PLAYING_QUEUE_TABLE_NAME); + onCreate(db); + } + + public synchronized void saveQueues(@NonNull final ArrayList playingQueue, @NonNull final ArrayList originalPlayingQueue) { + saveQueue(PLAYING_QUEUE_TABLE_NAME, playingQueue); + saveQueue(ORIGINAL_PLAYING_QUEUE_TABLE_NAME, originalPlayingQueue); + } + + /** + * Clears the existing database and saves the queue into the db so that when the + * app is restarted, the tracks you were listening to is restored + * + * @param queue the queue to save + */ + private synchronized void saveQueue(final String tableName, @NonNull final ArrayList queue) { + final SQLiteDatabase database = getWritableDatabase(); + database.beginTransaction(); + + try { + database.delete(tableName, null, null); + database.setTransactionSuccessful(); + } finally { + database.endTransaction(); + } + + final int NUM_PROCESS = 20; + int position = 0; + while (position < queue.size()) { + database.beginTransaction(); + try { + for (int i = position; i < queue.size() && i < position + NUM_PROCESS; i++) { + Song song = queue.get(i); + ContentValues values = new ContentValues(4); + + values.put(BaseColumns._ID, song.id); + values.put(AudioColumns.TITLE, song.title); + values.put(AudioColumns.TRACK, song.trackNumber); + values.put(AudioColumns.YEAR, song.year); + values.put(AudioColumns.DURATION, song.duration); + values.put(AudioColumns.DATA, song.data); + values.put(AudioColumns.DATE_MODIFIED, song.dateModified); + values.put(AudioColumns.ALBUM_ID, song.albumId); + values.put(AudioColumns.ALBUM, song.albumName); + values.put(AudioColumns.ARTIST_ID, song.artistId); + values.put(AudioColumns.ARTIST, song.artistName); + + database.insert(tableName, null, values); + } + database.setTransactionSuccessful(); + } finally { + database.endTransaction(); + position += NUM_PROCESS; + } + } + } + + @NonNull + public Observable> getSavedPlayingQueue() { + return getQueue(PLAYING_QUEUE_TABLE_NAME); + } + + @NonNull + public Observable> getSavedOriginalPlayingQueue() { + return getQueue(ORIGINAL_PLAYING_QUEUE_TABLE_NAME); + } + + @NonNull + private Observable> getQueue(@NonNull final String tableName) { + Cursor cursor = getReadableDatabase().query(tableName, null, + null, null, null, null, null); + return SongLoader.getSongs(cursor); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.java b/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.java new file mode 100644 index 00000000..1baa7247 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.java @@ -0,0 +1,169 @@ +package code.name.monkey.retromusic.providers; + +import android.content.Context; + +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist; +import java.io.File; +import java.util.ArrayList; + +import code.name.monkey.retromusic.Injection; +import code.name.monkey.retromusic.loaders.AlbumLoader; +import code.name.monkey.retromusic.loaders.ArtistLoader; +import code.name.monkey.retromusic.loaders.GenreLoader; +import code.name.monkey.retromusic.loaders.HomeLoader; +import code.name.monkey.retromusic.loaders.LastAddedSongsLoader; +import code.name.monkey.retromusic.loaders.PlaylistLoader; +import code.name.monkey.retromusic.loaders.PlaylistSongsLoader; +import code.name.monkey.retromusic.loaders.SearchLoader; +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.loaders.TopAndRecentlyPlayedTracksLoader; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.providers.interfaces.Repository; +import code.name.monkey.retromusic.rest.model.KuGouRawLyric; +import code.name.monkey.retromusic.rest.model.KuGouSearchLyricResult; +import code.name.monkey.retromusic.rest.service.KuGouApiService; +import code.name.monkey.retromusic.util.LyricUtil; +import io.reactivex.Observable; +import io.reactivex.schedulers.Schedulers; + +public class RepositoryImpl implements Repository { + private static RepositoryImpl INSTANCE; + private Context context; + + public RepositoryImpl(Context context) { + this.context = context; + } + + public static synchronized RepositoryImpl getInstance( ) { + if (INSTANCE == null) { + INSTANCE = new RepositoryImpl(RetroApplication.getInstance()); + } + return INSTANCE; + } + + @Override + public Observable> getAllSongs() { + return SongLoader.getAllSongs(context); + } + + @Override + public Observable> getSuggestionSongs() { + return HomeLoader.getRecentAndTopThings(context); + } + + @Override + public Observable getSong(int id) { + return SongLoader.getSong(context, id); + } + + @Override + public Observable> getAllAlbums() { + return AlbumLoader.getAllAlbums(context); + } + + @Override + public Observable> getRecentAlbums() { + return LastAddedSongsLoader.getLastAddedAlbums(context); + } + + @Override + public Observable> getTopAlbums() { + return TopAndRecentlyPlayedTracksLoader.getTopAlbums(context); + } + + @Override + public Observable getAlbum(int albumId) { + return AlbumLoader.getAlbum(context, albumId); + } + + @Override + public Observable> getAllArtists() { + return ArtistLoader.getAllArtists(context); + } + + @Override + public Observable> getRecentArtists() { + return LastAddedSongsLoader.getLastAddedArtists(context); + } + + @Override + public Observable> getTopArtists() { + return TopAndRecentlyPlayedTracksLoader.getTopArtists(context); + } + + @Override + public Observable getArtistById(long artistId) { + return ArtistLoader.getArtist(context, (int) artistId); + } + + @Override + public Observable> getAllPlaylists() { + return PlaylistLoader.getAllPlaylists(context); + } + + @Override + public Observable> getFavoriteSongs() { + return null; + } + + @Override + public Observable> search(String query) { + return SearchLoader.searchAll(context, query); + } + + @Override + public Observable> getPlaylistSongs(Playlist playlist) { + return PlaylistSongsLoader.getPlaylistSongList(context, playlist); + } + + @Override + public Observable> getHomeList() { + return HomeLoader.getHomeLoader(context); + } + + @Override + public Observable> getAllThings() { + return HomeLoader.getRecentAndTopThings(context); + } + + @Override + public Observable> getAllGenres() { + return GenreLoader.getAllGenres(context); + } + + @Override + public Observable> getGenre(int genreId) { + return GenreLoader.getSongs(context, genreId); + } + + @Override + public Observable downloadLrcFile(String title, String artist, long duration) { + KuGouApiService service = Injection.provideKuGouApiService(); + return service.searchLyric(title, String.valueOf(duration)) + .subscribeOn(Schedulers.io()) + .flatMap(kuGouSearchLyricResult -> { + if (kuGouSearchLyricResult.status == 200 + && kuGouSearchLyricResult.candidates != null + && kuGouSearchLyricResult.candidates.size() != 0) { + KuGouSearchLyricResult.Candidates candidates = kuGouSearchLyricResult.candidates.get(0); + return service.getRawLyric(candidates.id, candidates.accesskey); + } else { + return Observable.just(new KuGouRawLyric()); + } + }).map(kuGouRawLyric -> { + if (kuGouRawLyric == null) { + return null; + } + String rawLyric = LyricUtil.decryptBASE64(kuGouRawLyric.content); + if (rawLyric != null && rawLyric.isEmpty()) { + return null; + } + return LyricUtil.writeLrcToLoc(title, artist, rawLyric); + }); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/SongPlayCountStore.java b/app/src/main/java/code/name/monkey/retromusic/providers/SongPlayCountStore.java new file mode 100644 index 00000000..99f22e65 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/providers/SongPlayCountStore.java @@ -0,0 +1,404 @@ +/* +* Copyright (C) 2014 The CyanogenMod Project +* +* 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 +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* 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 code.name.monkey.retromusic.providers; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.Interpolator; + +/** + * This database tracks the number of play counts for an individual song. This is used to drive + * the top played tracks as well as the playlist images + */ +public class SongPlayCountStore extends SQLiteOpenHelper { + public static final String DATABASE_NAME = "song_play_count.db"; + private static final int VERSION = 2; + // how many weeks worth of playback to track + private static final int NUM_WEEKS = 52; + @Nullable + private static SongPlayCountStore sInstance = null; + // interpolator curve applied for measuring the curve + @NonNull + private static Interpolator sInterpolator = new AccelerateInterpolator(1.5f); + // how high to multiply the interpolation curve + @SuppressWarnings("FieldCanBeLocal") + private static int INTERPOLATOR_HEIGHT = 50; + + // how high the base value is. The ratio of the Height to Base is what really matters + @SuppressWarnings("FieldCanBeLocal") + private static int INTERPOLATOR_BASE = 25; + + @SuppressWarnings("FieldCanBeLocal") + private static int ONE_WEEK_IN_MS = 1000 * 60 * 60 * 24 * 7; + + @NonNull + private static String WHERE_ID_EQUALS = SongPlayCountColumns.ID + "=?"; + + // number of weeks since epoch time + private int mNumberOfWeeksSinceEpoch; + + // used to track if we've walked through the db and updated all the rows + private boolean mDatabaseUpdated; + + public SongPlayCountStore(final Context context) { + super(context, DATABASE_NAME, null, VERSION); + + long msSinceEpoch = System.currentTimeMillis(); + mNumberOfWeeksSinceEpoch = (int) (msSinceEpoch / ONE_WEEK_IN_MS); + + mDatabaseUpdated = false; + } + + /** + * @param context The {@link Context} to use + * @return A new instance of this class. + */ + @NonNull + public static synchronized SongPlayCountStore getInstance(@NonNull final Context context) { + if (sInstance == null) { + sInstance = new SongPlayCountStore(context.getApplicationContext()); + } + return sInstance; + } + + /** + * Calculates the score of the song given the play counts + * + * @param playCounts an array of the # of times a song has been played for each week + * where playCounts[N] is the # of times it was played N weeks ago + * @return the score + */ + private static float calculateScore(@Nullable final int[] playCounts) { + if (playCounts == null) { + return 0; + } + + float score = 0; + for (int i = 0; i < Math.min(playCounts.length, NUM_WEEKS); i++) { + score += playCounts[i] * getScoreMultiplierForWeek(i); + } + + return score; + } + + /** + * Gets the column name for each week # + * + * @param week number + * @return the column name + */ + @NonNull + private static String getColumnNameForWeek(final int week) { + return SongPlayCountColumns.WEEK_PLAY_COUNT + String.valueOf(week); + } + + /** + * Gets the score multiplier for each week + * + * @param week number + * @return the multiplier to apply + */ + private static float getScoreMultiplierForWeek(final int week) { + return sInterpolator.getInterpolation(1 - (week / (float) NUM_WEEKS)) * INTERPOLATOR_HEIGHT + + INTERPOLATOR_BASE; + } + + /** + * For some performance gain, return a static value for the column index for a week + * WARNING: This function assumes you have selected all columns for it to work + * + * @param week number + * @return column index of that week + */ + private static int getColumnIndexForWeek(final int week) { + // ID, followed by the weeks columns + return 1 + week; + } + + @Override + public void onCreate(@NonNull final SQLiteDatabase db) { + // create the play count table + // WARNING: If you change the order of these columns + // please update getColumnIndexForWeek + StringBuilder builder = new StringBuilder(); + builder.append("CREATE TABLE IF NOT EXISTS "); + builder.append(SongPlayCountColumns.NAME); + builder.append("("); + builder.append(SongPlayCountColumns.ID); + builder.append(" INT UNIQUE,"); + + for (int i = 0; i < NUM_WEEKS; i++) { + builder.append(getColumnNameForWeek(i)); + builder.append(" INT DEFAULT 0,"); + } + + builder.append(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX); + builder.append(" INT NOT NULL,"); + + builder.append(SongPlayCountColumns.PLAY_COUNT_SCORE); + builder.append(" REAL DEFAULT 0);"); + + db.execSQL(builder.toString()); + } + + @Override + public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion, final int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + SongPlayCountColumns.NAME); + onCreate(db); + } + + @Override + public void onDowngrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) { + // If we ever have downgrade, drop the table to be safe + db.execSQL("DROP TABLE IF EXISTS " + SongPlayCountColumns.NAME); + onCreate(db); + } + + /** + * Increases the play count of a song by 1 + * + * @param songId The song id to increase the play count + */ + public void bumpPlayCount(final long songId) { + if (songId == -1) { + return; + } + + final SQLiteDatabase database = getWritableDatabase(); + updateExistingRow(database, songId, true); + } + + /** + * This creates a new entry that indicates a song has been played once as well as its score + * + * @param database a write able database + * @param songId the id of the track + */ + private void createNewPlayedEntry(@NonNull final SQLiteDatabase database, final long songId) { + // no row exists, create a new one + float newScore = getScoreMultiplierForWeek(0); + int newPlayCount = 1; + + final ContentValues values = new ContentValues(3); + values.put(SongPlayCountColumns.ID, songId); + values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, newScore); + values.put(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX, mNumberOfWeeksSinceEpoch); + values.put(getColumnNameForWeek(0), newPlayCount); + + database.insert(SongPlayCountColumns.NAME, null, values); + } + + /** + * This function will take a song entry and update it to the latest week and increase the count + * for the current week by 1 if necessary + * + * @param database a writeable database + * @param id the id of the track to bump + * @param bumpCount whether to bump the current's week play count by 1 and adjust the score + */ + private void updateExistingRow(@NonNull final SQLiteDatabase database, final long id, boolean bumpCount) { + String stringId = String.valueOf(id); + + // begin the transaction + database.beginTransaction(); + + // get the cursor of this content inside the transaction + final Cursor cursor = database.query(SongPlayCountColumns.NAME, null, WHERE_ID_EQUALS, + new String[]{stringId}, null, null, null); + + // if we have a result + if (cursor != null && cursor.moveToFirst()) { + // figure how many weeks since we last updated + int lastUpdatedIndex = cursor.getColumnIndex(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX); + int lastUpdatedWeek = cursor.getInt(lastUpdatedIndex); + int weekDiff = mNumberOfWeeksSinceEpoch - lastUpdatedWeek; + + // if it's more than the number of weeks we track, delete it and create a new entry + if (Math.abs(weekDiff) >= NUM_WEEKS) { + // this entry needs to be dropped since it is too outdated + deleteEntry(database, stringId); + if (bumpCount) { + createNewPlayedEntry(database, id); + } + } else if (weekDiff != 0) { + // else, shift the weeks + int[] playCounts = new int[NUM_WEEKS]; + + if (weekDiff > 0) { + // time is shifted forwards + for (int i = 0; i < NUM_WEEKS - weekDiff; i++) { + playCounts[i + weekDiff] = cursor.getInt(getColumnIndexForWeek(i)); + } + } else if (weekDiff < 0) { + // time is shifted backwards (by user) - nor typical behavior but we + // will still handle it + + // since weekDiff is -ve, NUM_WEEKS + weekDiff is the real # of weeks we have to + // transfer. Then we transfer the old week i - weekDiff to week i + // for example if the user shifted back 2 weeks, ie -2, then for 0 to + // NUM_WEEKS + (-2) we set the new week i = old week i - (-2) or i+2 + for (int i = 0; i < NUM_WEEKS + weekDiff; i++) { + playCounts[i] = cursor.getInt(getColumnIndexForWeek(i - weekDiff)); + } + } + + // bump the count + if (bumpCount) { + playCounts[0]++; + } + + float score = calculateScore(playCounts); + + // if the score is non-existant, then delete it + if (score < .01f) { + deleteEntry(database, stringId); + } else { + // create the content values + ContentValues values = new ContentValues(NUM_WEEKS + 2); + values.put(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX, mNumberOfWeeksSinceEpoch); + values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, score); + + for (int i = 0; i < NUM_WEEKS; i++) { + values.put(getColumnNameForWeek(i), playCounts[i]); + } + + // update the entry + database.update(SongPlayCountColumns.NAME, values, WHERE_ID_EQUALS, + new String[]{stringId}); + } + } else if (bumpCount) { + // else no shifting, just update the scores + ContentValues values = new ContentValues(2); + + // increase the score by a single score amount + int scoreIndex = cursor.getColumnIndex(SongPlayCountColumns.PLAY_COUNT_SCORE); + float score = cursor.getFloat(scoreIndex) + getScoreMultiplierForWeek(0); + values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, score); + + // increase the play count by 1 + values.put(getColumnNameForWeek(0), cursor.getInt(getColumnIndexForWeek(0)) + 1); + + // update the entry + database.update(SongPlayCountColumns.NAME, values, WHERE_ID_EQUALS, + new String[]{stringId}); + } + + cursor.close(); + } else if (bumpCount) { + // if we have no existing results, create a new one + createNewPlayedEntry(database, id); + } + + database.setTransactionSuccessful(); + database.endTransaction(); + } + + public void clear() { + final SQLiteDatabase database = getWritableDatabase(); + database.delete(SongPlayCountColumns.NAME, null, null); + } + + /** + * Gets a cursor containing the top songs played. Note this only returns songs that have been + * played at least once in the past NUM_WEEKS + * + * @param numResults number of results to limit by. If <= 0 it returns all results + * @return the top tracks + */ + public Cursor getTopPlayedResults(int numResults) { + updateResults(); + + final SQLiteDatabase database = getReadableDatabase(); + return database.query(SongPlayCountColumns.NAME, new String[]{SongPlayCountColumns.ID}, + null, null, null, null, SongPlayCountColumns.PLAY_COUNT_SCORE + " DESC", + (numResults <= 0 ? null : String.valueOf(numResults))); + } + + /** + * This updates all the results for the getTopPlayedResults so that we can get an + * accurate list of the top played results + */ + private synchronized void updateResults() { + if (mDatabaseUpdated) { + return; + } + + final SQLiteDatabase database = getWritableDatabase(); + + database.beginTransaction(); + + int oldestWeekWeCareAbout = mNumberOfWeeksSinceEpoch - NUM_WEEKS + 1; + // delete rows we don't care about anymore + database.delete(SongPlayCountColumns.NAME, SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX + + " < " + oldestWeekWeCareAbout, null); + + // get the remaining rows + Cursor cursor = database.query(SongPlayCountColumns.NAME, + new String[]{SongPlayCountColumns.ID}, + null, null, null, null, null); + + if (cursor != null && cursor.moveToFirst()) { + // for each row, update it + do { + updateExistingRow(database, cursor.getLong(0), false); + } while (cursor.moveToNext()); + + cursor.close(); + } + + mDatabaseUpdated = true; + database.setTransactionSuccessful(); + database.endTransaction(); + } + + /** + * @param songId The song Id to remove. + */ + public void removeItem(final long songId) { + final SQLiteDatabase database = getWritableDatabase(); + deleteEntry(database, String.valueOf(songId)); + } + + /** + * Deletes the entry + * + * @param database database to use + * @param stringId id to delete + */ + private void deleteEntry(@NonNull final SQLiteDatabase database, final String stringId) { + database.delete(SongPlayCountColumns.NAME, WHERE_ID_EQUALS, new String[]{stringId}); + } + + public interface SongPlayCountColumns { + + String NAME = "song_play_count"; + + String ID = "song_id"; + + String WEEK_PLAY_COUNT = "week"; + + String LAST_UPDATED_WEEK_INDEX = "week_index"; + + String PLAY_COUNT_SCORE = "play_count_score"; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.java b/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.java new file mode 100644 index 00000000..11d3d7d4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.java @@ -0,0 +1,60 @@ +package code.name.monkey.retromusic.providers.interfaces; + +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist; +import io.reactivex.Observable; +import java.io.File; +import java.util.ArrayList; + +/** + * Created by hemanths on 11/08/17. + */ + +public interface Repository { + + Observable> getAllSongs(); + + Observable> getSuggestionSongs(); + + Observable getSong(int id); + + Observable> getAllAlbums(); + + Observable> getRecentAlbums(); + + Observable> getTopAlbums(); + + Observable getAlbum(int albumId); + + Observable> getAllArtists(); + + Observable> getRecentArtists(); + + Observable> getTopArtists(); + + + Observable getArtistById(long artistId); + + Observable> getAllPlaylists(); + + Observable> getFavoriteSongs(); + + Observable> search(String query); + + Observable> getPlaylistSongs(Playlist playlist); + + Observable> getHomeList(); + + Observable> getAllThings(); + + Observable> getAllGenres(); + + Observable> getGenre(int genreId); + + Observable downloadLrcFile(final String title, final String artist, final long duration); + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/rest/KogouClient.java b/app/src/main/java/code/name/monkey/retromusic/rest/KogouClient.java new file mode 100644 index 00000000..7ba3fb29 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/rest/KogouClient.java @@ -0,0 +1,76 @@ +package code.name.monkey.retromusic.rest; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import code.name.monkey.retromusic.Constants; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.rest.service.KuGouApiService; +import java.io.File; +import okhttp3.Cache; +import okhttp3.Call; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * Created by hemanths on 23/08/17. + */ + +public class KogouClient { + + private static final String BASE_URL = Constants.BASE_API_URL_KUGOU; + + private KuGouApiService apiService; + + public KogouClient() { + this(createDefaultOkHttpClientBuilder().build()); + } + + public KogouClient(@NonNull Call.Factory client) { + Retrofit restAdapter = new Retrofit.Builder() + .baseUrl(BASE_URL) + .callFactory(client) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .build(); + + apiService = restAdapter.create(KuGouApiService.class); + } + + @Nullable + public static Cache createDefaultCache(Context context) { + File cacheDir = new File(context.getCacheDir().getAbsolutePath(), "/okhttp-lastfm/"); + if (cacheDir.mkdirs() || cacheDir.isDirectory()) { + return new Cache(cacheDir, 1024 * 1024 * 10); + } + return null; + } + + public static Interceptor createCacheControlInterceptor() { + return chain -> { + Request modifiedRequest = chain.request().newBuilder() + .addHeader("Cache-Control", String.format("max-age=%d, max-stale=%d", 31536000, 31536000)) + .build(); + return chain.proceed(modifiedRequest); + }; + } + + public static OkHttpClient.Builder createDefaultOkHttpClientBuilder() { + HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); + interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + + return new OkHttpClient.Builder() + .addInterceptor(interceptor) + .cache(createDefaultCache(RetroApplication.getInstance())) + .addInterceptor(createCacheControlInterceptor()); + } + + public KuGouApiService getApiService() { + return apiService; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/rest/LastFMRestClient.java b/app/src/main/java/code/name/monkey/retromusic/rest/LastFMRestClient.java new file mode 100644 index 00000000..aae47690 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/rest/LastFMRestClient.java @@ -0,0 +1,66 @@ +package code.name.monkey.retromusic.rest; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import code.name.monkey.retromusic.rest.service.LastFMService; +import java.io.File; +import okhttp3.Cache; +import okhttp3.Call; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + + +public class LastFMRestClient { + + public static final String BASE_URL = "http://ws.audioscrobbler.com/2.0/"; + + private LastFMService apiService; + + public LastFMRestClient(@NonNull Context context) { + this(createDefaultOkHttpClientBuilder(context).build()); + } + + public LastFMRestClient(@NonNull Call.Factory client) { + Retrofit restAdapter = new Retrofit.Builder() + .baseUrl(BASE_URL) + .callFactory(client) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .build(); + + apiService = restAdapter.create(LastFMService.class); + } + + @Nullable + public static Cache createDefaultCache(Context context) { + File cacheDir = new File(context.getCacheDir().getAbsolutePath(), "/okhttp-lastfm/"); + if (cacheDir.mkdirs() || cacheDir.isDirectory()) { + return new Cache(cacheDir, 1024 * 1024 * 10); + } + return null; + } + + public static Interceptor createCacheControlInterceptor() { + return chain -> { + Request modifiedRequest = chain.request().newBuilder() + .addHeader("Cache-Control", String.format("max-age=%d, max-stale=%d", 31536000, 31536000)) + .build(); + return chain.proceed(modifiedRequest); + }; + } + + public static OkHttpClient.Builder createDefaultOkHttpClientBuilder(Context context) { + return new OkHttpClient.Builder() + .cache(createDefaultCache(context)) + .addInterceptor(createCacheControlInterceptor()); + } + + public LastFMService getApiService() { + return apiService; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/rest/model/KuGouRawLyric.java b/app/src/main/java/code/name/monkey/retromusic/rest/model/KuGouRawLyric.java new file mode 100644 index 00000000..1ce96f46 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/rest/model/KuGouRawLyric.java @@ -0,0 +1,41 @@ +package code.name.monkey.retromusic.rest.model; + +import com.google.gson.annotations.SerializedName; + +/** + * Created by hefuyi on 2017/1/20. + */ + +public class KuGouRawLyric { + + private static final String CHARSET = "charset"; + private static final String CONTENT = "content"; + private static final String FMT = "fmt"; + private static final String INFO = "info"; + private static final String STATUS = "status"; + + @SerializedName(CHARSET) + public String charset; + + @SerializedName(CONTENT) + public String content; + + @SerializedName(FMT) + public String fmt; + @SerializedName(INFO) + public String info; + @SerializedName(STATUS) + public int status; + + @Override + public String toString() { + return "KuGouRawLyric{" + + "charset='" + charset + '\'' + + ", content='" + content + '\'' + + ", fmt='" + fmt + '\'' + + ", info='" + info + '\'' + + ", status=" + status + + '}'; + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/rest/model/KuGouSearchLyricResult.java b/app/src/main/java/code/name/monkey/retromusic/rest/model/KuGouSearchLyricResult.java new file mode 100644 index 00000000..43f25be1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/rest/model/KuGouSearchLyricResult.java @@ -0,0 +1,90 @@ +package code.name.monkey.retromusic.rest.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +/** + * Created by hefuyi on 2017/1/20. + */ + +public class KuGouSearchLyricResult { + + private static final String INFO = "info"; + private static final String STATUS = "status"; + private static final String PROPOSAL = "proposal"; + private static final String KEYWORD = "keyword"; + private static final String CANDIDATES = "candidates"; + + @SerializedName(INFO) + public String info; + + @SerializedName(STATUS) + public int status; + + @SerializedName(PROPOSAL) + public String proposal; + + @SerializedName(KEYWORD) + public String keyword; + + @SerializedName(CANDIDATES) + public List candidates; + + @Override + public String toString() { + return "KuGouSearchLyricResult{" + + "info='" + info + '\'' + + ", status=" + status + + ", proposal='" + proposal + '\'' + + ", keyword='" + keyword + '\'' + + ", candidates=" + candidates + + '}'; + } + + public static class Candidates { + private static final String NICKNAME = "nickname"; + private static final String ACCESSKEY = "accesskey"; + private static final String SCORE = "score"; + private static final String DURATION = "duration"; + private static final String UID = "uid"; + private static final String SONG = "song"; + private static final String ID = "id"; + private static final String SINGER = "singer"; + private static final String LANGUAGE = "language"; + @SerializedName(NICKNAME) + public String nickname; + @SerializedName(ACCESSKEY) + public String accesskey; + @SerializedName(SCORE) + public int score; + @SerializedName(DURATION) + public long duration; + @SerializedName(UID) + public String uid; + @SerializedName(SONG) + public String songName; + @SerializedName(ID) + public String id; + @SerializedName(SINGER) + public String singer; + @SerializedName(LANGUAGE) + public String language; + + @Override + public String toString() { + return "Candidates{" + + "nickname='" + nickname + '\'' + + ", accesskey='" + accesskey + '\'' + + ", score=" + score + + ", duration=" + duration + + ", uid='" + uid + '\'' + + ", songName='" + songName + '\'' + + ", id='" + id + '\'' + + ", singer='" + singer + '\'' + + ", language='" + language + '\'' + + '}'; + } + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmAlbum.java b/app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmAlbum.java new file mode 100644 index 00000000..408fb224 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmAlbum.java @@ -0,0 +1,111 @@ +package code.name.monkey.retromusic.rest.model; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.ArrayList; +import java.util.List; + +public class LastFmAlbum { + @Expose + private Album album; + + public Album getAlbum() { + return album; + } + + public void setAlbum(Album album) { + this.album = album; + } + + public static class Album { + @Expose + private Tags tags; + @Expose + private List image = new ArrayList<>(); + @Expose + private Wiki wiki; + + public List getImage() { + return image; + } + + public void setImage(List image) { + this.image = image; + } + + public Wiki getWiki() { + return wiki; + } + + public void setWiki(Wiki wiki) { + this.wiki = wiki; + } + + public Tags getTags() { + return tags; + } + + public static class Image { + @SerializedName("#text") + @Expose + private String Text; + @Expose + private String size; + + public String getText() { + return Text; + } + + public void setText(String Text) { + this.Text = Text; + } + + public String getSize() { + return size; + } + + public void setSize(String size) { + this.size = size; + } + } + + public class Tags { + @Expose + private List tag = null; + + public List getTag() { + return tag; + } + } + + public class Tag { + @Expose + private String name; + + @Expose + private String url; + + public String getName() { + return name; + } + + public String getUrl() { + return url; + } + } + + public class Wiki { + @Expose + private String content; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmArtist.java b/app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmArtist.java new file mode 100644 index 00000000..03335a57 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmArtist.java @@ -0,0 +1,80 @@ +package code.name.monkey.retromusic.rest.model; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.ArrayList; +import java.util.List; + +public class LastFmArtist { + @Expose + private Artist artist; + + public Artist getArtist() { + return artist; + } + + public void setArtist(Artist artist) { + this.artist = artist; + } + + public static class Artist { + @Expose + private List image = new ArrayList<>(); + @Expose + private Bio bio; + + public List getImage() { + return image; + } + + public void setImage(List image) { + this.image = image; + } + + public Bio getBio() { + return bio; + } + + public void setBio(Bio bio) { + this.bio = bio; + } + + public class Bio { + @Expose + private String content; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + } + + public static class Image { + @SerializedName("#text") + @Expose + private String Text; + @Expose + private String size; + + public String getText() { + return Text; + } + + public void setText(String Text) { + this.Text = Text; + } + + public String getSize() { + return size; + } + + public void setSize(String size) { + this.size = size; + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmTrack.java b/app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmTrack.java new file mode 100644 index 00000000..f8623833 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/rest/model/LastFmTrack.java @@ -0,0 +1,174 @@ +package code.name.monkey.retromusic.rest.model; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +/** + * Created by hemanths on 15/06/17. + */ + +public class LastFmTrack { + + @Expose + private Track track; + + public Track getTrack() { + return track; + } + + public void setTrack(Track track) { + this.track = track; + } + + public static class Track { + @SerializedName("name") + @Expose + private String name; + @Expose + private Album album; + @Expose + private Wiki wiki; + @Expose + private Toptags toptags; + @Expose + private Artist artist; + + public Album getAlbum() { + return album; + } + + public Wiki getWiki() { + return wiki; + } + + public String getName() { + return name; + } + + public Toptags getToptags() { + return toptags; + } + + public static class Artist { + + @Expose + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + public static class Wiki { + @Expose + private String published; + + public String getPublished() { + return published; + } + + public void setPublished(String published) { + this.published = published; + } + } + + public static class Toptags { + @Expose + private List tag = null; + + + public List getTag() { + return tag; + } + + public static class Tag { + @Expose + private String name; + + public String getName() { + return name; + } + } + } + + public static class Album { + @Expose + private String artist; + @Expose + private List image = null; + @Expose + private String title; + @SerializedName("@attr") + @Expose + private Attr attr; + + public Attr getAttr() { + return attr; + } + + public void setAttr(Attr attr) { + this.attr = attr; + } + + public String getArtist() { + return artist; + } + + public void setArtist(String artist) { + this.artist = artist; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public List getImage() { + return image; + } + + public void setImage(List image) { + this.image = image; + } + + public static class Attr { + @Expose + private String position; + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + } + + public class Image { + + @SerializedName("#text") + @Expose + private String text; + @Expose + private String size; + + public String getSize() { + return size; + } + + public String getText() { + return text; + } + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/rest/service/KuGouApiService.java b/app/src/main/java/code/name/monkey/retromusic/rest/service/KuGouApiService.java new file mode 100644 index 00000000..ea11bd96 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/rest/service/KuGouApiService.java @@ -0,0 +1,21 @@ +package code.name.monkey.retromusic.rest.service; + +import code.name.monkey.retromusic.rest.model.KuGouRawLyric; +import code.name.monkey.retromusic.rest.model.KuGouSearchLyricResult; + +import io.reactivex.Observable; +import retrofit2.http.GET; +import retrofit2.http.Query; + +/** + * Created by hemanths on 28/07/17. + */ + +public interface KuGouApiService { + + @GET("search?ver=1&man=yes&client=pc") + Observable searchLyric(@Query("keyword") String songName, @Query("duration") String duration); + + @GET("download?ver=1&client=pc&fmt=lrc&charset=utf8") + Observable getRawLyric(@Query("id") String id, @Query("accesskey") String accesskey); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/rest/service/LastFMService.java b/app/src/main/java/code/name/monkey/retromusic/rest/service/LastFMService.java new file mode 100644 index 00000000..4a0ab117 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/rest/service/LastFMService.java @@ -0,0 +1,33 @@ +package code.name.monkey.retromusic.rest.service; + +import android.support.annotation.Nullable; + +import code.name.monkey.retromusic.BuildConfig; +import code.name.monkey.retromusic.rest.model.LastFmAlbum; +import code.name.monkey.retromusic.rest.model.LastFmArtist; +import code.name.monkey.retromusic.rest.model.LastFmTrack; + +import io.reactivex.Observable; +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Query; + + + +public interface LastFMService { + String API_KEY = "bd9c6ea4d55ec9ed3af7d276e5ece304"; + //String API_KEY = BuildConfig.LASTFM_API_KEY; + //String BASE_QUERY_PARAMETERS = "?format=json&autocorrect=1&api_key=" + API_KEY; + String BASE_QUERY_PARAMETERS = "?format=json&autocorrect=1&api_key=" + API_KEY; + String METHOD_TRACK = "track.getInfo"; + + @GET(BASE_QUERY_PARAMETERS + "&method=album.getinfo") + Observable getAlbumInfo(@Query("album") String albumName, @Query("artist") String artistName, @Nullable @Query("lang") String language); + + @GET("?api_key=" + BuildConfig.LASTFM_API_KEY + "&format=json&autocorrect=1" + "&method=" + METHOD_TRACK) + Observable getTrackInfo(@Query("artist") String artist, @Query("track") String track); + + @GET(BASE_QUERY_PARAMETERS + "&method=artist.getinfo") + Call getArtistInfo(@Query("artist") String artistName, @Nullable @Query("lang") String language, @Nullable @Header("Cache-Control") String cacheControl); +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MediaButtonIntentReceiver.java b/app/src/main/java/code/name/monkey/retromusic/service/MediaButtonIntentReceiver.java new file mode 100644 index 00000000..a728e7b4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/MediaButtonIntentReceiver.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2007 The Android Open Source Project 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 + * http://www.apache.org/licenses/LICENSE-2.0 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. + */ + +// Modified for Phonograph by Karim Abou Zeid (kabouzeid). + +package code.name.monkey.retromusic.service; + +import android.annotation.SuppressLint; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Handler; +import android.os.Message; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.util.Log; +import android.view.KeyEvent; + +import code.name.monkey.retromusic.BuildConfig; + +import static code.name.monkey.retromusic.Constants.ACTION_PAUSE; +import static code.name.monkey.retromusic.Constants.ACTION_PLAY; +import static code.name.monkey.retromusic.Constants.ACTION_REWIND; +import static code.name.monkey.retromusic.Constants.ACTION_SKIP; +import static code.name.monkey.retromusic.Constants.ACTION_STOP; +import static code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE; + +/** + * Used to control headset playback. + * Single press: pause/resume + * Double press: next track + * Triple press: previous track + */ +public class MediaButtonIntentReceiver extends BroadcastReceiver { + public static final String TAG = MediaButtonIntentReceiver.class.getSimpleName(); + private static final boolean DEBUG = BuildConfig.DEBUG; + private static final int MSG_HEADSET_DOUBLE_CLICK_TIMEOUT = 2; + + private static final int DOUBLE_CLICK = 400; + + private static WakeLock mWakeLock = null; + private static int mClickCounter = 0; + private static long mLastClickTime = 0; + + @SuppressLint("HandlerLeak") // false alarm, handler is already static + private static Handler mHandler = new Handler() { + + @Override + public void handleMessage(final Message msg) { + switch (msg.what) { + case MSG_HEADSET_DOUBLE_CLICK_TIMEOUT: + final int clickCount = msg.arg1; + final String command; + + if (DEBUG) Log.v(TAG, "Handling headset click, count = " + clickCount); + switch (clickCount) { + case 1: + command = ACTION_TOGGLE_PAUSE; + break; + case 2: + command = ACTION_SKIP; + break; + case 3: + command = ACTION_REWIND; + break; + default: + command = null; + break; + } + + if (command != null) { + final Context context = (Context) msg.obj; + startService(context, command); + } + break; + } + releaseWakeLockIfHandlerIdle(); + } + }; + + public static boolean handleIntent(final Context context, final Intent intent) { + final String intentAction = intent.getAction(); + if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) { + final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); + if (event == null) { + return false; + } + + final int keycode = event.getKeyCode(); + final int action = event.getAction(); + final long eventTime = event.getEventTime() != 0 ? + event.getEventTime() : System.currentTimeMillis(); + + String command = null; + switch (keycode) { + case KeyEvent.KEYCODE_MEDIA_STOP: + command = ACTION_STOP; + break; + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + command = ACTION_TOGGLE_PAUSE; + break; + case KeyEvent.KEYCODE_MEDIA_NEXT: + command = ACTION_SKIP; + break; + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + command = ACTION_REWIND; + break; + case KeyEvent.KEYCODE_MEDIA_PAUSE: + command = ACTION_PAUSE; + break; + case KeyEvent.KEYCODE_MEDIA_PLAY: + command = ACTION_PLAY; + break; + } + if (command != null) { + if (action == KeyEvent.ACTION_DOWN) { + if (event.getRepeatCount() == 0) { + // Only consider the first event in a sequence, not the repeat events, + // so that we don't trigger in cases where the first event went to + // a different app (e.g. when the user ends a phone call by + // long pressing the headset button) + + // The service may or may not be running, but we need to send it + // a command. + if (keycode == KeyEvent.KEYCODE_HEADSETHOOK || keycode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { + if (eventTime - mLastClickTime >= DOUBLE_CLICK) { + mClickCounter = 0; + } + + mClickCounter++; + if (DEBUG) Log.v(TAG, "Got headset click, count = " + mClickCounter); + mHandler.removeMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT); + + Message msg = mHandler.obtainMessage( + MSG_HEADSET_DOUBLE_CLICK_TIMEOUT, mClickCounter, 0, context); + + long delay = mClickCounter < 3 ? DOUBLE_CLICK : 0; + if (mClickCounter >= 3) { + mClickCounter = 0; + } + mLastClickTime = eventTime; + acquireWakeLockAndSendMessage(context, msg, delay); + } else { + startService(context, command); + } + return true; + } + } + } + } + return false; + } + + private static void startService(Context context, String command) { + final Intent intent = new Intent(context, MusicService.class); + intent.setAction(command); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(intent); + } else { + context.startService(intent); + } + } + + private static void acquireWakeLockAndSendMessage(Context context, Message msg, long delay) { + if (mWakeLock == null) { + Context appContext = context.getApplicationContext(); + PowerManager pm = (PowerManager) appContext.getSystemService(Context.POWER_SERVICE); + if (pm != null) { + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + "RetroMusicApp:Wakelock headset button"); + } + mWakeLock.setReferenceCounted(false); + } + if (DEBUG) Log.v(TAG, "Acquiring wake lock and sending " + msg.what); + // Make sure we don't indefinitely hold the wake lock under any circumstances + mWakeLock.acquire(10000); + + mHandler.sendMessageDelayed(msg, delay); + } + + private static void releaseWakeLockIfHandlerIdle() { + if (mHandler.hasMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT)) { + if (DEBUG) Log.v(TAG, "Handler still has messages pending, not releasing wake lock"); + return; + } + + if (mWakeLock != null) { + if (DEBUG) Log.v(TAG, "Releasing wake lock"); + mWakeLock.release(); + mWakeLock = null; + } + } + + @Override + public void onReceive(final Context context, final Intent intent) { + if (DEBUG) Log.v(TAG, "Received intent: " + intent); + if (handleIntent(context, intent) && isOrderedBroadcast()) { + abortBroadcast(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java new file mode 100644 index 00000000..d7a7e23b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java @@ -0,0 +1,334 @@ +package code.name.monkey.retromusic.service; + +import android.content.Context; +import android.content.Intent; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.media.audiofx.AudioEffect; +import android.net.Uri; +import android.os.PowerManager; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; +import android.widget.Toast; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.service.playback.Playback; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * @author Andrew Neal, Karim Abou Zeid (kabouzeid) + */ +public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener { + public static final String TAG = MultiPlayer.class.getSimpleName(); + + private MediaPlayer mCurrentMediaPlayer = new MediaPlayer(); + private MediaPlayer mNextMediaPlayer; + + private Context context; + @Nullable + private Playback.PlaybackCallbacks callbacks; + + private boolean mIsInitialized = false; + + /** + * Constructor of MultiPlayer + */ + MultiPlayer(final Context context) { + this.context = context; + mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK); + } + + /** + * @param path The path of the file, or the http/rtsp URL of the stream + * you want to play + * @return True if the player has been prepared and is + * ready to play, false otherwise + */ + @Override + public boolean setDataSource(@NonNull final String path) { + mIsInitialized = false; + mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path); + if (mIsInitialized) { + setNextDataSource(null); + } + return mIsInitialized; + } + + /** + * @param player The {@link MediaPlayer} to use + * @param path The path of the file, or the http/rtsp URL of the stream + * you want to play + * @return True if the player has been prepared and is + * ready to play, false otherwise + */ + private boolean setDataSourceImpl(@NonNull final MediaPlayer player, @NonNull final String path) { + if (context == null) { + return false; + } + try { + player.reset(); + player.setOnPreparedListener(null); + if (path.startsWith("content://")) { + player.setDataSource(context, Uri.parse(path)); + } else { + player.setDataSource(path); + } + player.setAudioStreamType(AudioManager.STREAM_MUSIC); + player.prepare(); + } catch (Exception e) { + return false; + } + player.setOnCompletionListener(this); + player.setOnErrorListener(this); + final Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION); + intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId()); + intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName()); + intent.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC); + context.sendBroadcast(intent); + return true; + } + + /** + * Set the MediaPlayer to start when this MediaPlayer finishes playback. + * + * @param path The path of the file, or the http/rtsp URL of the stream + * you want to play + */ + @Override + public void setNextDataSource(@Nullable final String path) { + if (context == null) { + return; + } + try { + mCurrentMediaPlayer.setNextMediaPlayer(null); + } catch (IllegalArgumentException e) { + Log.i(TAG, "Next media player is current one, continuing"); + } catch (IllegalStateException e) { + Log.e(TAG, "Media player not initialized!"); + return; + } + if (mNextMediaPlayer != null) { + mNextMediaPlayer.release(); + mNextMediaPlayer = null; + } + if (path == null) { + return; + } + if (PreferenceUtil.getInstance(context).gaplessPlayback()) { + mNextMediaPlayer = new MediaPlayer(); + mNextMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK); + mNextMediaPlayer.setAudioSessionId(getAudioSessionId()); + if (setDataSourceImpl(mNextMediaPlayer, path)) { + try { + mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer); + } catch (@NonNull IllegalArgumentException | IllegalStateException e) { + Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e); + if (mNextMediaPlayer != null) { + mNextMediaPlayer.release(); + mNextMediaPlayer = null; + } + } + } else { + if (mNextMediaPlayer != null) { + mNextMediaPlayer.release(); + mNextMediaPlayer = null; + } + } + } + } + + /** + * Sets the callbacks + * + * @param callbacks The callbacks to use + */ + @Override + public void setCallbacks(@Nullable final Playback.PlaybackCallbacks callbacks) { + this.callbacks = callbacks; + } + + /** + * @return True if the player is ready to go, false otherwise + */ + @Override + public boolean isInitialized() { + return mIsInitialized; + } + + /** + * Starts or resumes playback. + */ + @Override + public boolean start() { + try { + mCurrentMediaPlayer.start(); + return true; + } catch (IllegalStateException e) { + return false; + } + } + + /** + * Resets the MediaPlayer to its uninitialized state. + */ + @Override + public void stop() { + mCurrentMediaPlayer.reset(); + mIsInitialized = false; + } + + /** + * Releases resources associated with this MediaPlayer object. + */ + @Override + public void release() { + stop(); + mCurrentMediaPlayer.release(); + if (mNextMediaPlayer != null) { + mNextMediaPlayer.release(); + } + } + + /** + * Pauses playback. Call start() to resume. + */ + @Override + public boolean pause() { + try { + mCurrentMediaPlayer.pause(); + return true; + } catch (IllegalStateException e) { + return false; + } + } + + /** + * Checks whether the MultiPlayer is playing. + */ + @Override + public boolean isPlaying() { + return mIsInitialized && mCurrentMediaPlayer.isPlaying(); + } + + /** + * Gets the duration of the file. + * + * @return The duration in milliseconds + */ + @Override + public int duration() { + if (!mIsInitialized) { + return -1; + } + try { + return mCurrentMediaPlayer.getDuration(); + } catch (IllegalStateException e) { + return -1; + } + } + + /** + * Gets the current playback position. + * + * @return The current position in milliseconds + */ + @Override + public int position() { + if (!mIsInitialized) { + return -1; + } + try { + return mCurrentMediaPlayer.getCurrentPosition(); + } catch (IllegalStateException e) { + return -1; + } + } + + /** + * Gets the current playback position. + * + * @param whereto The offset in milliseconds from the start to seek to + * @return The offset in milliseconds from the start to seek to + */ + @Override + public int seek(final int whereto) { + try { + mCurrentMediaPlayer.seekTo(whereto); + return whereto; + } catch (IllegalStateException e) { + return -1; + } + } + + @Override + public boolean setVolume(final float vol) { + try { + mCurrentMediaPlayer.setVolume(vol, vol); + return true; + } catch (IllegalStateException e) { + return false; + } + } + + /** + * Sets the audio session ID. + * + * @param sessionId The audio session ID + */ + @Override + public boolean setAudioSessionId(final int sessionId) { + try { + mCurrentMediaPlayer.setAudioSessionId(sessionId); + return true; + } catch (@NonNull IllegalArgumentException | IllegalStateException e) { + return false; + } + } + + /** + * Returns the audio session ID. + * + * @return The current audio session ID. + */ + @Override + public int getAudioSessionId() { + return mCurrentMediaPlayer.getAudioSessionId(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean onError(final MediaPlayer mp, final int what, final int extra) { + mIsInitialized = false; + mCurrentMediaPlayer.release(); + mCurrentMediaPlayer = new MediaPlayer(); + mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK); + if (context != null) { + Toast.makeText(context, context.getResources().getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show(); + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public void onCompletion(final MediaPlayer mp) { + if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) { + mIsInitialized = false; + mCurrentMediaPlayer.release(); + mCurrentMediaPlayer = mNextMediaPlayer; + mIsInitialized = true; + mNextMediaPlayer = null; + if (callbacks != null) + callbacks.onTrackWentToNext(); + } else { + if (callbacks != null) + callbacks.onTrackEnded(); + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java new file mode 100644 index 00000000..0007eb23 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java @@ -0,0 +1,1447 @@ +package code.name.monkey.retromusic.service; + +import android.app.PendingIntent; +import android.app.Service; +import android.appwidget.AppWidgetManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.database.ContentObserver; +import android.graphics.Bitmap; +import android.graphics.Point; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; +import android.media.audiofx.AudioEffect; +import android.media.session.MediaSession; +import android.os.Binder; +import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.os.Process; +import android.preference.PreferenceManager; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.media.MediaMetadataCompat; +import android.support.v4.media.session.MediaSessionCompat; +import android.support.v4.media.session.PlaybackStateCompat; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.widget.Toast; + +import code.name.monkey.retromusic.service.notification.PlayingNotificationOreo; +import com.bumptech.glide.BitmapRequestBuilder; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.appwidgets.AppWidgetBig; +import code.name.monkey.retromusic.appwidgets.AppWidgetCard; +import code.name.monkey.retromusic.appwidgets.AppWidgetClassic; +import code.name.monkey.retromusic.appwidgets.AppWidgetSmall; +import code.name.monkey.retromusic.glide.BlurTransformation; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.ShuffleHelper; +import code.name.monkey.retromusic.helper.StopWatch; +import code.name.monkey.retromusic.loaders.PlaylistSongsLoader; +import code.name.monkey.retromusic.model.AbsCustomPlaylist; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.providers.HistoryStore; +import code.name.monkey.retromusic.providers.MusicPlaybackQueueStore; +import code.name.monkey.retromusic.providers.SongPlayCountStore; +import code.name.monkey.retromusic.service.notification.PlayingNotification; +import code.name.monkey.retromusic.service.notification.PlayingNotificationImpl24; +import code.name.monkey.retromusic.service.playback.Playback; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroUtil; + +import static code.name.monkey.retromusic.Constants.ACTION_PAUSE; +import static code.name.monkey.retromusic.Constants.ACTION_PLAY; +import static code.name.monkey.retromusic.Constants.ACTION_PLAY_PLAYLIST; +import static code.name.monkey.retromusic.Constants.ACTION_QUIT; +import static code.name.monkey.retromusic.Constants.ACTION_REWIND; +import static code.name.monkey.retromusic.Constants.ACTION_SKIP; +import static code.name.monkey.retromusic.Constants.ACTION_STOP; +import static code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE; +import static code.name.monkey.retromusic.Constants.APP_WIDGET_UPDATE; +import static code.name.monkey.retromusic.Constants.EXTRA_APP_WIDGET_NAME; +import static code.name.monkey.retromusic.Constants.INTENT_EXTRA_PLAYLIST; +import static code.name.monkey.retromusic.Constants.INTENT_EXTRA_SHUFFLE_MODE; +import static code.name.monkey.retromusic.Constants.MEDIA_STORE_CHANGED; +import static code.name.monkey.retromusic.Constants.META_CHANGED; +import static code.name.monkey.retromusic.Constants.MUSIC_PACKAGE_NAME; +import static code.name.monkey.retromusic.Constants.PLAY_STATE_CHANGED; +import static code.name.monkey.retromusic.Constants.QUEUE_CHANGED; +import static code.name.monkey.retromusic.Constants.REPEAT_MODE_CHANGED; +import static code.name.monkey.retromusic.Constants.RETRO_MUSIC_PACKAGE_NAME; +import static code.name.monkey.retromusic.Constants.SHUFFLE_MODE_CHANGED; + +/** + * @author Karim Abou Zeid (kabouzeid), Andrew Neal + */ +public class MusicService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener, Playback.PlaybackCallbacks { + public static final String TAG = MusicService.class.getSimpleName(); + + public static final String SAVED_POSITION = "POSITION"; + public static final String SAVED_POSITION_IN_TRACK = "POSITION_IN_TRACK"; + public static final String SAVED_SHUFFLE_MODE = "SHUFFLE_MODE"; + public static final String SAVED_REPEAT_MODE = "REPEAT_MODE"; + + public static final int RELEASE_WAKELOCK = 0; + public static final int TRACK_ENDED = 1; + public static final int TRACK_WENT_TO_NEXT = 2; + public static final int PLAY_SONG = 3; + public static final int PREPARE_NEXT = 4; + public static final int SET_POSITION = 5; + public static final int RESTORE_QUEUES = 9; + public static final int SHUFFLE_MODE_NONE = 0; + public static final int SHUFFLE_MODE_SHUFFLE = 1; + public static final int REPEAT_MODE_NONE = 0; + public static final int REPEAT_MODE_ALL = 1; + public static final int REPEAT_MODE_THIS = 2; + public static final int SAVE_QUEUES = 0; + private static final int FOCUS_CHANGE = 6; + private static final int DUCK = 7; + private static final int UNDUCK = 8; + private static final long MEDIA_SESSION_ACTIONS = PlaybackStateCompat.ACTION_PLAY + | PlaybackStateCompat.ACTION_PAUSE + | PlaybackStateCompat.ACTION_PLAY_PAUSE + | PlaybackStateCompat.ACTION_SKIP_TO_NEXT + | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS + | PlaybackStateCompat.ACTION_STOP + | PlaybackStateCompat.ACTION_SEEK_TO; + private final IBinder musicBind = new MusicBinder(); + private AppWidgetBig appWidgetBig = AppWidgetBig.getInstance(); + private AppWidgetClassic appWidgetClassic = AppWidgetClassic.getInstance(); + private AppWidgetSmall appWidgetSmall = AppWidgetSmall.getInstance(); + private AppWidgetCard appWidgetCard = AppWidgetCard.getInstance(); + private Playback playback; + private ArrayList playingQueue = new ArrayList<>(); + private ArrayList originalPlayingQueue = new ArrayList<>(); + private int position = -1; + private int nextPosition = -1; + private int shuffleMode; + private int repeatMode; + private boolean queuesRestored; + private boolean pausedByTransientLossOfFocus; + private final BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, @NonNull Intent intent) { + if (intent.getAction() != null && intent.getAction().equals(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) { + pause(); + } + } + }; + private PlayingNotification playingNotification; + private AudioManager audioManager; + @SuppressWarnings("deprecation") + private MediaSessionCompat mediaSession; + private PowerManager.WakeLock wakeLock; + private PlaybackHandler playerHandler; + private final AudioManager.OnAudioFocusChangeListener audioFocusListener = new AudioManager.OnAudioFocusChangeListener() { + @Override + public void onAudioFocusChange(final int focusChange) { + playerHandler.obtainMessage(FOCUS_CHANGE, focusChange, 0).sendToTarget(); + } + }; + private QueueSaveHandler queueSaveHandler; + private HandlerThread musicPlayerHandlerThread; + private HandlerThread queueSaveHandlerThread; + private SongPlayCountHelper songPlayCountHelper = new SongPlayCountHelper(); + private ThrottledSeekHandler throttledSeekHandler; + private boolean becomingNoisyReceiverRegistered; + private IntentFilter becomingNoisyReceiverIntentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY); + private ContentObserver mediaStoreObserver; + private boolean notHandledMetaChangedForCurrentTrack; + private PhoneStateListener phoneStateListener = new PhoneStateListener() { + @Override + public void onCallStateChanged(int state, String incomingNumber) { + switch (state) { + case TelephonyManager.CALL_STATE_IDLE: + //Not in call: Play music + play(); + break; + case TelephonyManager.CALL_STATE_RINGING: + case TelephonyManager.CALL_STATE_OFFHOOK: + //A call is dialing, active or on hold + pause(); + break; + default: + } + super.onCallStateChanged(state, incomingNumber); + } + }; + private boolean isServiceBound; + private Handler uiThreadHandler; + private final BroadcastReceiver widgetIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final String command = intent.getStringExtra(EXTRA_APP_WIDGET_NAME); + + if (AppWidgetClassic.NAME.equals(command)) { + final int[] ids = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); + appWidgetClassic.performUpdate(MusicService.this, ids); + } else if (AppWidgetSmall.NAME.equals(command)) { + final int[] ids = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); + appWidgetSmall.performUpdate(MusicService.this, ids); + } else if (AppWidgetBig.NAME.equals(command)) { + final int[] ids = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); + appWidgetBig.performUpdate(MusicService.this, ids); + } else if (AppWidgetCard.NAME.equals(command)) { + final int[] ids = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); + appWidgetCard.performUpdate(MusicService.this, ids); + } + } + }; + private IntentFilter headsetReceiverIntentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); + private boolean headsetReceiverRegistered = false; + private BroadcastReceiver headsetReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action != null) { + switch (action) { + case Intent.ACTION_HEADSET_PLUG: + int state = intent.getIntExtra("state", -1); + switch (state) { + case 0: + Log.d(TAG, "Headset unplugged"); + pause(); + break; + case 1: + Log.d(TAG, "Headset plugged"); + play(); + break; + } + break; + } + } + } + }; + + private static String getTrackUri(@NonNull Song song) { + return MusicUtil.getSongFileUri(song.id).toString(); + } + + private static Bitmap copy(Bitmap bitmap) { + Bitmap.Config config = bitmap.getConfig(); + if (config == null) { + config = Bitmap.Config.RGB_565; + } + try { + return bitmap.copy(config, false); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + return null; + } + } + + + @Override + public void onCreate() { + super.onCreate(); + + final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); + if (telephonyManager != null) { + telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE); + } + + final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); + if (powerManager != null) { + wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName()); + } + wakeLock.setReferenceCounted(false); + + musicPlayerHandlerThread = new HandlerThread("PlaybackHandler"); + musicPlayerHandlerThread.start(); + playerHandler = new PlaybackHandler(this, musicPlayerHandlerThread.getLooper()); + + playback = new MultiPlayer(this); + playback.setCallbacks(this); + + setupMediaSession(); + + // queue saving needs to run on a separate thread so that it doesn't block the playback handler events + queueSaveHandlerThread = new HandlerThread("QueueSaveHandler", Process.THREAD_PRIORITY_BACKGROUND); + queueSaveHandlerThread.start(); + queueSaveHandler = new QueueSaveHandler(this, queueSaveHandlerThread.getLooper()); + + uiThreadHandler = new Handler(); + + registerReceiver(widgetIntentReceiver, new IntentFilter(APP_WIDGET_UPDATE)); + + initNotification(); + + mediaStoreObserver = new MediaStoreObserver(playerHandler); + throttledSeekHandler = new ThrottledSeekHandler(playerHandler); + getContentResolver().registerContentObserver( + MediaStore.Audio.Media.INTERNAL_CONTENT_URI, true, mediaStoreObserver); + getContentResolver().registerContentObserver( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, mediaStoreObserver); + + PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this); + + restoreState(); + + mediaSession.setActive(true); + + sendBroadcast(new Intent("code.name.monkey.retromusic.RETRO_MUSIC_SERVICE_CREATED")); + + registerHeadsetEvents(); + + } + + private AudioManager getAudioManager() { + if (audioManager == null) { + audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + } + return audioManager; + } + + private void setupMediaSession() { + ComponentName mediaButtonReceiverComponentName = new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class); + + Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); + mediaButtonIntent.setComponent(mediaButtonReceiverComponentName); + + + PendingIntent mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0); + + mediaSession = new MediaSessionCompat(this, "RetroMusicPlayer", mediaButtonReceiverComponentName, mediaButtonReceiverPendingIntent); + mediaSession.setCallback(new MediaSessionCompat.Callback() { + @Override + public void onPlay() { + play(); + } + + @Override + public void onPause() { + pause(); + } + + @Override + public void onSkipToNext() { + playNextSong(true); + } + + @Override + public void onSkipToPrevious() { + back(true); + } + + @Override + public void onStop() { + quit(); + } + + @Override + public void onSeekTo(long pos) { + seek((int) pos); + } + + @Override + public boolean onMediaButtonEvent(Intent mediaButtonEvent) { + return MediaButtonIntentReceiver.handleIntent(MusicService.this, mediaButtonEvent); + } + }); + + mediaSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS + | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS); + + mediaSession.setMediaButtonReceiver(mediaButtonReceiverPendingIntent); + } + + @Override + public int onStartCommand(@Nullable Intent intent, int flags, int startId) { + if (intent != null) { + if (intent.getAction() != null) { + restoreQueuesAndPositionIfNecessary(); + String action = intent.getAction(); + switch (action) { + case ACTION_TOGGLE_PAUSE: + if (isPlaying()) { + pause(); + } else { + play(); + } + break; + case ACTION_PAUSE: + pause(); + break; + case ACTION_PLAY: + play(); + break; + case ACTION_PLAY_PLAYLIST: + Playlist playlist = intent.getParcelableExtra(INTENT_EXTRA_PLAYLIST); + int shuffleMode = intent.getIntExtra(INTENT_EXTRA_SHUFFLE_MODE, getShuffleMode()); + if (playlist != null) { + ArrayList playlistSongs; + if (playlist instanceof AbsCustomPlaylist) { + playlistSongs = ((AbsCustomPlaylist) playlist).getSongs(getApplicationContext()).blockingFirst(); + } else { + //noinspection unchecked + playlistSongs = PlaylistSongsLoader.getPlaylistSongList(getApplicationContext(), playlist.id).blockingFirst(); + } + if (!playlistSongs.isEmpty()) { + if (shuffleMode == SHUFFLE_MODE_SHUFFLE) { + int startPosition; + startPosition = new Random().nextInt(playlistSongs.size()); + openQueue(playlistSongs, startPosition, true); + setShuffleMode(shuffleMode); + } else { + openQueue(playlistSongs, 0, true); + } + } else { + Toast.makeText(getApplicationContext(), R.string.playlist_is_empty, Toast.LENGTH_LONG).show(); + } + } else { + Toast.makeText(getApplicationContext(), R.string.playlist_is_empty, Toast.LENGTH_LONG).show(); + } + break; + case ACTION_REWIND: + back(true); + break; + case ACTION_SKIP: + playNextSong(true); + break; + case ACTION_STOP: + case ACTION_QUIT: + return quit(); + } + } + } + + return START_STICKY; + } + + + @Override + public void onDestroy() { + unregisterReceiver(widgetIntentReceiver); + if (becomingNoisyReceiverRegistered) { + unregisterReceiver(becomingNoisyReceiver); + becomingNoisyReceiverRegistered = false; + } + if (headsetReceiverRegistered) { + unregisterReceiver(headsetReceiver); + headsetReceiverRegistered = false; + } + mediaSession.setActive(false); + quit(); + releaseResources(); + getContentResolver().unregisterContentObserver(mediaStoreObserver); + PreferenceUtil.getInstance(this).unregisterOnSharedPreferenceChangedListener(this); + wakeLock.release(); + + sendBroadcast(new Intent("code.name.monkey.retromusic.RETRO_MUSIC_MUSIC_SERVICE_DESTROYED")); + } + + @Override + public IBinder onBind(Intent intent) { + isServiceBound = true; + return musicBind; + } + + @Override + public void onRebind(Intent intent) { + isServiceBound = true; + } + + @Override + public boolean onUnbind(Intent intent) { + isServiceBound = false; + if (!isPlaying()) { + stopSelf(); + } + return true; + } + + private void saveQueuesImpl() { + MusicPlaybackQueueStore.getInstance(this).saveQueues(playingQueue, originalPlayingQueue); + } + + private void savePosition() { + PreferenceManager.getDefaultSharedPreferences(this).edit().putInt(SAVED_POSITION, getPosition()).apply(); + } + + private void savePositionInTrack() { + PreferenceManager.getDefaultSharedPreferences(this).edit().putInt(SAVED_POSITION_IN_TRACK, getSongProgressMillis()).apply(); + } + + public void saveState() { + saveQueues(); + savePosition(); + savePositionInTrack(); + } + + private void saveQueues() { + queueSaveHandler.removeMessages(SAVE_QUEUES); + queueSaveHandler.sendEmptyMessage(SAVE_QUEUES); + } + + private void restoreState() { + shuffleMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_SHUFFLE_MODE, 0); + repeatMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_REPEAT_MODE, 0); + handleAndSendChangeInternal(SHUFFLE_MODE_CHANGED); + handleAndSendChangeInternal(REPEAT_MODE_CHANGED); + + playerHandler.removeMessages(RESTORE_QUEUES); + playerHandler.sendEmptyMessage(RESTORE_QUEUES); + } + + private synchronized void restoreQueuesAndPositionIfNecessary() { + if (!queuesRestored && playingQueue.isEmpty()) { + ArrayList restoredQueue = MusicPlaybackQueueStore.getInstance(this).getSavedPlayingQueue() + .blockingFirst(); + + ArrayList restoredOriginalQueue = MusicPlaybackQueueStore.getInstance(this).getSavedOriginalPlayingQueue() + .blockingFirst(); + + int restoredPosition = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION, -1); + int restoredPositionInTrack = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION_IN_TRACK, -1); + + if (restoredQueue.size() > 0 && restoredQueue.size() == restoredOriginalQueue.size() && restoredPosition != -1) { + this.originalPlayingQueue = restoredOriginalQueue; + this.playingQueue = restoredQueue; + + position = restoredPosition; + openCurrent(); + prepareNext(); + + if (restoredPositionInTrack > 0) seek(restoredPositionInTrack); + + notHandledMetaChangedForCurrentTrack = true; + sendChangeInternal(META_CHANGED); + sendChangeInternal(QUEUE_CHANGED); + } + } + queuesRestored = true; + } + + private int quit() { + pause(); + playingNotification.stop(); + + if (isServiceBound) { + return START_STICKY; + } else { + closeAudioEffectSession(); + getAudioManager().abandonAudioFocus(audioFocusListener); + stopSelf(); + return START_NOT_STICKY; + } + } + + private void releaseResources() { + playerHandler.removeCallbacksAndMessages(null); + musicPlayerHandlerThread.quitSafely(); + queueSaveHandler.removeCallbacksAndMessages(null); + queueSaveHandlerThread.quitSafely(); + playback.release(); + playback = null; + mediaSession.release(); + } + + public boolean isPlaying() { + return playback != null && playback.isPlaying(); + } + + public int getPosition() { + return position; + } + + public void setPosition(final int position) { + // handle this on the handlers thread to avoid blocking the ui thread + playerHandler.removeMessages(SET_POSITION); + playerHandler.obtainMessage(SET_POSITION, position, 0).sendToTarget(); + } + + public void playNextSong(boolean force) { + playSongAt(getNextPosition(force)); + } + + private boolean openTrackAndPrepareNextAt(int position) { + synchronized (this) { + this.position = position; + boolean prepared = openCurrent(); + if (prepared) prepareNextImpl(); + notifyChange(META_CHANGED); + notHandledMetaChangedForCurrentTrack = false; + return prepared; + } + } + + private boolean openCurrent() { + synchronized (this) { + try { + return playback.setDataSource(getTrackUri(getCurrentSong())); + } catch (Exception e) { + return false; + } + } + } + + private void prepareNext() { + playerHandler.removeMessages(PREPARE_NEXT); + playerHandler.obtainMessage(PREPARE_NEXT).sendToTarget(); + } + + private boolean prepareNextImpl() { + synchronized (this) { + try { + int nextPosition = getNextPosition(false); + playback.setNextDataSource(getTrackUri(getSongAt(nextPosition))); + this.nextPosition = nextPosition; + return true; + } catch (Exception e) { + return false; + } + } + } + + private void closeAudioEffectSession() { + final Intent audioEffectsIntent = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION); + audioEffectsIntent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, playback.getAudioSessionId()); + audioEffectsIntent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); + sendBroadcast(audioEffectsIntent); + } + + private boolean requestFocus() { + return (getAudioManager().requestAudioFocus(audioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED); + } + + public void initNotification() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !PreferenceUtil.getInstance(this).classicNotification()) { + playingNotification = new PlayingNotificationImpl24(); + } else { + playingNotification = new PlayingNotificationOreo(); + } + playingNotification.init(this); + } + + public void updateNotification() { + if (playingNotification != null && getCurrentSong().id != -1) { + playingNotification.update(); + } + } + + private void updateMediaSessionPlaybackState() { + mediaSession.setPlaybackState( + new PlaybackStateCompat.Builder() + .setActions(MEDIA_SESSION_ACTIONS) + .setState(isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED, + getPosition(), 1) + .build()); + } + + private void updateMediaSessionMetaData() { + final Song song = getCurrentSong(); + + if (song.id == -1) { + mediaSession.setMetadata(null); + return; + } + + final MediaMetadataCompat.Builder metaData = new MediaMetadataCompat.Builder() + .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, song.artistName) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, song.artistName) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, song.albumName) + .putString(MediaMetadataCompat.METADATA_KEY_TITLE, song.title) + .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, song.duration) + .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, getPosition() + 1) + .putLong(MediaMetadataCompat.METADATA_KEY_YEAR, song.year) + .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, null); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + metaData.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, getPlayingQueue().size()); + } + + if (PreferenceUtil.getInstance(this).albumArtOnLockscreen()) { + final Point screenSize = RetroUtil.getScreenSize(MusicService.this); + final BitmapRequestBuilder request = SongGlideRequest.Builder.from(Glide.with(MusicService.this), song) + .checkIgnoreMediaStore(MusicService.this) + .asBitmap().build(); + if (PreferenceUtil.getInstance(this).blurredAlbumArt()) { + request.transform(new BlurTransformation.Builder(MusicService.this).build()); + } + runOnUiThread(new Runnable() { + @Override + public void run() { + request.into(new SimpleTarget(screenSize.x, screenSize.y) { + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + mediaSession.setMetadata(metaData.build()); + } + + @Override + public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) { + metaData.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, copy(resource)); + mediaSession.setMetadata(metaData.build()); + } + }); + } + }); + } else { + mediaSession.setMetadata(metaData.build()); + } + } + + public void runOnUiThread(Runnable runnable) { + uiThreadHandler.post(runnable); + } + + public Song getCurrentSong() { + return getSongAt(getPosition()); + } + + public Song getSongAt(int position) { + if (position >= 0 && position < getPlayingQueue().size()) { + return getPlayingQueue().get(position); + } else { + return Song.EMPTY_SONG; + } + } + + public int getNextPosition(boolean force) { + int position = getPosition() + 1; + switch (getRepeatMode()) { + case REPEAT_MODE_ALL: + if (isLastTrack()) { + position = 0; + } + break; + case REPEAT_MODE_THIS: + if (force) { + if (isLastTrack()) { + position = 0; + } + } else { + position -= 1; + } + break; + default: + case REPEAT_MODE_NONE: + if (isLastTrack()) { + position -= 1; + } + break; + } + return position; + } + + private boolean isLastTrack() { + return getPosition() == getPlayingQueue().size() - 1; + } + + public ArrayList getPlayingQueue() { + return playingQueue; + } + + public int getRepeatMode() { + return repeatMode; + } + + public void setRepeatMode(final int repeatMode) { + switch (repeatMode) { + case REPEAT_MODE_NONE: + case REPEAT_MODE_ALL: + case REPEAT_MODE_THIS: + this.repeatMode = repeatMode; + PreferenceManager.getDefaultSharedPreferences(this).edit() + .putInt(SAVED_REPEAT_MODE, repeatMode) + .apply(); + prepareNext(); + handleAndSendChangeInternal(REPEAT_MODE_CHANGED); + break; + } + } + + public void openQueue(@Nullable final ArrayList playingQueue, final int startPosition, final boolean startPlaying) { + if (playingQueue != null && !playingQueue.isEmpty() && startPosition >= 0 && startPosition < playingQueue.size()) { + // it is important to copy the playing queue here first as we might add/remove songs later + originalPlayingQueue = new ArrayList<>(playingQueue); + this.playingQueue = new ArrayList<>(originalPlayingQueue); + + int position = startPosition; + if (shuffleMode == SHUFFLE_MODE_SHUFFLE) { + ShuffleHelper.makeShuffleList(this.playingQueue, startPosition); + position = 0; + } + if (startPlaying) { + playSongAt(position); + } else { + setPosition(position); + } + notifyChange(QUEUE_CHANGED); + } + } + + public void addSong(int position, Song song) { + playingQueue.add(position, song); + originalPlayingQueue.add(position, song); + notifyChange(QUEUE_CHANGED); + } + + public void addSong(Song song) { + playingQueue.add(song); + originalPlayingQueue.add(song); + notifyChange(QUEUE_CHANGED); + } + + public void addSongs(int position, List songs) { + playingQueue.addAll(position, songs); + originalPlayingQueue.addAll(position, songs); + notifyChange(QUEUE_CHANGED); + } + + public void addSongs(List songs) { + playingQueue.addAll(songs); + originalPlayingQueue.addAll(songs); + notifyChange(QUEUE_CHANGED); + } + + public void removeSong(int position) { + if (getShuffleMode() == SHUFFLE_MODE_NONE) { + playingQueue.remove(position); + originalPlayingQueue.remove(position); + } else { + originalPlayingQueue.remove(playingQueue.remove(position)); + } + + rePosition(position); + + notifyChange(QUEUE_CHANGED); + } + + public void removeSong(@NonNull Song song) { + for (int i = 0; i < playingQueue.size(); i++) { + if (playingQueue.get(i).id == song.id) { + playingQueue.remove(i); + rePosition(i); + } + } + for (int i = 0; i < originalPlayingQueue.size(); i++) { + if (originalPlayingQueue.get(i).id == song.id) { + originalPlayingQueue.remove(i); + } + } + notifyChange(QUEUE_CHANGED); + } + + private void rePosition(int deletedPosition) { + int currentPosition = getPosition(); + if (deletedPosition < currentPosition) { + position = currentPosition - 1; + } else if (deletedPosition == currentPosition) { + if (playingQueue.size() > deletedPosition) { + setPosition(position); + } else { + setPosition(position - 1); + } + } + } + + public void moveSong(int from, int to) { + if (from == to) return; + final int currentPosition = getPosition(); + Song songToMove = playingQueue.remove(from); + playingQueue.add(to, songToMove); + if (getShuffleMode() == SHUFFLE_MODE_NONE) { + Song tmpSong = originalPlayingQueue.remove(from); + originalPlayingQueue.add(to, tmpSong); + } + if (from > currentPosition && to <= currentPosition) { + position = currentPosition + 1; + } else if (from < currentPosition && to >= currentPosition) { + position = currentPosition - 1; + } else if (from == currentPosition) { + position = to; + } + notifyChange(QUEUE_CHANGED); + } + + public void clearQueue() { + playingQueue.clear(); + originalPlayingQueue.clear(); + + setPosition(-1); + notifyChange(QUEUE_CHANGED); + } + + public void playSongAt(final int position) { + // handle this on the handlers thread to avoid blocking the ui thread + playerHandler.removeMessages(PLAY_SONG); + playerHandler.obtainMessage(PLAY_SONG, position, 0).sendToTarget(); + } + + private void playSongAtImpl(int position) { + if (openTrackAndPrepareNextAt(position)) { + play(); + } else { + Toast.makeText(this, getResources().getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show(); + } + } + + public void pause() { + pausedByTransientLossOfFocus = false; + if (playback.isPlaying()) { + playback.pause(); + notifyChange(PLAY_STATE_CHANGED); + } + } + + public void play() { + synchronized (this) { + if (requestFocus()) { + if (!playback.isPlaying()) { + if (!playback.isInitialized()) { + playSongAt(getPosition()); + } else { + playback.start(); + if (!becomingNoisyReceiverRegistered) { + registerReceiver(becomingNoisyReceiver, becomingNoisyReceiverIntentFilter); + becomingNoisyReceiverRegistered = true; + } + if (notHandledMetaChangedForCurrentTrack) { + handleChangeInternal(META_CHANGED); + notHandledMetaChangedForCurrentTrack = false; + } + notifyChange(PLAY_STATE_CHANGED); + + // fixes a bug where the volume would stay ducked because the AudioManager.AUDIOFOCUS_GAIN event is not sent + playerHandler.removeMessages(DUCK); + playerHandler.sendEmptyMessage(UNDUCK); + } + } + } else { + Toast.makeText(this, getResources().getString(R.string.audio_focus_denied), Toast.LENGTH_SHORT).show(); + } + } + } + + public void playSongs(ArrayList songs, int shuffleMode) { + if (songs != null && !songs.isEmpty()) { + if (shuffleMode == SHUFFLE_MODE_SHUFFLE) { + int startPosition = 0; + if (!songs.isEmpty()) { + startPosition = new Random().nextInt(songs.size()); + } + openQueue(songs, startPosition, false); + setShuffleMode(shuffleMode); + } else { + openQueue(songs, 0, false); + } + play(); + } else { + Toast.makeText(getApplicationContext(), R.string.playlist_is_empty, Toast.LENGTH_LONG).show(); + } + } + + public void playPreviousSong(boolean force) { + playSongAt(getPreviousPosition(force)); + } + + public void back(boolean force) { + if (getSongProgressMillis() > 2000) { + seek(0); + } else { + playPreviousSong(force); + } + } + + public int getPreviousPosition(boolean force) { + int newPosition = getPosition() - 1; + switch (repeatMode) { + case REPEAT_MODE_ALL: + if (newPosition < 0) { + newPosition = getPlayingQueue().size() - 1; + } + break; + case REPEAT_MODE_THIS: + if (force) { + if (newPosition < 0) { + newPosition = getPlayingQueue().size() - 1; + } + } else { + newPosition = getPosition(); + } + break; + default: + case REPEAT_MODE_NONE: + if (newPosition < 0) { + newPosition = 0; + } + break; + } + return newPosition; + } + + public int getSongProgressMillis() { + return playback.position(); + } + + public int getSongDurationMillis() { + return playback.duration(); + } + + public long getQueueDurationMillis(int position) { + long duration = 0; + for (int i = position + 1; i < playingQueue.size(); i++) + duration += playingQueue.get(i).duration; + return duration; + } + + public int seek(int millis) { + synchronized (this) { + try { + int newPosition = playback.seek(millis); + throttledSeekHandler.notifySeek(); + return newPosition; + } catch (Exception e) { + return -1; + } + } + } + + public void cycleRepeatMode() { + switch (getRepeatMode()) { + case REPEAT_MODE_NONE: + setRepeatMode(REPEAT_MODE_ALL); + break; + case REPEAT_MODE_ALL: + setRepeatMode(REPEAT_MODE_THIS); + break; + default: + setRepeatMode(REPEAT_MODE_NONE); + break; + } + } + + public void toggleShuffle() { + if (getShuffleMode() == SHUFFLE_MODE_NONE) { + setShuffleMode(SHUFFLE_MODE_SHUFFLE); + } else { + setShuffleMode(SHUFFLE_MODE_NONE); + } + } + + public int getShuffleMode() { + return shuffleMode; + } + + public void setShuffleMode(final int shuffleMode) { + PreferenceManager.getDefaultSharedPreferences(this).edit() + .putInt(SAVED_SHUFFLE_MODE, shuffleMode) + .apply(); + switch (shuffleMode) { + case SHUFFLE_MODE_SHUFFLE: + this.shuffleMode = shuffleMode; + ShuffleHelper.makeShuffleList(this.getPlayingQueue(), getPosition()); + position = 0; + break; + case SHUFFLE_MODE_NONE: + this.shuffleMode = shuffleMode; + int currentSongId = getCurrentSong().id; + playingQueue = new ArrayList<>(originalPlayingQueue); + int newPosition = 0; + for (Song song : getPlayingQueue()) { + if (song.id == currentSongId) { + newPosition = getPlayingQueue().indexOf(song); + } + } + position = newPosition; + break; + } + handleAndSendChangeInternal(SHUFFLE_MODE_CHANGED); + notifyChange(QUEUE_CHANGED); + } + + private void notifyChange(@NonNull final String what) { + handleAndSendChangeInternal(what); + sendPublicIntent(what); + } + + private void handleAndSendChangeInternal(@NonNull final String what) { + handleChangeInternal(what); + sendChangeInternal(what); + } + + // to let other apps know whats playing. i.E. last.fm (scrobbling) or musixmatch + private void sendPublicIntent(@NonNull final String what) { + final Intent intent = new Intent(what.replace(RETRO_MUSIC_PACKAGE_NAME, MUSIC_PACKAGE_NAME)); + + final Song song = getCurrentSong(); + + intent.putExtra("id", song.id); + + intent.putExtra("artist", song.artistName); + intent.putExtra("album", song.albumName); + intent.putExtra("track", song.title); + + intent.putExtra("duration", song.duration); + intent.putExtra("position", (long) getSongProgressMillis()); + + intent.putExtra("playing", isPlaying()); + + intent.putExtra("scrobbling_source", RETRO_MUSIC_PACKAGE_NAME); + + sendStickyBroadcast(intent); + + } + + private void sendChangeInternal(final String what) { + sendBroadcast(new Intent(what)); + appWidgetBig.notifyChange(this, what); + appWidgetClassic.notifyChange(this, what); + appWidgetSmall.notifyChange(this, what); + appWidgetCard.notifyChange(this, what); + } + + private void handleChangeInternal(@NonNull final String what) { + switch (what) { + case PLAY_STATE_CHANGED: + updateNotification(); + updateMediaSessionPlaybackState(); + final boolean isPlaying = isPlaying(); + if (!isPlaying && getSongProgressMillis() > 0) { + savePositionInTrack(); + } + songPlayCountHelper.notifyPlayStateChanged(isPlaying); + break; + case META_CHANGED: + updateNotification(); + updateMediaSessionMetaData(); + savePosition(); + savePositionInTrack(); + final Song currentSong = getCurrentSong(); + HistoryStore.getInstance(this).addSongId(currentSong.id); + if (songPlayCountHelper.shouldBumpPlayCount()) { + SongPlayCountStore.getInstance(this).bumpPlayCount(songPlayCountHelper.getSong().id); + } + songPlayCountHelper.notifySongChanged(currentSong); + break; + case QUEUE_CHANGED: + updateMediaSessionMetaData(); // because playing queue size might have changed + saveState(); + if (playingQueue.size() > 0) { + prepareNext(); + } else { + playingNotification.stop(); + } + break; + } + } + + public int getAudioSessionId() { + return playback.getAudioSessionId(); + } + + public MediaSessionCompat getMediaSession() { + return mediaSession; + } + + public void releaseWakeLock() { + if (wakeLock.isHeld()) { + wakeLock.release(); + } + } + + public void acquireWakeLock(long milli) { + wakeLock.acquire(milli); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + switch (key) { + case PreferenceUtil.GAPLESS_PLAYBACK: + if (sharedPreferences.getBoolean(key, false)) { + prepareNext(); + } else { + playback.setNextDataSource(null); + } + break; + case PreferenceUtil.ALBUM_ART_ON_LOCKSCREEN: + case PreferenceUtil.BLURRED_ALBUM_ART: + updateMediaSessionMetaData(); + break; + case PreferenceUtil.COLORED_NOTIFICATION: + case PreferenceUtil.DOMINANT_COLOR: + updateNotification(); + break; + case PreferenceUtil.CLASSIC_NOTIFICATION: + initNotification(); + updateNotification(); + break; + case PreferenceUtil.TOGGLE_HEADSET: + registerHeadsetEvents(); + break; + } + } + + private void registerHeadsetEvents() { + if (!headsetReceiverRegistered && PreferenceUtil.getInstance(this).getHeadsetPlugged()) { + registerReceiver(headsetReceiver, headsetReceiverIntentFilter); + headsetReceiverRegistered = true; + } + } + + @Override + public void onTrackWentToNext() { + playerHandler.sendEmptyMessage(TRACK_WENT_TO_NEXT); + } + + @Override + public void onTrackEnded() { + acquireWakeLock(30000); + playerHandler.sendEmptyMessage(TRACK_ENDED); + } + + private static final class QueueSaveHandler extends Handler { + @NonNull + private final WeakReference mService; + + QueueSaveHandler(final MusicService service, @NonNull final Looper looper) { + super(looper); + mService = new WeakReference<>(service); + } + + @Override + public void handleMessage(@NonNull Message msg) { + final MusicService service = mService.get(); + switch (msg.what) { + case SAVE_QUEUES: + service.saveQueuesImpl(); + break; + } + } + } + + private static final class PlaybackHandler extends Handler { + @NonNull + private final WeakReference mService; + private float currentDuckVolume = 1.0f; + + PlaybackHandler(final MusicService service, @NonNull final Looper looper) { + super(looper); + mService = new WeakReference<>(service); + } + + @Override + public void handleMessage(@NonNull final Message msg) { + final MusicService service = mService.get(); + if (service == null) { + return; + } + + switch (msg.what) { + case DUCK: + if (PreferenceUtil.getInstance(service).audioDucking()) { + currentDuckVolume -= .05f; + if (currentDuckVolume > .2f) { + sendEmptyMessageDelayed(DUCK, 10); + } else { + currentDuckVolume = .2f; + } + } else { + currentDuckVolume = 1f; + } + service.playback.setVolume(currentDuckVolume); + break; + + case UNDUCK: + if (PreferenceUtil.getInstance(service).audioDucking()) { + currentDuckVolume += .03f; + if (currentDuckVolume < 1f) { + sendEmptyMessageDelayed(UNDUCK, 10); + } else { + currentDuckVolume = 1f; + } + } else { + currentDuckVolume = 1f; + } + service.playback.setVolume(currentDuckVolume); + break; + + case TRACK_WENT_TO_NEXT: + if (service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) { + service.pause(); + service.seek(0); + } else { + service.position = service.nextPosition; + service.prepareNextImpl(); + service.notifyChange(META_CHANGED); + } + break; + + case TRACK_ENDED: + if (service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) { + service.notifyChange(PLAY_STATE_CHANGED); + service.seek(0); + } else { + service.playNextSong(false); + } + sendEmptyMessage(RELEASE_WAKELOCK); + break; + + case RELEASE_WAKELOCK: + service.releaseWakeLock(); + break; + + case PLAY_SONG: + service.playSongAtImpl(msg.arg1); + break; + + case SET_POSITION: + service.openTrackAndPrepareNextAt(msg.arg1); + service.notifyChange(PLAY_STATE_CHANGED); + break; + + case PREPARE_NEXT: + service.prepareNextImpl(); + break; + + case RESTORE_QUEUES: + service.restoreQueuesAndPositionIfNecessary(); + break; + + case FOCUS_CHANGE: + switch (msg.arg1) { + case AudioManager.AUDIOFOCUS_GAIN: + if (!service.isPlaying() && service.pausedByTransientLossOfFocus) { + service.play(); + service.pausedByTransientLossOfFocus = false; + } + removeMessages(DUCK); + sendEmptyMessage(UNDUCK); + break; + + case AudioManager.AUDIOFOCUS_LOSS: + // Lost focus for an unbounded amount of time: stop playback and release media playback + service.pause(); + break; + + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: + // Lost focus for a short time, but we have to stop + // playback. We don't release the media playback because playback + // is likely to resume + boolean wasPlaying = service.isPlaying(); + service.pause(); + service.pausedByTransientLossOfFocus = wasPlaying; + break; + + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: + // Lost focus for a short time, but it's ok to keep playing + // at an attenuated level + removeMessages(UNDUCK); + sendEmptyMessage(DUCK); + break; + } + break; + } + } + } + + private static class SongPlayCountHelper { + public static final String TAG = SongPlayCountHelper.class.getSimpleName(); + + private StopWatch stopWatch = new StopWatch(); + private Song song = Song.EMPTY_SONG; + + public Song getSong() { + return song; + } + + boolean shouldBumpPlayCount() { + return song.duration * 0.5d < stopWatch.getElapsedTime(); + } + + void notifySongChanged(Song song) { + synchronized (this) { + stopWatch.reset(); + this.song = song; + } + } + + void notifyPlayStateChanged(boolean isPlaying) { + synchronized (this) { + if (isPlaying) { + stopWatch.start(); + } else { + stopWatch.pause(); + } + } + } + } + + public class MusicBinder extends Binder { + @NonNull + public MusicService getService() { + return MusicService.this; + } + } + + private class MediaStoreObserver extends ContentObserver implements Runnable { + // milliseconds to delay before calling refresh to aggregate events + private static final long REFRESH_DELAY = 500; + private Handler mHandler; + + MediaStoreObserver(Handler handler) { + super(handler); + mHandler = handler; + } + + @Override + public void onChange(boolean selfChange) { + // if a change is detected, remove any scheduled callback + // then post a new one. This is intended to prevent closely + // spaced events from generating multiple refresh calls + mHandler.removeCallbacks(this); + mHandler.postDelayed(this, REFRESH_DELAY); + } + + @Override + public void run() { + // actually call refresh when the delayed callback fires + // do not send a sticky broadcast here + handleAndSendChangeInternal(MEDIA_STORE_CHANGED); + } + } + + private class ThrottledSeekHandler implements Runnable { + // milliseconds to throttle before calling run() to aggregate events + private static final long THROTTLE = 500; + private Handler mHandler; + + ThrottledSeekHandler(Handler handler) { + mHandler = handler; + } + + void notifySeek() { + mHandler.removeCallbacks(this); + mHandler.postDelayed(this, THROTTLE); + } + + @Override + public void run() { + savePositionInTrack(); + sendPublicIntent(PLAY_STATE_CHANGED); // for musixmatch synced lyrics + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/service/WearBrowserService.java b/app/src/main/java/code/name/monkey/retromusic/service/WearBrowserService.java new file mode 100644 index 00000000..5bf23cfe --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/WearBrowserService.java @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2015 Naman Dwivedi + * + * 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 code.name.monkey.retromusic.service; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.Intent; +import android.media.MediaDescription; +import android.media.browse.MediaBrowser; +import android.media.session.MediaSession; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.service.media.MediaBrowserService; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.util.ArrayList; +import java.util.List; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.RetroUtil; + +/** + * @author Hemanth S (h4h13). + */ +@TargetApi(21) +public class WearBrowserService extends MediaBrowserService { + + public static final String MEDIA_ID_ROOT = "__ROOT__"; + public static final int TYPE_ARTIST = 0; + public static final int TYPE_ALBUM = 1; + public static final int TYPE_SONG = 2; + public static final int TYPE_PLAYLIST = 3; + public static final int TYPE_ARTIST_SONG_ALBUMS = 4; + public static final int TYPE_ALBUM_SONGS = 5; + public static final int TYPE_ARTIST_ALL_SONGS = 6; + public static final int TYPE_PLAYLIST_ALL_SONGS = 7; + + public static WearBrowserService sInstance; + MediaSession mSession; + private Context mContext; + private boolean mServiceStarted; + + public static WearBrowserService getInstance() { + return sInstance; + } + + @Override + public void onCreate() { + super.onCreate(); + sInstance = this; + mContext = this; + mSession = new MediaSession(this, "WearBrowserService"); + setSessionToken(mSession.getSessionToken()); + mSession.setCallback(new MediaSessionCallback()); + mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS); + + } + + @Override + public int onStartCommand(Intent startIntent, int flags, int startId) { + return START_STICKY; + } + + @Override + public void onDestroy() { + mServiceStarted = false; + mSession.release(); + } + + @Nullable + @Override + public BrowserRoot onGetRoot(@NonNull String s, int i, @Nullable Bundle bundle) { + return new BrowserRoot(MEDIA_ID_ROOT, null); + } + + @Override + public void onLoadChildren(@NonNull String parentId, @NonNull Result> result) { + result.detach(); + loadChildren(parentId, result); + } + + private void setSessionActive() { + if (!mServiceStarted) { + startService(new Intent(getApplicationContext(), WearBrowserService.class)); + mServiceStarted = true; + } + + if (!mSession.isActive()) { + mSession.setActive(true); + } + } + + private void setSessionInactive() { + if (mServiceStarted) { + stopSelf(); + mServiceStarted = false; + } + + if (mSession.isActive()) { + mSession.setActive(false); + } + } + + private void fillMediaItems(List mediaItems, String mediaId, + String title, Uri icon, String subTitle, int playableOrBrowsable) { + mediaItems.add(new MediaBrowser.MediaItem( + new MediaDescription.Builder() + .setMediaId(mediaId) + .setTitle(title) + .setIconUri(icon) + .setSubtitle(subTitle) + .build(), playableOrBrowsable + )); + } + + private void addMediaRoots(List mMediaRoot) { + mMediaRoot.add(new MediaBrowser.MediaItem( + new MediaDescription.Builder() + .setMediaId(Integer.toString(TYPE_ARTIST)) + .setTitle(getString(R.string.artists)) + .setIconUri(Uri.parse("android.resource://" + + "naman14.timber/drawable/ic_empty_music2")) + .setSubtitle(getString(R.string.artists)) + .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE + )); + + mMediaRoot.add(new MediaBrowser.MediaItem( + new MediaDescription.Builder() + .setMediaId(Integer.toString(TYPE_ALBUM)) + .setTitle(getString(R.string.albums)) + .setIconUri(Uri.parse("android.resource://" + + "naman14.timber/drawable/ic_empty_music2")) + .setSubtitle(getString(R.string.albums)) + .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE + )); + + mMediaRoot.add(new MediaBrowser.MediaItem( + new MediaDescription.Builder() + .setMediaId(Integer.toString(TYPE_SONG)) + .setTitle(getString(R.string.songs)) + .setIconUri(Uri.parse("android.resource://" + + "naman14.timber/drawable/ic_empty_music2")) + .setSubtitle(getString(R.string.songs)) + .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE + )); + + + mMediaRoot.add(new MediaBrowser.MediaItem( + new MediaDescription.Builder() + .setMediaId(Integer.toString(TYPE_PLAYLIST)) + .setTitle(getString(R.string.playlists)) + .setIconUri(Uri.parse("android.resource://" + + "naman14.timber/drawable/ic_empty_music2")) + .setSubtitle(getString(R.string.playlists)) + .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE + )); + + } + + private void loadChildren(final String parentId, final Result> result) { + + final List mediaItems = new ArrayList<>(); + + new AsyncTask() { + @Override + protected Void doInBackground(final Void... unused) { + + if (parentId.equals(MEDIA_ID_ROOT)) { + addMediaRoots(mediaItems); + } else { + switch (Integer.parseInt(Character.toString(parentId.charAt(0)))) { + /*case TYPE_ARTIST: + List artistList = ArtistLoader.getAllArtists(mContext); + for (Artist artist : artistList) { + String albumNmber = TimberUtils.makeLabel(mContext, R.plurals.Nalbums, artist.albumCount); + String songCount = TimberUtils.makeLabel(mContext, R.plurals.Nsongs, artist.songCount); + fillMediaItems(mediaItems, Integer.toString(TYPE_ARTIST_SONG_ALBUMS) + Long.toString(artist.id), artist.name, Uri.parse("android.resource://" + + "naman14.timber/drawable/ic_empty_music2"), TimberUtils.makeCombinedString(mContext, albumNmber, songCount), MediaBrowser.MediaItem.FLAG_BROWSABLE); + } + break; + case TYPE_ALBUM: + List albumList = AlbumLoader.getAllAlbums(mContext); + for (Album album : albumList) { + fillMediaItems(mediaItems, Integer.toString(TYPE_ALBUM_SONGS) + Long.toString(album.id), album.title, TimberUtils.getAlbumArtUri(album.id), album.artistName, MediaBrowser.MediaItem.FLAG_BROWSABLE); + } + break;*/ + case TYPE_SONG: + List songList = SongLoader.getAllSongs(mContext).blockingFirst(); + for (Song song : songList) { + fillMediaItems(mediaItems, String.valueOf(song.id), song.title, RetroUtil.getAlbumArtUri(song.albumId), song.artistName, MediaBrowser.MediaItem.FLAG_PLAYABLE); + } + break; + /* case TYPE_ALBUM_SONGS: + List albumSongList = AlbumSongLoader.getSongsForAlbum(mContext, Long.parseLong(parentId.substring(1))); + for (Song song : albumSongList) { + fillMediaItems(mediaItems, String.valueOf(song.id), song.title, TimberUtils.getAlbumArtUri(song.albumId), song.artistName, MediaBrowser.MediaItem.FLAG_PLAYABLE); + } + break; + case TYPE_ARTIST_SONG_ALBUMS: + fillMediaItems(mediaItems, Integer.toString(TYPE_ARTIST_ALL_SONGS) + Long.parseLong(parentId.substring(1)), "All songs", Uri.parse("android.resource://" + + "naman14.timber/drawable/ic_empty_music2"), "All songs by artist", MediaBrowser.MediaItem.FLAG_BROWSABLE); + List artistAlbums = ArtistAlbumLoader.getAlbumsForArtist(mContext, Long.parseLong(parentId.substring(1))); + for (Album album : artistAlbums) { + String songCount = TimberUtils.makeLabel(mContext, R.plurals.Nsongs, album.songCount); + fillMediaItems(mediaItems, Integer.toString(TYPE_ALBUM_SONGS) + Long.toString(album.id), album.title, TimberUtils.getAlbumArtUri(album.id), songCount, MediaBrowser.MediaItem.FLAG_BROWSABLE); + + } + break; + case TYPE_ARTIST_ALL_SONGS: + List artistSongs = ArtistSongLoader.getSongsForArtist(mContext, Long.parseLong(parentId.substring(1))); + for (Song song : artistSongs) { + fillMediaItems(mediaItems, String.valueOf(song.id), song.title, TimberUtils.getAlbumArtUri(song.albumId), song.albumName, MediaBrowser.MediaItem.FLAG_PLAYABLE); + } + break; + case TYPE_PLAYLIST: + List playlistList = PlaylistLoader.getPlaylists(mContext, false); + for (Playlist playlist : playlistList) { + String songCount = TimberUtils.makeLabel(mContext, R.plurals.Nsongs, playlist.songCount); + fillMediaItems(mediaItems, Integer.toString(TYPE_PLAYLIST_ALL_SONGS) + Long.toString(playlist.id), playlist.name, + Uri.parse("android.resource://" + + "naman14.timber/drawable/ic_empty_music2"), songCount, MediaBrowser.MediaItem.FLAG_BROWSABLE); + } + break; + case TYPE_PLAYLIST_ALL_SONGS: + List playlistSongs = PlaylistSongLoader.getSongsInPlaylist(mContext, Long.parseLong(parentId.substring(1))); + for (Song song : playlistSongs) { + fillMediaItems(mediaItems, String.valueOf(song.id), song.title, TimberUtils.getAlbumArtUri(song.albumId), song.albumName, MediaBrowser.MediaItem.FLAG_PLAYABLE); + } + break;*/ + + } + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + result.sendResult(mediaItems); + } + }.execute(); + + } + + private final class MediaSessionCallback extends MediaSession.Callback { + + @Override + public void onPlay() { + setSessionActive(); + } + + @Override + public void onSeekTo(long position) { + + } + + @Override + public void onPlayFromMediaId(final String mediaId, Bundle extras) { + long songId = Long.parseLong(mediaId); + setSessionActive(); + ArrayList songs = new ArrayList<>(); + songs.add(SongLoader.getSong(mContext, Integer.parseInt(mediaId)).blockingFirst()); + MusicPlayerRemote.openQueue(songs, 0, true); + } + + @Override + public void onPause() { + + } + + @Override + public void onStop() { + setSessionInactive(); + } + + @Override + public void onSkipToNext() { + + } + + @Override + public void onSkipToPrevious() { + + } + + @Override + public void onFastForward() { + + } + + @Override + public void onRewind() { + + } + + @Override + public void onCustomAction(String action, Bundle extras) { + + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/service/daydream/RetroMusicAlbums.java b/app/src/main/java/code/name/monkey/retromusic/service/daydream/RetroMusicAlbums.java new file mode 100644 index 00000000..c42dae27 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/daydream/RetroMusicAlbums.java @@ -0,0 +1,186 @@ +package code.name.monkey.retromusic.service.daydream; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.service.dreams.DreamService; +import android.support.transition.TransitionManager; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; +import io.reactivex.Observable; +import io.reactivex.ObservableSource; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.functions.Function; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by hemanths on 25/09/17. + */ + +public class RetroMusicAlbums extends DreamService { + @BindView(R.id.recycler_view) + RecyclerView mRecyclerView; + @BindView(R.id.title) + TextView mTitle; + @BindView(R.id.text) + TextView mText; + @BindView(R.id.title_container) + ViewGroup mViewGroup; + + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null) { + return; + } + String artist = intent.getStringExtra("artist"); + String track = intent.getStringExtra("track"); + if (mViewGroup != null) { + mViewGroup.setVisibility(View.VISIBLE); + TransitionManager.beginDelayedTransition(mViewGroup); + if (mTitle != null) { + mTitle.setText(track); + } + if (mText != null) { + mText.setText(artist); + } + } + + } + }; + private Unbinder unbinder; + private CompositeDisposable mDisposable; + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + View view = LayoutInflater.from(this).inflate(R.layout.dream_service, null); + setContentView(view); + unbinder = ButterKnife.bind(this, view); + + mRecyclerView.setItemAnimator(new DefaultItemAnimator()); + GridLayoutManager layoutManager = new GridLayoutManager(this, 4, LinearLayoutManager.VERTICAL, false); + mRecyclerView.setLayoutManager(layoutManager); + + + mDisposable.add(getPlayingQueue() + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .flatMap((Function, ObservableSource>>) songs -> Observable.create(e -> { + if (songs.isEmpty()) { + e.onNext(SongLoader.getAllSongs(RetroMusicAlbums.this).blockingFirst()); + } else { + e.onNext(songs); + } + e.onComplete(); + })) + .subscribe(songs -> { + if (songs.size() > 0) { + ImagesAdapter imagesAdapter = new ImagesAdapter(songs); + mRecyclerView.setAdapter(imagesAdapter); + } + })); + + } + + @Override + public void onCreate() { + super.onCreate(); + setInteractive(true); + setFullscreen(true); + + mDisposable = new CompositeDisposable(); + + IntentFilter iF = new IntentFilter(); + iF.addAction("com.android.music.musicservicecommand"); + iF.addAction("com.android.music.metachanged"); + registerReceiver(mBroadcastReceiver, iF); + + } + + @Override + public void onDestroy() { + super.onDestroy(); + unbinder.unbind(); + mDisposable.clear(); + unregisterReceiver(mBroadcastReceiver); + } + + private Observable> getPlayingQueue() { + return Observable.just(MusicPlayerRemote.getPlayingQueue()); + } + + class ImagesAdapter extends RecyclerView.Adapter { + + private final ArrayList list; + + public ImagesAdapter(ArrayList songs) { + this.list = songs; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + return new ViewHolder(LayoutInflater.from(getApplicationContext()) + .inflate(R.layout.image, viewGroup, false)); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int i) { + Song song = list.get(i); + SongGlideRequest.Builder.from(Glide.with(getApplicationContext()), song) + .checkIgnoreMediaStore(getApplicationContext()) + .generatePalette(getApplicationContext()).build() + .override(400, 400) + .into(new RetroMusicColoredTarget(holder.image) { + + @Override + public void onColorReady(int color) { + + } + }); + + } + + @Override + public int getItemCount() { + return list.size(); + } + + class ViewHolder extends MediaEntryViewHolder { + + public ViewHolder(View itemView) { + super(itemView); + } + + @Override + public void onClick(View v) { + super.onClick(v); + MusicPlayerRemote.openQueue(list, getAdapterPosition(), true); + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotification.java b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotification.java new file mode 100644 index 00000000..b444af22 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotification.java @@ -0,0 +1,80 @@ +package code.name.monkey.retromusic.service.notification; + + +import static android.content.Context.NOTIFICATION_SERVICE; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.os.Build; +import android.support.annotation.RequiresApi; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.service.MusicService; + + +public abstract class PlayingNotification { + + static final String NOTIFICATION_CHANNEL_ID = "playing_notification"; + private static final int NOTIFICATION_ID = 1; + private static final int NOTIFY_MODE_FOREGROUND = 1; + private static final int NOTIFY_MODE_BACKGROUND = 0; + protected MusicService service; + boolean stopped; + private int notifyMode = NOTIFY_MODE_BACKGROUND; + private NotificationManager notificationManager; + + public synchronized void init(MusicService service) { + this.service = service; + notificationManager = (NotificationManager) service.getSystemService(NOTIFICATION_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + createNotificationChannel(); + } + } + + public abstract void update(); + + public synchronized void stop() { + stopped = true; + service.stopForeground(true); + notificationManager.cancel(NOTIFICATION_ID); + } + + void updateNotifyModeAndPostNotification(Notification notification) { + int newNotifyMode; + if (service.isPlaying()) { + newNotifyMode = NOTIFY_MODE_FOREGROUND; + } else { + newNotifyMode = NOTIFY_MODE_BACKGROUND; + } + + if (notifyMode != newNotifyMode && newNotifyMode == NOTIFY_MODE_BACKGROUND) { + service.stopForeground(false); + } + + if (newNotifyMode == NOTIFY_MODE_FOREGROUND) { + service.startForeground(NOTIFICATION_ID, notification); + } else if (newNotifyMode == NOTIFY_MODE_BACKGROUND) { + notificationManager.notify(NOTIFICATION_ID, notification); + } + + notifyMode = newNotifyMode; + } + + @RequiresApi(26) + private void createNotificationChannel() { + NotificationChannel notificationChannel = notificationManager + .getNotificationChannel(NOTIFICATION_CHANNEL_ID); + if (notificationChannel == null) { + notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, + service.getString(R.string.playing_notification_name), + NotificationManager.IMPORTANCE_LOW); + notificationChannel + .setDescription(service.getString(R.string.playing_notification_description)); + notificationChannel.enableLights(false); + notificationChannel.enableVibration(false); + notificationChannel.setShowBadge(false); + + notificationManager.createNotificationChannel(notificationChannel); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl.java b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl.java new file mode 100644 index 00000000..cd424700 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl.java @@ -0,0 +1,225 @@ +package code.name.monkey.retromusic.service.notification; + + +import android.app.Notification; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.support.v4.app.NotificationCompat; +import android.text.TextUtils; +import android.view.View; +import android.widget.RemoteViews; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.target.Target; + +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.activities.MainActivity; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroColorUtil; +import code.name.monkey.retromusic.util.RetroUtil; + +import static code.name.monkey.retromusic.Constants.ACTION_QUIT; +import static code.name.monkey.retromusic.Constants.ACTION_REWIND; +import static code.name.monkey.retromusic.Constants.ACTION_SKIP; +import static code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE; +import static code.name.monkey.retromusic.util.RetroUtil.createBitmap; + +public class PlayingNotificationImpl extends PlayingNotification { + + private Target target; + + + @Override + public synchronized void update() { + stopped = false; + + final Song song = service.getCurrentSong(); + + final boolean isPlaying = service.isPlaying(); + + final RemoteViews notificationLayout = new RemoteViews(service.getPackageName(), + R.layout.notification); + final RemoteViews notificationLayoutBig = new RemoteViews(service.getPackageName(), + R.layout.notification_big); + + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) { + notificationLayout.setViewVisibility(R.id.media_titles, View.INVISIBLE); + } else { + notificationLayout.setViewVisibility(R.id.media_titles, View.VISIBLE); + notificationLayout.setTextViewText(R.id.title, song.title); + notificationLayout.setTextViewText(R.id.text, song.artistName); + } + + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName) && TextUtils + .isEmpty(song.albumName)) { + notificationLayoutBig.setViewVisibility(R.id.media_titles, View.INVISIBLE); + } else { + notificationLayoutBig.setViewVisibility(R.id.media_titles, View.VISIBLE); + notificationLayoutBig.setTextViewText(R.id.title, song.title); + notificationLayoutBig.setTextViewText(R.id.text, song.artistName); + notificationLayoutBig.setTextViewText(R.id.text2, song.albumName); + } + + linkButtons(notificationLayout, notificationLayoutBig); + + Intent action = new Intent(service, MainActivity.class); + action.putExtra("expand", true); + action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + + final PendingIntent clickIntent = PendingIntent + .getActivity(service, 0, action, PendingIntent.FLAG_UPDATE_CURRENT); + final PendingIntent deleteIntent = buildPendingIntent(service, ACTION_QUIT, null); + + final Notification notification = new NotificationCompat.Builder(service, + NOTIFICATION_CHANNEL_ID) + .setSmallIcon(R.drawable.ic_notification) + .setContentIntent(clickIntent) + .setDeleteIntent(deleteIntent) + .setCategory(NotificationCompat.CATEGORY_SERVICE) + .setPriority(NotificationCompat.PRIORITY_MAX) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setContent(notificationLayout) + .setCustomBigContentView(notificationLayoutBig) + .setOngoing(isPlaying) + .build(); + + final int bigNotificationImageSize = service.getResources() + .getDimensionPixelSize(R.dimen.notification_big_image_size); + service.runOnUiThread(new Runnable() { + @Override + public void run() { + if (target != null) { + Glide.clear(target); + } + target = SongGlideRequest.Builder.from(Glide.with(service), song) + .checkIgnoreMediaStore(service) + .generatePalette(service).build() + .into(new SimpleTarget(bigNotificationImageSize, + bigNotificationImageSize) { + @Override + public void onResourceReady(BitmapPaletteWrapper resource, + GlideAnimation glideAnimation) { + update(resource.getBitmap(), + PreferenceUtil.getInstance(service).isDominantColor() ? + RetroColorUtil.getDominantColor(resource.getBitmap(), Color.TRANSPARENT) : + RetroColorUtil.getColor(resource.getPalette(), Color.TRANSPARENT)); + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + update(null, Color.WHITE); + } + + private void update(@Nullable Bitmap bitmap, int bgColor) { + if (bitmap != null) { + notificationLayout.setImageViewBitmap(R.id.image, bitmap); + notificationLayoutBig.setImageViewBitmap(R.id.image, bitmap); + } else { + notificationLayout.setImageViewResource(R.id.image, R.drawable.default_album_art); + notificationLayoutBig + .setImageViewResource(R.id.image, R.drawable.default_album_art); + } + + if (!PreferenceUtil.getInstance(service).coloredNotification()) { + bgColor = Color.WHITE; + } + setBackgroundColor(bgColor); + setNotificationContent(ColorUtil.isColorLight(bgColor)); + + if (stopped) { + return; // notification has been stopped before loading was finished + } + updateNotifyModeAndPostNotification(notification); + } + + private void setBackgroundColor(int color) { + notificationLayout.setInt(R.id.root, "setBackgroundColor", color); + notificationLayoutBig.setInt(R.id.root, "setBackgroundColor", color); + } + + private void setNotificationContent(boolean dark) { + int primary = MaterialValueHelper.getPrimaryTextColor(service, dark); + int secondary = MaterialValueHelper.getSecondaryTextColor(service, dark); + + Bitmap close = createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_close_white_24dp, primary), + 1.5f); + Bitmap prev = createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, + primary), 1.5f); + Bitmap next = createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, + primary), 1.5f); + Bitmap playPause = createBitmap(RetroUtil.getTintedVectorDrawable(service, + isPlaying ? R.drawable.ic_pause_white_24dp + : R.drawable.ic_play_arrow_white_24dp, primary), 1.5f); + + notificationLayout.setTextColor(R.id.title, primary); + notificationLayout.setTextColor(R.id.text, secondary); + notificationLayout.setImageViewBitmap(R.id.action_prev, prev); + notificationLayout.setImageViewBitmap(R.id.action_next, next); + notificationLayout.setImageViewBitmap(R.id.action_play_pause, playPause); + + notificationLayoutBig.setTextColor(R.id.title, primary); + notificationLayoutBig.setTextColor(R.id.text, secondary); + notificationLayoutBig.setTextColor(R.id.text2, secondary); + + notificationLayoutBig.setImageViewBitmap(R.id.action_quit, close); + notificationLayoutBig.setImageViewBitmap(R.id.action_prev, prev); + notificationLayoutBig.setImageViewBitmap(R.id.action_next, next); + notificationLayoutBig.setImageViewBitmap(R.id.action_play_pause, playPause); + + } + }); + } + }); + } + + private void linkButtons(final RemoteViews notificationLayout, + final RemoteViews notificationLayoutBig) { + PendingIntent pendingIntent; + + final ComponentName serviceName = new ComponentName(service, MusicService.class); + + // Previous track + pendingIntent = buildPendingIntent(service, ACTION_REWIND, serviceName); + notificationLayout.setOnClickPendingIntent(R.id.action_prev, pendingIntent); + notificationLayoutBig.setOnClickPendingIntent(R.id.action_prev, pendingIntent); + + // Play and pause + pendingIntent = buildPendingIntent(service, ACTION_TOGGLE_PAUSE, serviceName); + notificationLayout.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent); + notificationLayoutBig.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent); + + // Next track + pendingIntent = buildPendingIntent(service, ACTION_SKIP, serviceName); + notificationLayout.setOnClickPendingIntent(R.id.action_next, pendingIntent); + notificationLayoutBig.setOnClickPendingIntent(R.id.action_next, pendingIntent); + + // Close + pendingIntent = buildPendingIntent(service, ACTION_QUIT, serviceName); + notificationLayoutBig.setOnClickPendingIntent(R.id.action_quit, pendingIntent); + } + + private PendingIntent buildPendingIntent(Context context, final String action, + final ComponentName serviceName) { + Intent intent = new Intent(action); + intent.setComponent(serviceName); + return PendingIntent.getService(context, 0, intent, 0); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl24.java b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl24.java new file mode 100644 index 00000000..c0360102 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl24.java @@ -0,0 +1,146 @@ +package code.name.monkey.retromusic.service.notification; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.v4.app.NotificationCompat; +import android.support.v4.media.app.NotificationCompat.MediaStyle; +import android.text.Html; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; + +import code.name.monkey.retromusic.Constants; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.activities.MainActivity; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroColorUtil; + +import static code.name.monkey.retromusic.Constants.ACTION_QUIT; +import static code.name.monkey.retromusic.Constants.ACTION_REWIND; +import static code.name.monkey.retromusic.Constants.ACTION_SKIP; +import static code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE; + +public class PlayingNotificationImpl24 extends PlayingNotification { + + @Override + public synchronized void update() { + stopped = false; + + final Song song = service.getCurrentSong(); + final boolean isPlaying = service.isPlaying(); + + + final int playButtonResId = isPlaying ? R.drawable.ic_pause_white_24dp : + R.drawable.ic_play_arrow_white_24dp; + + Intent action = new Intent(service, MainActivity.class); + action.putExtra("expand", true); + action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + final PendingIntent clickIntent = PendingIntent + .getActivity(service, 0, action, PendingIntent.FLAG_UPDATE_CURRENT); + + final ComponentName serviceName = new ComponentName(service, MusicService.class); + Intent intent = new Intent(Constants.ACTION_QUIT); + intent.setComponent(serviceName); + final PendingIntent deleteIntent = PendingIntent.getService(service, 0, intent, 0); + + final int bigNotificationImageSize = service.getResources() + .getDimensionPixelSize(R.dimen.notification_big_image_size); + service.runOnUiThread(() -> SongGlideRequest.Builder.from(Glide.with(service), song) + .checkIgnoreMediaStore(service) + .generatePalette(service).build() + .into(new SimpleTarget(bigNotificationImageSize, + bigNotificationImageSize) { + @Override + public void onResourceReady(BitmapPaletteWrapper resource, + GlideAnimation glideAnimation) { + update(resource.getBitmap(), + PreferenceUtil.getInstance(RetroApplication.getInstance()).isDominantColor() ? + RetroColorUtil.getDominantColor(resource.getBitmap(), Color.TRANSPARENT) : + RetroColorUtil.getColor(resource.getPalette(), Color.TRANSPARENT)); + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + update(null, Color.TRANSPARENT); + } + + void update(Bitmap bitmap, int color) { + if (bitmap == null) { + bitmap = BitmapFactory + .decodeResource(service.getResources(), R.drawable.default_album_art); + } + NotificationCompat.Action playPauseAction = new NotificationCompat.Action( + playButtonResId, + service.getString(R.string.action_play_pause), + retrievePlaybackAction(ACTION_TOGGLE_PAUSE)); + + NotificationCompat.Action closeAction = new NotificationCompat.Action( + R.drawable.ic_close_white_24dp, + service.getString(R.string.close_notification), + retrievePlaybackAction(ACTION_QUIT)); + + NotificationCompat.Action previousAction = new NotificationCompat.Action( + R.drawable.ic_skip_previous_white_24dp, + service.getString(R.string.action_previous), + retrievePlaybackAction(ACTION_REWIND)); + + NotificationCompat.Action nextAction = new NotificationCompat.Action( + R.drawable.ic_skip_next_white_24dp, + service.getString(R.string.action_next), + retrievePlaybackAction(ACTION_SKIP)); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(service, + NOTIFICATION_CHANNEL_ID) + .setSmallIcon(R.drawable.ic_notification) + .setLargeIcon(bitmap) + .setContentIntent(clickIntent) + .setDeleteIntent(deleteIntent) + .setContentTitle(Html.fromHtml("" + song.title + "")) + .setContentText(song.artistName) + .setSubText(Html.fromHtml("" + song.albumName + "")) + .setOngoing(isPlaying) + .setShowWhen(false) + .addAction(previousAction) + .addAction(playPauseAction) + .addAction(nextAction) + .addAction(closeAction); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + builder.setStyle(new MediaStyle() + .setMediaSession(service.getMediaSession().getSessionToken()) + .setShowActionsInCompactView(0, 1, 2, 3, 4)) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC); + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O && PreferenceUtil + .getInstance(service).coloredNotification()) { + builder.setColor(color); + } + } + + if (stopped) { + return; // notification has been stopped before loading was finished + } + updateNotifyModeAndPostNotification(builder.build()); + } + })); + } + + private PendingIntent retrievePlaybackAction(final String action) { + final ComponentName serviceName = new ComponentName(service, MusicService.class); + Intent intent = new Intent(action); + intent.setComponent(serviceName); + return PendingIntent.getService(service, 0, intent, 0); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationOreo.java b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationOreo.java new file mode 100644 index 00000000..6a305c6c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationOreo.java @@ -0,0 +1,244 @@ +package code.name.monkey.retromusic.service.notification; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.support.v4.app.NotificationCompat; +import android.widget.RemoteViews; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.target.Target; + +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.activities.MainActivity; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroUtil; +import code.name.monkey.retromusic.util.color.MediaNotificationProcessor; + +import static code.name.monkey.retromusic.Constants.ACTION_QUIT; +import static code.name.monkey.retromusic.Constants.ACTION_REWIND; +import static code.name.monkey.retromusic.Constants.ACTION_SKIP; +import static code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE; +import static code.name.monkey.retromusic.util.RetroUtil.createBitmap; + +/** + * @author Hemanth S (h4h13). + */ +public class PlayingNotificationOreo extends PlayingNotification { + + private Target target; + + private RemoteViews getCombinedRemoteViews(boolean collapsed, Song song) { + RemoteViews remoteViews = new RemoteViews(service.getPackageName(), + collapsed ? R.layout.layout_notification_collapsed : R.layout.layout_notification_expanded); + + remoteViews.setTextViewText(R.id.appName, service.getString(R.string.app_name) + " • " + song.albumName); + remoteViews.setTextViewText(R.id.title, song.title); + remoteViews.setTextViewText(R.id.subtitle, song.artistName); + + TypedArray typedArray = service + .obtainStyledAttributes(new int[]{android.R.attr.selectableItemBackground}); + int selectableItemBackground = typedArray.getResourceId(0, 0); + typedArray.recycle(); + + remoteViews.setInt(R.id.content, "setBackgroundResource", selectableItemBackground); + + linkButtons(remoteViews); + + //setNotificationContent(remoteViews, ColorUtil.isColorLight(backgroundColor)); + return remoteViews; + } + + @Override + public void update() { + stopped = false; + final Song song = service.getCurrentSong(); + final boolean isPlaying = service.isPlaying(); + + final RemoteViews notificationLayout = getCombinedRemoteViews(true, song); + final RemoteViews notificationLayoutBig = getCombinedRemoteViews(false, song); + + Intent action = new Intent(service, MainActivity.class); + action.putExtra("expand", true); + action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + + final PendingIntent clickIntent = PendingIntent + .getActivity(service, 0, action, PendingIntent.FLAG_UPDATE_CURRENT); + final PendingIntent deleteIntent = buildPendingIntent(service, ACTION_QUIT, null); + + final NotificationCompat.Builder builder = new NotificationCompat.Builder(service, + NOTIFICATION_CHANNEL_ID) + .setSmallIcon(R.drawable.ic_notification) + .setContentIntent(clickIntent) + .setDeleteIntent(deleteIntent) + .setCategory(NotificationCompat.CATEGORY_SERVICE) + .setPriority(NotificationCompat.PRIORITY_MAX) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setCustomContentView(notificationLayout) + .setCustomBigContentView(notificationLayoutBig) + .setOngoing(isPlaying); + + final int bigNotificationImageSize = service.getResources() + .getDimensionPixelSize(R.dimen.notification_big_image_size); + service.runOnUiThread(new Runnable() { + @Override + public void run() { + if (target != null) { + Glide.clear(target); + } + target = SongGlideRequest.Builder.from(Glide.with(service), song) + .checkIgnoreMediaStore(service) + .generatePalette(service).build() + .into(new SimpleTarget(bigNotificationImageSize, + bigNotificationImageSize) { + @Override + public void onResourceReady(BitmapPaletteWrapper resource, + GlideAnimation glideAnimation) { + + MediaNotificationProcessor mediaNotificationProcessor = new MediaNotificationProcessor(service, service, new MediaNotificationProcessor.onColorThing() { + @Override + public void bothColor(int i, int i2) { + update(resource.getBitmap(), i, i2); + } + }); + mediaNotificationProcessor.processNotification(resource.getBitmap()); + + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + update(null, Color.WHITE, Color.BLACK); + } + + private void update(@Nullable Bitmap bitmap, int bgColor, int textColor) { + if (bitmap != null) { + notificationLayout.setImageViewBitmap(R.id.largeIcon, bitmap); + notificationLayoutBig.setImageViewBitmap(R.id.largeIcon, bitmap); + } else { + notificationLayout + .setImageViewResource(R.id.largeIcon, R.drawable.default_album_art); + notificationLayoutBig + .setImageViewResource(R.id.largeIcon, R.drawable.default_album_art); + } + + if (!PreferenceUtil.getInstance(service).coloredNotification()) { + bgColor = Color.WHITE; + } + setBackgroundColor(bgColor); + setNotificationContent(ColorUtil.isColorLight(bgColor)); + + if (stopped) { + return; // notification has been stopped before loading was finished + } + updateNotifyModeAndPostNotification(builder.build()); + } + + private void setBackgroundColor(int color) { + + notificationLayout.setInt(R.id.image, "setBackgroundColor", color); + notificationLayoutBig.setInt(R.id.image, "setBackgroundColor", color); + + notificationLayout.setInt(R.id.foregroundImage, "setColorFilter", color); + notificationLayoutBig.setInt(R.id.foregroundImage, "setColorFilter", color); + } + + private void setNotificationContent(boolean dark) { + int primary = MaterialValueHelper.getPrimaryTextColor(service, dark); + int secondary = MaterialValueHelper.getSecondaryTextColor(service, dark); + + Bitmap close = createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_close_white_24dp, primary), + 1.3f); + Bitmap prev = createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, + primary), 1.3f); + Bitmap next = createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, + primary), 1.3f); + Bitmap playPause = createBitmap(RetroUtil.getTintedVectorDrawable(service, + isPlaying ? R.drawable.ic_pause_white_24dp + : R.drawable.ic_play_arrow_white_24dp, primary), 1.3f); + + notificationLayout.setTextColor(R.id.title, primary); + notificationLayout.setTextColor(R.id.subtitle, secondary); + notificationLayout.setTextColor(R.id.appName, secondary); + + notificationLayout.setImageViewBitmap(R.id.action_prev, prev); + notificationLayout.setImageViewBitmap(R.id.action_next, next); + notificationLayout.setImageViewBitmap(R.id.action_play_pause, playPause); + + notificationLayoutBig.setTextColor(R.id.title, primary); + notificationLayoutBig.setTextColor(R.id.subtitle, secondary); + notificationLayoutBig.setTextColor(R.id.appName, secondary); + + notificationLayoutBig.setImageViewBitmap(R.id.action_quit, close); + notificationLayoutBig.setImageViewBitmap(R.id.action_prev, prev); + notificationLayoutBig.setImageViewBitmap(R.id.action_next, next); + notificationLayoutBig.setImageViewBitmap(R.id.action_play_pause, playPause); + + notificationLayout.setImageViewBitmap(R.id.smallIcon, + createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_notification, secondary), 0.6f)); + notificationLayoutBig.setImageViewBitmap(R.id.smallIcon, + createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_notification, secondary), 0.6f)); + + notificationLayout.setInt(R.id.arrow, "setColorFilter", secondary); + notificationLayoutBig.setInt(R.id.arrow, "setColorFilter", secondary); + + } + }); + } + }); + + if (stopped) { + return; // notification has been stopped before loading was finished + } + updateNotifyModeAndPostNotification(builder.build()); + } + + + private PendingIntent buildPendingIntent(Context context, final String action, + final ComponentName serviceName) { + Intent intent = new Intent(action); + intent.setComponent(serviceName); + return PendingIntent.getService(context, 0, intent, 0); + } + + + private void linkButtons(final RemoteViews notificationLayout) { + PendingIntent pendingIntent; + + final ComponentName serviceName = new ComponentName(service, MusicService.class); + + // Previous track + pendingIntent = buildPendingIntent(service, ACTION_REWIND, serviceName); + notificationLayout.setOnClickPendingIntent(R.id.action_prev, pendingIntent); + + // Play and pause + pendingIntent = buildPendingIntent(service, ACTION_TOGGLE_PAUSE, serviceName); + notificationLayout.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent); + + // Next track + pendingIntent = buildPendingIntent(service, ACTION_SKIP, serviceName); + notificationLayout.setOnClickPendingIntent(R.id.action_next, pendingIntent); + + // Close + pendingIntent = buildPendingIntent(service, ACTION_QUIT, serviceName); + notificationLayout.setOnClickPendingIntent(R.id.action_quit, pendingIntent); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.java b/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.java new file mode 100644 index 00000000..8863b36e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.java @@ -0,0 +1,43 @@ +package code.name.monkey.retromusic.service.playback; + +import android.support.annotation.Nullable; + + +public interface Playback { + + boolean setDataSource(String path); + + void setNextDataSource(@Nullable String path); + + void setCallbacks(PlaybackCallbacks callbacks); + + boolean isInitialized(); + + boolean start(); + + void stop(); + + void release(); + + boolean pause(); + + boolean isPlaying(); + + int duration(); + + int position(); + + int seek(int whereto); + + boolean setVolume(float vol); + + boolean setAudioSessionId(int sessionId); + + int getAudioSessionId(); + + interface PlaybackCallbacks { + void onTrackWentToNext(); + + void onTrackEnded(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/swipebtn/DimentionUtils.java b/app/src/main/java/code/name/monkey/retromusic/swipebtn/DimentionUtils.java new file mode 100755 index 00000000..587055a5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/swipebtn/DimentionUtils.java @@ -0,0 +1,13 @@ +package code.name.monkey.retromusic.swipebtn; + +import android.content.Context; + +final class DimentionUtils { + + private DimentionUtils() { + } + + static float convertPixelsToSp(float px, Context context) { + return px / context.getResources().getDisplayMetrics().scaledDensity; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/swipebtn/OnActiveListener.java b/app/src/main/java/code/name/monkey/retromusic/swipebtn/OnActiveListener.java new file mode 100755 index 00000000..429584ce --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/swipebtn/OnActiveListener.java @@ -0,0 +1,5 @@ +package code.name.monkey.retromusic.swipebtn; + +public interface OnActiveListener { + void onActive(); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/swipebtn/OnStateChangeListener.java b/app/src/main/java/code/name/monkey/retromusic/swipebtn/OnStateChangeListener.java new file mode 100755 index 00000000..c4adf4a2 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/swipebtn/OnStateChangeListener.java @@ -0,0 +1,5 @@ +package code.name.monkey.retromusic.swipebtn; + +public interface OnStateChangeListener { + void onStateChange(boolean active); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/swipebtn/SwipeButton.java b/app/src/main/java/code/name/monkey/retromusic/swipebtn/SwipeButton.java new file mode 100755 index 00000000..eaecc952 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/swipebtn/SwipeButton.java @@ -0,0 +1,486 @@ +package code.name.monkey.retromusic.swipebtn; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.support.v4.content.ContextCompat; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import code.name.monkey.retromusic.R; + +public class SwipeButton extends RelativeLayout { + + + private static final int ENABLED = 0; + private static final int DISABLED = 1; + private ImageView swipeButtonInner; + private float initialX; + private boolean active; + private TextView centerText; + private ViewGroup background; + private Drawable disabledDrawable; + private Drawable enabledDrawable; + private OnStateChangeListener onStateChangeListener; + private OnActiveListener onActiveListener; + private int collapsedWidth; + private int collapsedHeight; + + private LinearLayout layer; + private boolean trailEnabled = false; + private boolean hasActivationState; + + public SwipeButton(Context context) { + super(context); + + init(context, null, -1, -1); + } + + public SwipeButton(Context context, AttributeSet attrs) { + super(context, attrs); + + init(context, attrs, -1, -1); + } + + public SwipeButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + init(context, attrs, defStyleAttr, -1); + } + + @TargetApi(21) + public SwipeButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + + init(context, attrs, defStyleAttr, defStyleRes); + } + + public void setCenterTextColor(int color) { + if (centerText == null) { + return; + } + centerText.setTextColor(color); + } + + public boolean isActive() { + return active; + } + + public void setText(String text) { + centerText.setText(text); + } + + public void setBackground(Drawable drawable) { + background.setBackground(drawable); + } + + public ViewGroup getSwipeBackground() { + return background; + } + + public void setSlidingButtonBackground(Drawable drawable) { + background.setBackground(drawable); + } + + public void setDisabledDrawable(Drawable drawable) { + disabledDrawable = drawable; + + if (!active) { + swipeButtonInner.setImageDrawable(drawable); + } + } + + public void setButtonBackground(Drawable buttonBackground) { + if (buttonBackground != null) { + swipeButtonInner.setBackground(buttonBackground); + } + } + + public void setEnabledDrawable(Drawable drawable) { + enabledDrawable = drawable; + + if (active) { + swipeButtonInner.setImageDrawable(drawable); + } + } + + public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) { + this.onStateChangeListener = onStateChangeListener; + } + + public void setOnActiveListener(OnActiveListener onActiveListener) { + this.onActiveListener = onActiveListener; + } + + public void setInnerTextPadding(int left, int top, int right, int bottom) { + centerText.setPadding(left, top, right, bottom); + } + + public void setSwipeButtonPadding(int left, int top, int right, int bottom) { + swipeButtonInner.setPadding(left, top, right, bottom); + } + + public void setHasActivationState(boolean hasActivationState) { + this.hasActivationState = hasActivationState; + } + + private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + hasActivationState = true; + + background = new RelativeLayout(context); + + LayoutParams layoutParamsView = new LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + + layoutParamsView.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); + + addView(background, layoutParamsView); + + final TextView centerText = new TextView(context); + this.centerText = centerText; + centerText.setGravity(Gravity.CENTER); + + LayoutParams layoutParams = new LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + + layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); + + background.addView(centerText, layoutParams); + + final ImageView swipeButton = new ImageView(context); + this.swipeButtonInner = swipeButton; + + if (attrs != null && defStyleAttr == -1 && defStyleRes == -1) { + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SwipeButton, + defStyleAttr, defStyleRes); + + collapsedWidth = (int) typedArray.getDimension(R.styleable.SwipeButton_button_image_width, + ViewGroup.LayoutParams.WRAP_CONTENT); + collapsedHeight = (int) typedArray.getDimension(R.styleable.SwipeButton_button_image_height, + ViewGroup.LayoutParams.WRAP_CONTENT); + trailEnabled = typedArray.getBoolean(R.styleable.SwipeButton_button_trail_enabled, + false); + Drawable trailingDrawable = typedArray.getDrawable(R.styleable.SwipeButton_button_trail_drawable); + + Drawable backgroundDrawable = typedArray.getDrawable(R.styleable.SwipeButton_inner_text_background); + + if (backgroundDrawable != null) { + background.setBackground(backgroundDrawable); + } else { + background.setBackground(ContextCompat.getDrawable(context, R.drawable.shape_rounded_edit)); + } + + if (trailEnabled) { + layer = new LinearLayout(context); + + if (trailingDrawable != null) { + layer.setBackground(trailingDrawable); + } else { + layer.setBackground(typedArray.getDrawable(R.styleable.SwipeButton_button_background)); + } + + layer.setGravity(Gravity.START); + layer.setVisibility(View.GONE); + background.addView(layer, layoutParamsView); + } + + centerText.setText(typedArray.getText(R.styleable.SwipeButton_inner_text)); + centerText.setTextColor(typedArray.getColor(R.styleable.SwipeButton_inner_text_color, + Color.WHITE)); + + float textSize = DimentionUtils.convertPixelsToSp( + typedArray.getDimension(R.styleable.SwipeButton_inner_text_size, 0), context); + + if (textSize != 0) { + centerText.setTextSize(textSize); + } else { + centerText.setTextSize(12); + } + + disabledDrawable = typedArray.getDrawable(R.styleable.SwipeButton_button_image_disabled); + enabledDrawable = typedArray.getDrawable(R.styleable.SwipeButton_button_image_enabled); + float innerTextLeftPadding = typedArray.getDimension( + R.styleable.SwipeButton_inner_text_left_padding, 0); + float innerTextTopPadding = typedArray.getDimension( + R.styleable.SwipeButton_inner_text_top_padding, 0); + float innerTextRightPadding = typedArray.getDimension( + R.styleable.SwipeButton_inner_text_right_padding, 0); + float innerTextBottomPadding = typedArray.getDimension( + R.styleable.SwipeButton_inner_text_bottom_padding, 0); + + int initialState = typedArray.getInt(R.styleable.SwipeButton_initial_state, DISABLED); + + if (initialState == ENABLED) { + LayoutParams layoutParamsButton = new LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + + layoutParamsButton.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE); + layoutParamsButton.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE); + + swipeButton.setImageDrawable(enabledDrawable); + + addView(swipeButton, layoutParamsButton); + + active = true; + } else { + LayoutParams layoutParamsButton = new LayoutParams(collapsedWidth, collapsedHeight); + + layoutParamsButton.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE); + layoutParamsButton.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE); + + swipeButton.setImageDrawable(disabledDrawable); + + addView(swipeButton, layoutParamsButton); + + active = false; + } + + centerText.setPadding((int) innerTextLeftPadding, + (int) innerTextTopPadding, + (int) innerTextRightPadding, + (int) innerTextBottomPadding); + + Drawable buttonBackground = typedArray.getDrawable(R.styleable.SwipeButton_button_background); + + if (buttonBackground != null) { + swipeButton.setBackground(buttonBackground); + } else { + swipeButton.setBackground(ContextCompat.getDrawable(context, R.drawable.shape_rounded_edit)); + } + + float buttonLeftPadding = typedArray.getDimension( + R.styleable.SwipeButton_button_left_padding, 0); + float buttonTopPadding = typedArray.getDimension( + R.styleable.SwipeButton_button_top_padding, 0); + float buttonRightPadding = typedArray.getDimension( + R.styleable.SwipeButton_button_right_padding, 0); + float buttonBottomPadding = typedArray.getDimension( + R.styleable.SwipeButton_button_bottom_padding, 0); + + swipeButton.setPadding((int) buttonLeftPadding, + (int) buttonTopPadding, + (int) buttonRightPadding, + (int) buttonBottomPadding); + + hasActivationState = typedArray.getBoolean(R.styleable.SwipeButton_has_activate_state, true); + + typedArray.recycle(); + } + + setOnTouchListener(getButtonTouchListener()); + } + + private OnTouchListener getButtonTouchListener() { + return new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + return !TouchUtils.isTouchOutsideInitialPosition(event, swipeButtonInner); + case MotionEvent.ACTION_MOVE: + if (initialX == 0) { + initialX = swipeButtonInner.getX(); + } + + if (event.getX() > swipeButtonInner.getWidth() / 2 && + event.getX() + swipeButtonInner.getWidth() / 2 < getWidth()) { + swipeButtonInner.setX(event.getX() - swipeButtonInner.getWidth() / 2); + centerText.setAlpha(1 - 1.3f * (swipeButtonInner.getX() + swipeButtonInner.getWidth()) / getWidth()); + setTrailingEffect(); + } + + if (event.getX() + swipeButtonInner.getWidth() / 2 > getWidth() && + swipeButtonInner.getX() + swipeButtonInner.getWidth() / 2 < getWidth()) { + swipeButtonInner.setX(getWidth() - swipeButtonInner.getWidth()); + } + + if (event.getX() < swipeButtonInner.getWidth() / 2) { + swipeButtonInner.setX(0); + } + + return true; + case MotionEvent.ACTION_UP: + if (active) { + collapseButton(); + } else { + if (swipeButtonInner.getX() + swipeButtonInner.getWidth() > getWidth() * 0.9) { + if (hasActivationState) { + expandButton(); + } else if (onActiveListener != null) { + onActiveListener.onActive(); + moveButtonBack(); + } + } else { + moveButtonBack(); + } + } + + return true; + } + + return false; + } + }; + } + + private void expandButton() { + final ValueAnimator positionAnimator = + ValueAnimator.ofFloat(swipeButtonInner.getX(), 0); + positionAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float x = (Float) positionAnimator.getAnimatedValue(); + swipeButtonInner.setX(x); + } + }); + + + final ValueAnimator widthAnimator = ValueAnimator.ofInt( + swipeButtonInner.getWidth(), + getWidth()); + + widthAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + ViewGroup.LayoutParams params = swipeButtonInner.getLayoutParams(); + params.width = (Integer) widthAnimator.getAnimatedValue(); + swipeButtonInner.setLayoutParams(params); + } + }); + + + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + + active = true; + swipeButtonInner.setImageDrawable(enabledDrawable); + + if (onStateChangeListener != null) { + onStateChangeListener.onStateChange(active); + } + + if (onActiveListener != null) { + onActiveListener.onActive(); + } + } + }); + + animatorSet.playTogether(positionAnimator, widthAnimator); + animatorSet.start(); + } + + private void moveButtonBack() { + final ValueAnimator positionAnimator = + ValueAnimator.ofFloat(swipeButtonInner.getX(), 0); + positionAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); + positionAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float x = (Float) positionAnimator.getAnimatedValue(); + swipeButtonInner.setX(x); + setTrailingEffect(); + } + }); + + positionAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + if (layer != null) { + layer.setVisibility(View.GONE); + } + } + }); + + ObjectAnimator objectAnimator = ObjectAnimator.ofFloat( + centerText, "alpha", 1); + + positionAnimator.setDuration(200); + + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether(objectAnimator, positionAnimator); + animatorSet.start(); + } + + private void collapseButton() { + int finalWidth; + + if (collapsedWidth == ViewGroup.LayoutParams.WRAP_CONTENT) { + finalWidth = swipeButtonInner.getHeight(); + } else { + finalWidth = collapsedWidth; + } + + final ValueAnimator widthAnimator = ValueAnimator.ofInt(swipeButtonInner.getWidth(), finalWidth); + + widthAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + ViewGroup.LayoutParams params = swipeButtonInner.getLayoutParams(); + params.width = (Integer) widthAnimator.getAnimatedValue(); + swipeButtonInner.setLayoutParams(params); + setTrailingEffect(); + } + }); + + widthAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + active = false; + swipeButtonInner.setImageDrawable(disabledDrawable); + if (onStateChangeListener != null) { + onStateChangeListener.onStateChange(active); + } + if (layer != null) { + layer.setVisibility(View.GONE); + } + } + }); + + ObjectAnimator objectAnimator = ObjectAnimator.ofFloat( + centerText, "alpha", 1); + + AnimatorSet animatorSet = new AnimatorSet(); + + animatorSet.playTogether(objectAnimator, widthAnimator); + animatorSet.start(); + } + + private void setTrailingEffect() { + if (trailEnabled) { + layer.setVisibility(View.VISIBLE); + layer.setLayoutParams(new LayoutParams( + (int) (swipeButtonInner.getX() + swipeButtonInner.getWidth() / 3), centerText.getHeight())); + } + } + + public void toggleState() { + if (isActive()) { + collapseButton(); + } else { + expandButton(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/swipebtn/TouchUtils.java b/app/src/main/java/code/name/monkey/retromusic/swipebtn/TouchUtils.java new file mode 100755 index 00000000..b9762592 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/swipebtn/TouchUtils.java @@ -0,0 +1,13 @@ +package code.name.monkey.retromusic.swipebtn; + +import android.view.MotionEvent; +import android.view.View; + +final class TouchUtils { + private TouchUtils() { + } + + static boolean isTouchOutsideInitialPosition(MotionEvent event, View view) { + return event.getX() > view.getX() + view.getWidth(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/transform/CustPagerTransformer.java b/app/src/main/java/code/name/monkey/retromusic/transform/CustPagerTransformer.java new file mode 100644 index 00000000..6e72fed3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/transform/CustPagerTransformer.java @@ -0,0 +1,45 @@ +package code.name.monkey.retromusic.transform; + +import android.content.Context; +import android.support.v4.view.ViewPager; +import android.view.View; + +/** + * 实现ViewPager左右滑动时的时差 + * Created by xmuSistone on 2016/9/18. + */ +public class CustPagerTransformer implements ViewPager.PageTransformer { + + private int maxTranslateOffsetX; + private ViewPager viewPager; + + public CustPagerTransformer(Context context) { + this.maxTranslateOffsetX = dp2px(context, 180); + } + + public void transformPage(View view, float position) { + if (viewPager == null) { + viewPager = (ViewPager) view.getParent(); + } + + int leftInScreen = view.getLeft() - viewPager.getScrollX(); + int centerXInViewPager = leftInScreen + view.getMeasuredWidth() / 2; + int offsetX = centerXInViewPager - viewPager.getMeasuredWidth() / 2; + float offsetRate = (float) offsetX * 0.20f / viewPager.getMeasuredWidth(); + float scaleFactor = 1 - Math.abs(offsetRate); + if (scaleFactor > 0) { + view.setScaleX(scaleFactor); + view.setScaleY(scaleFactor); + view.setTranslationX(-maxTranslateOffsetX * offsetRate); + } + } + + /** + * dp和像素转换 + */ + private int dp2px(Context context, float dipValue) { + float m = context.getResources().getDisplayMetrics().density; + return (int) (dipValue * m + 0.5f); + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/transform/NormalPageTransformer.java b/app/src/main/java/code/name/monkey/retromusic/transform/NormalPageTransformer.java new file mode 100644 index 00000000..4ad5c7eb --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/transform/NormalPageTransformer.java @@ -0,0 +1,47 @@ +package code.name.monkey.retromusic.transform; + +import android.support.v4.view.ViewPager; +import android.view.View; + +/** + * @author Hemanth S (h4h13). + */ + +public class NormalPageTransformer implements ViewPager.PageTransformer { + private static final float MIN_SCALE = 0.85f; + private static final float MIN_ALPHA = 0.5f; + + @Override + public void transformPage(View view, float position) { + int pageWidth = view.getWidth(); + int pageHeight = view.getHeight(); + + if (position < -1) { // [-Infinity,-1) + // This page is way off-screen to the left. + view.setAlpha(1); + view.setScaleY(0.7f); + } else if (position <= 1) { // [-1,1] + // Modify the default slide transition to shrink the page as well + float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); + float vertMargin = pageHeight * (1 - scaleFactor) / 2; + float horzMargin = pageWidth * (1 - scaleFactor) / 2; + if (position < 0) { + view.setTranslationX(horzMargin - vertMargin / 2); + } else { + view.setTranslationX(-horzMargin + vertMargin / 2); + } + + // Scale the page down (between MIN_SCALE and 1) + view.setScaleX(scaleFactor); + view.setScaleY(scaleFactor); + + // Fade the page relative to its size. + //view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA)); + + } else { // (1,+Infinity] + // This page is way off-screen to the right. + view.setAlpha(1); + view.setScaleY(0.7f); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/transform/ParallaxPagerTransformer.java b/app/src/main/java/code/name/monkey/retromusic/transform/ParallaxPagerTransformer.java new file mode 100644 index 00000000..c2479db4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/transform/ParallaxPagerTransformer.java @@ -0,0 +1,56 @@ +package code.name.monkey.retromusic.transform; + +import android.annotation.TargetApi; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.v4.view.ViewPager; +import android.util.Log; +import android.view.View; + +/** + * Created by xgc1986 on 2/Apr/2016 + */ + +public class ParallaxPagerTransformer implements ViewPager.PageTransformer { + private int id; + private int border = 0; + private float speed = 0.2f; + + public ParallaxPagerTransformer(int id) { + this.id = id; + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + @Override + public void transformPage(@NonNull View view, float position) { + + View parallaxView = view.findViewById(id); + + if (view == null ) { + Log.w("ParallaxPager", "There is no view"); + } + + if (parallaxView != null) { + if (position > -1 && position < 1) { + float width = parallaxView.getWidth(); + parallaxView.setTranslationX(-(position * width * speed)); + float sc = ((float)view.getWidth() - border)/ view.getWidth(); + if (position == 0) { + view.setScaleX(1); + view.setScaleY(1); + } else { + view.setScaleX(sc); + view.setScaleY(sc); + } + } + } + } + + public void setBorder(int px) { + border = px; + } + + public void setSpeed(float speed) { + this.speed = speed; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/AboutActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/AboutActivity.java new file mode 100644 index 00000000..b6ae31cb --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/AboutActivity.java @@ -0,0 +1,167 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.AppBarLayout; +import android.support.v4.app.ShareCompat; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.view.View; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.Constants; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.ui.activities.base.AbsBaseActivity; +import code.name.monkey.retromusic.util.NavigationUtil; + +import static code.name.monkey.retromusic.Constants.APP_INSTAGRAM_LINK; +import static code.name.monkey.retromusic.Constants.APP_TWITTER_LINK; +import static code.name.monkey.retromusic.Constants.GITHUB_PROJECT; +import static code.name.monkey.retromusic.Constants.GOOGLE_PLUS_COMMUNITY; +import static code.name.monkey.retromusic.Constants.RATE_ON_GOOGLE_PLAY; +import static code.name.monkey.retromusic.Constants.TELEGRAM_CHANGE_LOG; +import static code.name.monkey.retromusic.Constants.TRANSLATE; + +/** + * @author Hemanth S (h4h13) + */ + +public class AboutActivity extends AbsBaseActivity { + @BindView(R.id.toolbar) + Toolbar toolbar; + + @BindView(R.id.app_bar) + AppBarLayout appBar; + @BindView(R.id.buy_pro) + TextView supportText; + @BindView(R.id.app_version) + TextView appVersion; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_about); + ButterKnife.bind(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + setUpToolbar(); + + appVersion.setText(getAppVersion()); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void setUpToolbar() { + int primaryColor = ThemeStore.primaryColor(this); + toolbar.setBackgroundColor(primaryColor); + appBar.setBackgroundColor(primaryColor); + setTitle(R.string.action_about); + setSupportActionBar(toolbar); + //noinspection ConstantConditions + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + supportText.setText(RetroApplication.isProVersion() ? R.string.thank_you : R.string.buy_retromusic_pro); + } + + + private void openUrl(String url) { + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(url)); + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(i); + } + + + @OnClick({R.id.app_github, R.id.faq_link, + R.id.app_google_plus, R.id.app_translation, + R.id.support_container, R.id.app_rate, R.id.app_share, R.id.pro_container, + R.id.instagram_link, R.id.twitter_link, R.id.changelog, + R.id.open_source, R.id.discord_link, R.id.telegram_link}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.faq_link: + openUrl(Constants.FAQ_LINK); + break; + case R.id.telegram_link: + openUrl(Constants.APP_TELEGRAM_LINK); + break; + case R.id.discord_link: + openUrl(Constants.DISCORD_LINK); + break; + case R.id.app_github: + openUrl(GITHUB_PROJECT); + break; + case R.id.app_google_plus: + openUrl(GOOGLE_PLUS_COMMUNITY); + break; + case R.id.support_container: + startActivity(new Intent(this, SupportDevelopmentActivity.class)); + break; + case R.id.app_translation: + openUrl(TRANSLATE); + break; + case R.id.app_rate: + openUrl(RATE_ON_GOOGLE_PLAY); + break; + case R.id.app_share: + shareApp(); + break; + case R.id.pro_container: + NavigationUtil.goToProVersion(this); + break; + + case R.id.instagram_link: + openUrl(APP_INSTAGRAM_LINK); + break; + case R.id.twitter_link: + openUrl(APP_TWITTER_LINK); + break; + case R.id.changelog: + openUrl(TELEGRAM_CHANGE_LOG); + break; + case R.id.open_source: + NavigationUtil.goToOpenSource(this); + break; + } + } + + private String getAppVersion() { + try { + PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0); + return packageInfo.versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return "0.0.0"; + } + } + + private void shareApp() { + Intent shareIntent = ShareCompat.IntentBuilder.from(this) + .setType("songText/plain") + .setText(String.format(getString(R.string.app_share), getPackageName())) + .getIntent(); + if (shareIntent.resolveActivity(getPackageManager()) != null) { + startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.action_share))); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/AlbumDetailsActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/AlbumDetailsActivity.java new file mode 100644 index 00000000..15febb95 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/AlbumDetailsActivity.java @@ -0,0 +1,414 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CollapsingToolbarLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.NestedScrollView; +import android.support.v7.widget.AppCompatTextView; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuItem; +import android.view.SubMenu; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.PopupMenu; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +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.TintHelper; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog; +import code.name.monkey.retromusic.dialogs.DeleteSongsDialog; +import code.name.monkey.retromusic.glide.ArtistGlideRequest; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder; +import code.name.monkey.retromusic.loaders.ArtistLoader; +import code.name.monkey.retromusic.misc.AppBarStateChangeListener; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.mvp.contract.AlbumDetailsContract; +import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsPresenter; +import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity; +import code.name.monkey.retromusic.ui.activities.tageditor.AbsTagEditorActivity; +import code.name.monkey.retromusic.ui.activities.tageditor.AlbumTagEditorActivity; +import code.name.monkey.retromusic.ui.adapter.album.AlbumAdapter; +import code.name.monkey.retromusic.ui.adapter.album.HorizontalAlbumAdapter; +import code.name.monkey.retromusic.ui.adapter.song.SimpleSongAdapter; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroUtil; + +public class AlbumDetailsActivity extends AbsSlidingMusicPanelActivity implements + AlbumDetailsContract.AlbumDetailsView { + + public static final String EXTRA_ALBUM_ID = "extra_album_id"; + private static final int TAG_EDITOR_REQUEST = 2001; + @BindView(R.id.image) + ImageView image; + @BindView(R.id.recycler_view) + RecyclerView recyclerView; + @BindView(R.id.title) + TextView title; + @BindView(R.id.text) + TextView text; + @BindView(R.id.song_title) + AppCompatTextView songTitle; + @BindView(R.id.action_shuffle_all) + FloatingActionButton shuffleButton; + @BindView(R.id.collapsing_toolbar) + @Nullable + CollapsingToolbarLayout collapsingToolbarLayout; + @BindView(R.id.app_bar) + @Nullable + AppBarLayout appBarLayout; + @BindView(R.id.image_container) + @Nullable + View imageContainer; + @BindView(R.id.content) + View contentContainer; + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.more_recycler_view) + RecyclerView moreRecyclerView; + @BindView(R.id.more_title) + TextView moreTitle; + @BindView(R.id.artist_image) + ImageView artistImage; + + private AlbumDetailsPresenter albumDetailsPresenter; + private Album album; + private SimpleSongAdapter adapter; + + @Override + protected View createContentView() { + return wrapSlidingMusicPanel(R.layout.activity_album); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + setDrawUnderStatusbar(true); + super.onCreate(savedInstanceState); + ButterKnife.bind(this); + + supportPostponeEnterTransition(); + setupToolbarMarginHeight(); + setBottomBarVisibility(View.GONE); + setLightNavigationBar(true); + setNavigationbarColorAuto(); + + int albumId = getIntent().getIntExtra(EXTRA_ALBUM_ID, -1); + albumDetailsPresenter = new AlbumDetailsPresenter(this, albumId); + + } + + private void setupToolbarMarginHeight() { + int primaryColor = ThemeStore.primaryColor(this); + TintHelper.setTintAuto(contentContainer, primaryColor, true); + if (collapsingToolbarLayout != null) { + collapsingToolbarLayout.setContentScrimColor(primaryColor); + collapsingToolbarLayout.setStatusBarScrimColor(ColorUtil.darkenColor(primaryColor)); + } + + toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); + setSupportActionBar(toolbar); + //noinspection ConstantConditions + getSupportActionBar().setTitle(null); + + if (toolbar != null && !PreferenceUtil.getInstance(this).getFullScreenMode()) { + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams(); + params.topMargin = RetroUtil.getStatusBarHeight(this); + toolbar.setLayoutParams(params); + } + + if (appBarLayout != null) { + appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { + @Override + public void onStateChanged(AppBarLayout appBarLayout, State state) { + int color; + switch (state) { + case COLLAPSED: + setLightStatusbar(!ATHUtil.isWindowBackgroundDark(AlbumDetailsActivity.this)); + color = ATHUtil.resolveColor(AlbumDetailsActivity.this, R.attr.iconColor); + break; + default: + case EXPANDED: + case IDLE: + setLightStatusbar(false); + color = ContextCompat.getColor(AlbumDetailsActivity.this, R.color.md_white_1000); + break; + } + ToolbarContentTintHelper.colorizeToolbar(toolbar, color, AlbumDetailsActivity.this); + } + }); + } + + } + + @OnClick({R.id.action_shuffle_all}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.menu_close: + onBackPressed(); + break; + case R.id.menu: + PopupMenu popupMenu = new PopupMenu(this, view); + popupMenu.inflate(R.menu.menu_album_detail); + MenuItem sortOrder = popupMenu.getMenu().findItem(R.id.action_sort_order); + setUpSortOrderMenu(sortOrder.getSubMenu()); + popupMenu.setOnMenuItemClickListener(this::onOptionsItemSelected); + popupMenu.show(); + break; + case R.id.action_shuffle_all: + MusicPlayerRemote.openAndShuffleQueue(album.songs, true); + break; + } + } + + @Override + protected void onResume() { + super.onResume(); + albumDetailsPresenter.subscribe(); + } + + @Override + protected void onPause() { + super.onPause(); + albumDetailsPresenter.unsubscribe(); + } + + @Override + public void loading() { + + } + + @Override + public void showEmptyView() { + + } + + @Override + public void completed() { + supportStartPostponedEnterTransition(); + } + + @Override + public void showData(Album album) { + if (album.songs.isEmpty()) { + finish(); + return; + } + this.album = album; + + title.setText(album.getTitle()); + text.setText(String.format("%s%s • %s", album.getArtistName(), " • " + MusicUtil.getYearString(album.getYear()), + MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, album.songs)))); + + loadAlbumCover(); + + adapter = new SimpleSongAdapter(this, this.album.songs, R.layout.item_song); + + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + recyclerView.setItemAnimator(new DefaultItemAnimator()); + recyclerView.setAdapter(adapter); + recyclerView.setNestedScrollingEnabled(false); + + loadMoreFrom(album); + + } + + private void loadMoreFrom(Album album) { + + ArtistGlideRequest.Builder.from(Glide.with(this), + ArtistLoader.getArtist(this, album.getArtistId()).blockingFirst()) + .forceDownload(true) + .generatePalette(this).build() + .dontAnimate() + .into(new RetroMusicColoredTarget(artistImage) { + @Override + public void onColorReady(int color) { + setColors(color); + } + }); + + + ArrayList albums = ArtistLoader.getArtist(this, album.getArtistId()).blockingFirst().albums; + albums.remove(album); + if (!albums.isEmpty()) { + moreTitle.setVisibility(View.VISIBLE); + moreRecyclerView.setVisibility(View.VISIBLE); + } else { + return; + } + moreTitle.setText(String.format("More from %s", album.getArtistName())); + + AlbumAdapter albumAdapter = new HorizontalAlbumAdapter(this, albums, + false, null); + moreRecyclerView.setLayoutManager(new GridLayoutManager(this, 1, GridLayoutManager.HORIZONTAL, false)); + moreRecyclerView.setAdapter(albumAdapter); + } + + public Album getAlbum() { + return album; + } + + private void loadAlbumCover() { + SongGlideRequest.Builder.from(Glide.with(this), getAlbum().safeGetFirstSong()) + .checkIgnoreMediaStore(this) + .generatePalette(this).build() + .dontAnimate() + .listener(new RequestListener() { + @Override + public boolean onException(Exception e, Object model, Target target, + boolean isFirstResource) { + supportStartPostponedEnterTransition(); + return false; + } + + @Override + public boolean onResourceReady(BitmapPaletteWrapper resource, Object model, + Target target, boolean isFromMemoryCache, + boolean isFirstResource) { + supportStartPostponedEnterTransition(); + return false; + } + }) + .into(new RetroMusicColoredTarget(image) { + @Override + public void onColorReady(int color) { + setColors(color); + } + }); + } + + private void setColors(int color) { + int themeColor = PreferenceUtil.getInstance(this).getAdaptiveColor() ? color : ThemeStore.accentColor(this); + songTitle.setTextColor(themeColor); + moreTitle.setTextColor(themeColor); + + TintHelper.setTintAuto(shuffleButton, themeColor, true); + findViewById(R.id.root).setBackgroundColor(ThemeStore.primaryColor(this)); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_album_detail, menu); + MenuItem sortOrder = menu.findItem(R.id.action_sort_order); + setUpSortOrderMenu(sortOrder.getSubMenu()); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + return handleSortOrderMenuItem(item); + } + + private boolean handleSortOrderMenuItem(@NonNull MenuItem item) { + String sortOrder = null; + final ArrayList songs = adapter.getDataSet(); + switch (item.getItemId()) { + case R.id.action_play_next: + MusicPlayerRemote.playNext(songs); + return true; + case R.id.action_add_to_current_playing: + MusicPlayerRemote.enqueue(songs); + return true; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(songs).show(getSupportFragmentManager(), "ADD_PLAYLIST"); + return true; + case R.id.action_delete_from_device: + DeleteSongsDialog.create(songs).show(getSupportFragmentManager(), "DELETE_SONGS"); + return true; + case android.R.id.home: + super.onBackPressed(); + return true; + case R.id.action_tag_editor: + Intent intent = new Intent(this, AlbumTagEditorActivity.class); + intent.putExtra(AbsTagEditorActivity.EXTRA_ID, getAlbum().getId()); + startActivityForResult(intent, TAG_EDITOR_REQUEST); + return true; + case R.id.action_go_to_artist: + NavigationUtil.goToArtist(this, getAlbum().getArtistId()); + return true; + /*Sort*/ + case R.id.action_sort_order_title: + sortOrder = AlbumSongSortOrder.SONG_A_Z; + break; + case R.id.action_sort_order_title_desc: + sortOrder = AlbumSongSortOrder.SONG_Z_A; + break; + case R.id.action_sort_order_track_list: + sortOrder = AlbumSongSortOrder.SONG_TRACK_LIST; + break; + case R.id.action_sort_order_artist_song_duration: + sortOrder = AlbumSongSortOrder.SONG_DURATION; + break; + } + if (sortOrder != null) { + item.setChecked(true); + setSaveSortOrder(sortOrder); + } + return true; + } + + private String getSavedSortOrder() { + return PreferenceUtil.getInstance(this).getAlbumDetailSongSortOrder(); + } + + private void setUpSortOrderMenu(@NonNull SubMenu sortOrder) { + switch (getSavedSortOrder()) { + case AlbumSongSortOrder.SONG_A_Z: + sortOrder.findItem(R.id.action_sort_order_title).setChecked(true); + break; + case AlbumSongSortOrder.SONG_Z_A: + sortOrder.findItem(R.id.action_sort_order_title_desc).setChecked(true); + break; + case AlbumSongSortOrder.SONG_TRACK_LIST: + sortOrder.findItem(R.id.action_sort_order_track_list).setChecked(true); + break; + case AlbumSongSortOrder.SONG_DURATION: + sortOrder.findItem(R.id.action_sort_order_artist_song_duration).setChecked(true); + break; + } + } + + private void setSaveSortOrder(String sortOrder) { + PreferenceUtil.getInstance(this).setAlbumDetailSongSortOrder(sortOrder); + reload(); + } + + @Override + public void onMediaStoreChanged() { + super.onMediaStoreChanged(); + reload(); + } + + private void reload() { + albumDetailsPresenter.subscribe(); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ArtistDetailActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ArtistDetailActivity.java new file mode 100755 index 00000000..de8372b5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ArtistDetailActivity.java @@ -0,0 +1,429 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.content.Intent; +import android.content.res.ColorStateList; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CollapsingToolbarLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.AppCompatTextView; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.text.Html; +import android.text.Spanned; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.bumptech.glide.Glide; + +import java.util.ArrayList; +import java.util.Locale; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +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.TintHelper; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog; +import code.name.monkey.retromusic.glide.ArtistGlideRequest; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.misc.AppBarStateChangeListener; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.mvp.contract.ArtistDetailContract; +import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsPresenter; +import code.name.monkey.retromusic.rest.LastFMRestClient; +import code.name.monkey.retromusic.rest.model.LastFmArtist; +import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity; +import code.name.monkey.retromusic.ui.adapter.album.AlbumAdapter; +import code.name.monkey.retromusic.ui.adapter.album.HorizontalAlbumAdapter; +import code.name.monkey.retromusic.ui.adapter.song.SimpleSongAdapter; +import code.name.monkey.retromusic.util.CustomArtistImageUtil; +import code.name.monkey.retromusic.util.DensityUtil; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implements + ArtistDetailContract.ArtistsDetailsView { + + public static final String EXTRA_ARTIST_ID = "extra_artist_id"; + private static final int REQUEST_CODE_SELECT_IMAGE = 9003; + @BindView(R.id.image) + ImageView image; + @BindView(R.id.biography) + TextView biographyTextView; + @BindView(R.id.recycler_view) + RecyclerView recyclerView; + @BindView(R.id.album_recycler_view) + RecyclerView albumRecyclerView; + @BindView(R.id.album_title) + AppCompatTextView albumTitle; + @BindView(R.id.song_title) + AppCompatTextView songTitle; + @BindView(R.id.biography_title) + AppCompatTextView biographyTitle; + @BindView(R.id.title) + TextView title; + @BindView(R.id.text) + TextView text; + @BindView(R.id.action_shuffle_all) + FloatingActionButton shuffleButton; + @BindView(R.id.collapsing_toolbar) + @Nullable + CollapsingToolbarLayout collapsingToolbarLayout; + @BindView(R.id.app_bar) + @Nullable + AppBarLayout appBarLayout; + @BindView(R.id.gradient_background) + @Nullable + View background; + @BindView(R.id.image_container) + @Nullable + View imageContainer; + @BindView(R.id.content) + View contentContainer; + @BindView(R.id.toolbar) + Toolbar toolbar; + @Nullable + private Spanned biography; + private Artist artist; + private LastFMRestClient lastFMRestClient; + private ArtistDetailsPresenter artistDetailsPresenter; + private SimpleSongAdapter songAdapter; + private AlbumAdapter albumAdapter; + private boolean forceDownload; + + @Override + protected View createContentView() { + return wrapSlidingMusicPanel(R.layout.activity_artist_details); + } + + @Override + protected void onCreate(Bundle bundle) { + setDrawUnderStatusbar(true); + super.onCreate(bundle); + ButterKnife.bind(this); + + supportPostponeEnterTransition(); + setBottomBarVisibility(View.GONE); + setNavigationbarColorAuto(); + setLightNavigationBar(true); + + lastFMRestClient = new LastFMRestClient(this); + + setUpViews(); + + int artistID = getIntent().getIntExtra(EXTRA_ARTIST_ID, -1); + artistDetailsPresenter = new ArtistDetailsPresenter(this, artistID); + } + + private void setUpViews() { + setupRecyclerView(); + setupToolbar(); + setupContainerHeight(); + } + + private void setupContainerHeight() { + if (imageContainer != null) { + LayoutParams params = imageContainer.getLayoutParams(); + params.width = DensityUtil.getScreenHeight(this) / 2; + imageContainer.setLayoutParams(params); + } + } + + private void setupToolbar() { + toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); + setSupportActionBar(toolbar); + //noinspection ConstantConditions + getSupportActionBar().setTitle(null); + + + if (toolbar != null && !PreferenceUtil.getInstance(this).getFullScreenMode()) { + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams(); + params.topMargin = RetroUtil.getStatusBarHeight(this); + toolbar.setLayoutParams(params); + } + + + int primaryColor = ThemeStore.primaryColor(this); + TintHelper.setTintAuto(contentContainer, primaryColor, true); + + if (appBarLayout != null) { + appBarLayout.setBackgroundColor(primaryColor); + appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { + @Override + public void onStateChanged(AppBarLayout appBarLayout, AppBarStateChangeListener.State state) { + int color; + switch (state) { + case COLLAPSED: + setLightStatusbar(!ATHUtil.isWindowBackgroundDark(ArtistDetailActivity.this)); + color = ATHUtil.resolveColor(ArtistDetailActivity.this, R.attr.iconColor); + break; + default: + case EXPANDED: + case IDLE: + setLightStatusbar(false); + color = ContextCompat.getColor(ArtistDetailActivity.this, R.color.md_white_1000); + break; + } + ToolbarContentTintHelper.colorizeToolbar(toolbar, color, ArtistDetailActivity.this); + } + }); + } + if (collapsingToolbarLayout != null) { + collapsingToolbarLayout.setContentScrimColor(primaryColor); + collapsingToolbarLayout.setStatusBarScrimColor(ColorUtil.darkenColor(primaryColor)); + } + } + + private void setupRecyclerView() { + albumAdapter = new HorizontalAlbumAdapter(this, new ArrayList<>(), false, null); + albumRecyclerView.setItemAnimator(new DefaultItemAnimator()); + albumRecyclerView + .setLayoutManager(new GridLayoutManager(this, 1, GridLayoutManager.HORIZONTAL, false)); + albumRecyclerView.setAdapter(albumAdapter); + + songAdapter = new SimpleSongAdapter(this, new ArrayList<>(), R.layout.item_song); + recyclerView.setItemAnimator(new DefaultItemAnimator()); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + recyclerView.setAdapter(songAdapter); + } + + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + switch (requestCode) { + case REQUEST_CODE_SELECT_IMAGE: + if (resultCode == RESULT_OK) { + CustomArtistImageUtil.getInstance(this).setCustomArtistImage(artist, data.getData()); + } + break; + default: + if (resultCode == RESULT_OK) { + reload(); + } + break; + } + } + + @Override + protected void onResume() { + super.onResume(); + artistDetailsPresenter.subscribe(); + } + + @Override + protected void onPause() { + super.onPause(); + artistDetailsPresenter.unsubscribe(); + } + + @Override + public void loading() { + } + + @Override + public void showEmptyView() { + + } + + @Override + public void completed() { + supportStartPostponedEnterTransition(); + } + + @Override + public void showData(Artist artist) { + setArtist(artist); + } + + private Artist getArtist() { + if (artist == null) { + artist = new Artist(); + } + return artist; + } + + private void setArtist(Artist artist) { + if (artist.getSongCount() <= 0) { + finish(); + } + this.artist = artist; + loadArtistImage(); + + if (RetroUtil.isAllowedToDownloadMetadata(this)) { + loadBiography(); + } + title.setText(artist.getName()); + text.setText(String.format("%s • %s", MusicUtil.getArtistInfoString(this, artist), MusicUtil + .getReadableDurationString(MusicUtil.getTotalDuration(this, artist.getSongs())))); + + songAdapter.swapDataSet(artist.getSongs()); + albumAdapter.swapDataSet(artist.albums); + } + + private void loadBiography() { + loadBiography(Locale.getDefault().getLanguage()); + } + + private void loadBiography(@Nullable final String lang) { + biography = null; + + lastFMRestClient.getApiService() + .getArtistInfo(getArtist().getName(), lang, null) + .enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, + @NonNull Response response) { + final LastFmArtist lastFmArtist = response.body(); + if (lastFmArtist != null && lastFmArtist.getArtist() != null) { + final String bioContent = lastFmArtist.getArtist().getBio().getContent(); + if (bioContent != null && !bioContent.trim().isEmpty()) { + //TransitionManager.beginDelayedTransition(titleContainer); + biographyTextView.setVisibility(View.VISIBLE); + biographyTitle.setVisibility(View.VISIBLE); + biography = Html.fromHtml(bioContent); + biographyTextView.setText(biography); + } + } + + // If the "lang" parameter is set and no biography is given, retry with default language + if (biography == null && lang != null) { + loadBiography(null); + return; + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + t.printStackTrace(); + biography = null; + } + }); + } + + @OnClick(R.id.biography) + void toggleArtistBiography() { + if (biographyTextView.getMaxLines() == 4) { + biographyTextView.setMaxLines(Integer.MAX_VALUE); + } else { + biographyTextView.setMaxLines(4); + } + } + + private void loadArtistImage() { + ArtistGlideRequest.Builder.from(Glide.with(this), artist) + .forceDownload(forceDownload) + .generatePalette(this).build() + .dontAnimate() + .into(new RetroMusicColoredTarget(image) { + @Override + public void onColorReady(int color) { + setColors(color); + } + }); + forceDownload = false; + } + + private void setColors(int color) { + + int textColor = + PreferenceUtil.getInstance(this).getAdaptiveColor() ? color : ThemeStore.accentColor(this); + + albumTitle.setTextColor(textColor); + songTitle.setTextColor(textColor); + biographyTitle.setTextColor(textColor); + + TintHelper.setTintAuto(shuffleButton, textColor, true); + + if (background != null) { + background.setBackgroundTintList(ColorStateList.valueOf(color)); + } + findViewById(R.id.root).setBackgroundColor(ThemeStore.primaryColor(this)); + } + + @OnClick({R.id.action_shuffle_all}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.action_shuffle_all: + MusicPlayerRemote.openAndShuffleQueue(getArtist().getSongs(), true); + break; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + return handleSortOrderMenuItem(item); + } + + private boolean handleSortOrderMenuItem(@NonNull MenuItem item) { + final ArrayList songs = getArtist().getSongs(); + switch (item.getItemId()) { + case android.R.id.home: + super.onBackPressed(); + return true; + case R.id.action_play_next: + MusicPlayerRemote.playNext(songs); + return true; + case R.id.action_add_to_current_playing: + MusicPlayerRemote.enqueue(songs); + return true; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(songs).show(getSupportFragmentManager(), "ADD_PLAYLIST"); + return true; + case R.id.action_set_artist_image: + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("image/*"); + startActivityForResult( + Intent.createChooser(intent, getString(R.string.pick_from_local_storage)), + REQUEST_CODE_SELECT_IMAGE); + return true; + case R.id.action_reset_artist_image: + Toast.makeText(ArtistDetailActivity.this, getResources().getString(R.string.updating), + Toast.LENGTH_SHORT).show(); + CustomArtistImageUtil.getInstance(ArtistDetailActivity.this).resetCustomArtistImage(artist); + forceDownload = true; + return true; + } + return true; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_artist_detail, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public void onMediaStoreChanged() { + super.onMediaStoreChanged(); + reload(); + } + + private void reload() { + artistDetailsPresenter.unsubscribe(); + artistDetailsPresenter.subscribe(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/EqualizerActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/EqualizerActivity.java new file mode 100644 index 00000000..83e1d19d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/EqualizerActivity.java @@ -0,0 +1,223 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.os.Bundle; +import android.support.design.widget.AppBarLayout; +import android.support.v7.widget.SwitchCompat; +import android.support.v7.widget.Toolbar; +import android.transition.TransitionManager; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.CompoundButton; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import android.widget.Spinner; +import android.widget.TextView; +import butterknife.BindView; +import butterknife.ButterKnife; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.EqualizerHelper; +import code.name.monkey.retromusic.ui.activities.base.AbsMusicServiceActivity; + +/** + * @author Hemanth S (h4h13). + */ + +public class EqualizerActivity extends AbsMusicServiceActivity implements + AdapterView.OnItemSelectedListener { + + @BindView(R.id.equalizer) + SwitchCompat mEnable; + @BindView(R.id.content) + LinearLayout mContent; + @BindView(R.id.bands) + LinearLayout mLinearLayout; + + @BindView(R.id.bass_boost_strength) + SeekBar mBassBoostStrength; + @BindView(R.id.virtualizer_strength) + SeekBar mVirtualizerStrength; + + @BindView(R.id.bass_boost) + TextView mBassBoost; + @BindView(R.id.virtualizer) + TextView mVirtualizer; + + @BindView(R.id.toolbar) + Toolbar mToolbar; + @BindView(R.id.app_bar) + AppBarLayout mAppBar; + @BindView(R.id.presets) + Spinner mPresets; + + private CompoundButton.OnCheckedChangeListener mListener = (buttonView, isChecked) -> { + switch (buttonView.getId()) { + case R.id.equalizer: + EqualizerHelper.getInstance().getEqualizer().setEnabled(isChecked); + TransitionManager.beginDelayedTransition(mContent); + mContent.setVisibility(isChecked ? View.VISIBLE : View.GONE); + break; + } + }; + private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + if (seekBar == mBassBoostStrength) { + mBassBoost.setEnabled(progress > 0); + EqualizerHelper.getInstance().setBassBoostStrength(progress); + EqualizerHelper.getInstance().setBassBoostEnabled(progress > 0); + } else if (seekBar == mVirtualizerStrength) { + mVirtualizer.setEnabled(progress > 0); + EqualizerHelper.getInstance().setVirtualizerEnabled(progress > 0); + EqualizerHelper.getInstance().setVirtualizerStrength(progress); + } + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + + } + }; + private ArrayAdapter mPresetsNamesAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_equalizer); + ButterKnife.bind(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + int primaryColor = ThemeStore.primaryColor(this); + mToolbar.setBackgroundColor(primaryColor); + mAppBar.setBackgroundColor(primaryColor); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); + } + }); + mToolbar.setTitle(R.string.equalizer); + setSupportActionBar(mToolbar); + //noinspection ConstantConditions + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + mEnable.setChecked(EqualizerHelper.getInstance().getEqualizer().getEnabled()); + mEnable.setOnCheckedChangeListener(mListener); + + mPresetsNamesAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1); + mPresets.setAdapter(mPresetsNamesAdapter); + mPresets.setOnItemSelectedListener(this); + + mBassBoostStrength.setProgress(EqualizerHelper.getInstance().getBassBoostStrength()); + mBassBoostStrength.setOnSeekBarChangeListener(mSeekBarChangeListener); + + mVirtualizerStrength.setProgress(EqualizerHelper.getInstance().getVirtualizerStrength()); + mVirtualizerStrength.setOnSeekBarChangeListener(mSeekBarChangeListener); + + setupUI(); + addPresets(); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + } + return super.onOptionsItemSelected(item); + + } + + private void addPresets() { + mPresetsNamesAdapter.clear(); + mPresetsNamesAdapter.add("Custom"); + for (int j = 0; j < EqualizerHelper.getInstance().getEqualizer().getNumberOfPresets(); j++) { + mPresetsNamesAdapter + .add(EqualizerHelper.getInstance().getEqualizer().getPresetName((short) j)); + mPresetsNamesAdapter.notifyDataSetChanged(); + } + mPresets + .setSelection((int) EqualizerHelper.getInstance().getEqualizer().getCurrentPreset() + 1); + } + + private void setupUI() { + mLinearLayout.removeAllViews(); + short bands; + try { + // get number of supported bands + bands = (short) EqualizerHelper.getInstance().getNumberOfBands(); + + // for each of the supported bands, we will set up a slider from -10dB to 10dB boost/attenuation, + // as well as text labels to assist the user + for (short i = 0; i < bands; i++) { + final short band = i; + + View view = LayoutInflater.from(this).inflate(R.layout.retro_seekbar, mLinearLayout, false); + TextView freqTextView = view.findViewById(R.id.hurtz); + freqTextView.setText( + String.format("%d Hz", EqualizerHelper.getInstance().getCenterFreq((int) band) / 1000)); + + TextView minDbTextView = view.findViewById(R.id.minus_db); + minDbTextView + .setText(String.format("%d dB", EqualizerHelper.getInstance().getBandLevelLow() / 100)); + + TextView maxDbTextView = view.findViewById(R.id.plus_db); + maxDbTextView.setText( + String.format("%d dB", EqualizerHelper.getInstance().getBandLevelHigh() / 100)); + + SeekBar bar = view.findViewById(R.id.seekbar); + bar.setMax(EqualizerHelper.getInstance().getBandLevelHigh() - EqualizerHelper.getInstance() + .getBandLevelLow()); + bar.setProgress( + EqualizerHelper.getInstance().getBandLevel((int) band) - EqualizerHelper.getInstance() + .getBandLevelLow()); + bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + EqualizerHelper.getInstance().setBandLevel((int) band, + (int) (progress + EqualizerHelper.getInstance().getBandLevelLow())); + if (fromUser) { + mPresets.setSelection(0); + } + } + + public void onStartTrackingTouch(SeekBar seekBar) { + } + + public void onStopTrackingTouch(SeekBar seekBar) { + } + }); + + mLinearLayout.addView(view); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + if (position == 0) { + return; + } + EqualizerHelper.getInstance().getEqualizer().usePreset((short) (position - 1)); + setupUI(); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/GenreDetailsActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/GenreDetailsActivity.java new file mode 100644 index 00000000..bd1d0742 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/GenreDetailsActivity.java @@ -0,0 +1,272 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CollapsingToolbarLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.afollestad.materialcab.MaterialCab; +import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity; +import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.menu.GenreMenuHelper; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.misc.AppBarStateChangeListener; +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.mvp.contract.GenreDetailsContract; +import code.name.monkey.retromusic.mvp.presenter.GenreDetailsPresenter; +import code.name.monkey.retromusic.ui.adapter.song.SongAdapter; +import code.name.monkey.retromusic.util.RetroColorUtil; +import code.name.monkey.retromusic.util.RetroUtil; +import code.name.monkey.retromusic.util.ViewUtil; + +/** + * @author Hemanth S (h4h13). + */ + +public class GenreDetailsActivity extends AbsSlidingMusicPanelActivity implements + GenreDetailsContract.GenreDetailsView, CabHolder { + public static final String EXTRA_GENRE_ID = "extra_genre_id"; + @BindView(R.id.recycler_view) + RecyclerView recyclerView; + + @BindView(R.id.toolbar) + Toolbar toolbar; + + @BindView(android.R.id.empty) + TextView empty; + + @BindView(R.id.status_bar) + View statusBar; + + @BindView(R.id.action_shuffle) + FloatingActionButton shuffleButton; + + @BindView(R.id.progress_bar) + ProgressBar progressBar; + + @BindView(R.id.app_bar) + AppBarLayout appBarLayout; + + @BindView(R.id.collapsing_toolbar) + CollapsingToolbarLayout toolbarLayout; + + private Genre genre; + private GenreDetailsPresenter presenter; + private SongAdapter songAdapter; + private MaterialCab cab; + + private void checkIsEmpty() { + empty.setVisibility( + songAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE + ); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + setDrawUnderStatusbar(true); + super.onCreate(savedInstanceState); + ButterKnife.bind(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + setBottomBarVisibility(View.GONE); + + RetroUtil.statusBarHeight(statusBar); + + + genre = getIntent().getParcelableExtra(EXTRA_GENRE_ID); + presenter = new GenreDetailsPresenter(this, genre.id); + + setUpToolBar(); + setupRecyclerView(); + } + + @OnClick({R.id.action_shuffle}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.action_shuffle: + MusicPlayerRemote.openAndShuffleQueue(songAdapter.getDataSet(), true); + break; + } + } + + private void setUpToolBar() { + int primaryColor = ThemeStore.primaryColor(this); + toolbar.setBackgroundColor(primaryColor); + appBarLayout.setBackgroundColor(primaryColor); + toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); + setSupportActionBar(toolbar); + //noinspection ConstantConditions + getSupportActionBar().setTitle(genre.name); + setTitle(R.string.app_name); + + appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { + @Override + public void onStateChanged(AppBarLayout appBarLayout, AppBarStateChangeListener.State state) { + int color; + switch (state) { + default: + case COLLAPSED: + case EXPANDED: + case IDLE: + color = ATHUtil.resolveColor(GenreDetailsActivity.this, android.R.attr.textColorPrimary); + break; + } + toolbarLayout.setExpandedTitleColor(color); + ToolbarContentTintHelper.colorizeToolbar(toolbar, color, GenreDetailsActivity.this); + } + }); + + TintHelper.setTintAuto(shuffleButton, ThemeStore.accentColor(this), true); + } + + @Override + protected void onResume() { + super.onResume(); + presenter.subscribe(); + } + + @Override + protected void onPause() { + super.onPause(); + presenter.unsubscribe(); + } + + @Override + protected View createContentView() { + return wrapSlidingMusicPanel(R.layout.activity_playlist_detail); + } + + + @Override + public void loading() { + + } + + @Override + public void showEmptyView() { + + } + + @Override + public void completed() { + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_genre_detail, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + } + return GenreMenuHelper.handleMenuClick(this, genre, item); + } + + private void setupRecyclerView() { + ViewUtil.setUpFastScrollRecyclerViewColor(this, + ((FastScrollRecyclerView) recyclerView), ThemeStore.accentColor(this)); + songAdapter = new SongAdapter(this, new ArrayList(), R.layout.item_list, false, this); + recyclerView.setItemAnimator(new DefaultItemAnimator()); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + recyclerView.setAdapter(songAdapter); + + songAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { + @Override + public void onChanged() { + super.onChanged(); + checkIsEmpty(); + } + }); + } + + @Override + public void showData(ArrayList songs) { + songAdapter.swapDataSet(songs); + } + + public void showHeartAnimation() { + shuffleButton.clearAnimation(); + + shuffleButton.setScaleX(0.9f); + shuffleButton.setScaleY(0.9f); + shuffleButton.setVisibility(View.VISIBLE); + shuffleButton.setPivotX(shuffleButton.getWidth() / 2); + shuffleButton.setPivotY(shuffleButton.getHeight() / 2); + + shuffleButton.animate() + .setDuration(200) + .setInterpolator(new DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(() -> shuffleButton.animate() + .setDuration(200) + .setInterpolator(new AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .start()) + .start(); + } + + @NonNull + @Override + public MaterialCab openCab(final int menu, final MaterialCab.Callback callback) { + if (cab != null && cab.isActive()) cab.finish(); + cab = new MaterialCab(this, R.id.cab_stub) + .setMenu(menu) + .setCloseDrawableRes(R.drawable.ic_close_white_24dp) + .setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(this))) + .start(callback); + return cab; + } + + @Override + public void onBackPressed() { + if (cab != null && cab.isActive()) cab.finish(); + else { + recyclerView.stopScroll(); + super.onBackPressed(); + } + } + + @Override + public void onMediaStoreChanged() { + super.onMediaStoreChanged(); + presenter.subscribe(); + } + + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/LicenseActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/LicenseActivity.java new file mode 100644 index 00000000..0efcfac5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/LicenseActivity.java @@ -0,0 +1,52 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.AppBarLayout; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.webkit.WebView; +import butterknife.BindView; +import butterknife.ButterKnife; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.ui.activities.base.AbsBaseActivity; + +public class LicenseActivity extends AbsBaseActivity { + @BindView(R.id.license) + WebView mLicense; + @BindView(R.id.toolbar) + Toolbar mToolbar; + @BindView(R.id.appbar) + AppBarLayout mAppbar; + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_license); + ButterKnife.bind(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + mLicense.loadUrl("file:///android_asset/index.html"); + + mToolbar.setTitle(R.string.licenses); + mToolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); + mToolbar.setNavigationOnClickListener(view -> onBackPressed()); + mToolbar.setBackgroundColor(ThemeStore.primaryColor(this)); + mAppbar.setBackgroundColor(ThemeStore.primaryColor(this)); + setSupportActionBar(mToolbar); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/LockScreenActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/LockScreenActivity.java new file mode 100644 index 00000000..8a993189 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/LockScreenActivity.java @@ -0,0 +1,86 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.os.Bundle; +import android.support.v4.view.ViewCompat; +import android.view.WindowManager; + +import com.bumptech.glide.Glide; +import com.r0adkll.slidr.Slidr; +import com.r0adkll.slidr.model.SlidrConfig; +import com.r0adkll.slidr.model.SlidrPosition; + +import butterknife.ButterKnife; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.activities.base.AbsMusicServiceActivity; +import code.name.monkey.retromusic.ui.fragments.player.lockscreen.LockScreenPlayerControlsFragment; + +public class LockScreenActivity extends AbsMusicServiceActivity { + private LockScreenPlayerControlsFragment mFragment; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD + | WindowManager.LayoutParams.FLAG_FULLSCREEN + | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); + + setDrawUnderStatusbar(true); + setContentView(R.layout.activity_lock_screen_old_style); + + hideStatusBar(); + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + SlidrConfig config = new SlidrConfig.Builder() + .position(SlidrPosition.BOTTOM) + .build(); + + Slidr.attach(this, config); + + ButterKnife.bind(this); + mFragment = (LockScreenPlayerControlsFragment) getSupportFragmentManager().findFragmentById(R.id.playback_controls_fragment); + + findViewById(R.id.slide).setTranslationY(100f); + findViewById(R.id.slide).setAlpha(0f); + ViewCompat.animate(findViewById(R.id.slide)) + .translationY(0f) + .alpha(1f) + .setDuration(1500) + .start(); + + findViewById(R.id.root_layout).setBackgroundColor(ThemeStore.primaryColor(this)); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSongs(); + } + + @Override + public void onServiceConnected() { + super.onServiceConnected(); + updateSongs(); + } + + private void updateSongs() { + Song song = MusicPlayerRemote.getCurrentSong(); + SongGlideRequest.Builder.from(Glide.with(this), song) + .checkIgnoreMediaStore(this) + .generatePalette(this) + .build().into(new RetroMusicColoredTarget(findViewById(R.id.image)) { + @Override + public void onColorReady(int color) { + mFragment.setDark(color); + } + }); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/LyricsActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/LyricsActivity.java new file mode 100644 index 00000000..3d388f85 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/LyricsActivity.java @@ -0,0 +1,392 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.annotation.SuppressLint; +import android.content.res.ColorStateList; +import android.graphics.Color; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.Toolbar; +import android.text.InputType; +import android.text.TextUtils; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.TextView; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; +import com.bumptech.glide.Glide; + +import org.jaudiotagger.tag.FieldKey; + +import java.io.File; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.model.lyrics.Lyrics; +import code.name.monkey.retromusic.ui.activities.base.AbsMusicServiceActivity; +import code.name.monkey.retromusic.ui.activities.tageditor.WriteTagsAsyncTask; +import code.name.monkey.retromusic.util.LyricUtil; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroUtil; +import code.name.monkey.retromusic.views.LyricView; +import io.reactivex.disposables.CompositeDisposable; + +public class LyricsActivity extends AbsMusicServiceActivity implements MusicProgressViewUpdateHelper.Callback { + + @BindView(R.id.title) + TextView songTitle; + @BindView(R.id.text) + TextView songText; + @BindView(R.id.lyrics) + LyricView lyricView; + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.offline_lyrics) + TextView offlineLyrics; + @BindView(R.id.actions) + RadioGroup actionsLayout; + @BindView(R.id.gradient_background) + View background; + + private MusicProgressViewUpdateHelper updateHelper; + private AsyncTask updateLyricsAsyncTask; + private CompositeDisposable disposable; + private Song song; + private Lyrics lyrics; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_lyrics); + ButterKnife.bind(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + updateHelper = new MusicProgressViewUpdateHelper(this, 500, 1000); + + setupToolbar(); + setupLyricsView(); + setupWakelock(); + + actionsLayout.setOnCheckedChangeListener((group, checkedId) -> selectLyricsTye(checkedId)); + } + + private void selectLyricsTye(int group) { + + RadioButton radioButton = actionsLayout.findViewById(group); + radioButton.setBackgroundTintList(ColorStateList.valueOf(ThemeStore.accentColor(this))); + radioButton.setTextColor(ThemeStore.textColorPrimary(this)); + + offlineLyrics.setVisibility(View.GONE); + lyricView.setVisibility(View.GONE); + switch (group) { + case R.id.synced_lyrics: + loadLRCLyrics(); + lyricView.setVisibility(View.VISIBLE); + break; + default: + case R.id.normal_lyrics: + loadSongLyrics(); + offlineLyrics.setVisibility(View.VISIBLE); + break; + } + } + + private void loadLRCLyrics() { + if (LyricUtil.isLrcFileExist(song.title, song.artistName)) { + showLyricsLocal(LyricUtil.getLocalLyricFile(song.title, song.artistName)); + } + } + + private void setupWakelock() { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + + private void setupLyricsView() { + disposable = new CompositeDisposable(); + //lyricView.setLineSpace(15.0f); + //lyricView.setTextSize(17.0f); + //lyricView.setPlayable(true); + //lyricView.setTranslationY(DensityUtil.getScreenWidth(this) + DensityUtil.dip2px(this, 120)); + lyricView.setOnPlayerClickListener((progress, content) -> MusicPlayerRemote.seekTo((int) progress)); + + //lyricView.setHighLightTextColor(ThemeStore.accentColor(this)); + lyricView.setDefaultColor(ContextCompat.getColor(this, R.color.md_grey_400)); + //lyricView.setTouchable(false); + lyricView.setHintColor(Color.WHITE); + + + } + + private void setupToolbar() { + toolbar.setBackgroundColor(ThemeStore.primaryColor(this)); + toolbar.setTitle(""); + toolbar.setNavigationOnClickListener(v -> onBackPressed()); + setSupportActionBar(toolbar); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + loadLrcFile(); + } + + @Override + protected void onResume() { + super.onResume(); + updateHelper.start(); + } + + @Override + protected void onPause() { + super.onPause(); + updateHelper.stop(); + } + + @Override + public void onServiceConnected() { + super.onServiceConnected(); + loadLrcFile(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + disposable.clear(); + lyricView.setOnPlayerClickListener(null); + + if (updateLyricsAsyncTask != null && !updateLyricsAsyncTask.isCancelled()) { + updateLyricsAsyncTask.cancel(true); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + lyricView.setCurrentTimeMillis(progress); + } + + private void loadLrcFile() { + song = MusicPlayerRemote.getCurrentSong(); + songTitle.setText(song.title); + songText.setText(song.artistName); + SongGlideRequest.Builder.from(Glide.with(this), song) + .checkIgnoreMediaStore(this) + .generatePalette(this) + .build() + .into(new RetroMusicColoredTarget(findViewById(R.id.image)) { + @Override + public void onColorReady(int color) { + if (PreferenceUtil.getInstance(LyricsActivity.this).getAdaptiveColor()) { + background.setBackgroundColor(color); + } + } + }); + selectLyricsTye(actionsLayout.getCheckedRadioButtonId()); + } + + private void showLyricsLocal(File file) { + if (file == null) { + lyricView.reset(); + lyricView.setVisibility(View.GONE); + } else { + lyricView.setVisibility(View.VISIBLE); + lyricView.setLyricFile(file, "UTF-8"); + } + } + + @OnClick({R.id.edit_lyrics}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.edit_lyrics: + switch (actionsLayout.getCheckedRadioButtonId()) { + case R.id.synced_lyrics: + showSyncedLyrics(); + break; + case R.id.normal_lyrics: + showLyricsSaveDialog(); + break; + } + break; + } + } + + @SuppressLint("StaticFieldLeak") + private void loadSongLyrics() { + if (updateLyricsAsyncTask != null) updateLyricsAsyncTask.cancel(false); + final Song song = MusicPlayerRemote.getCurrentSong(); + updateLyricsAsyncTask = new AsyncTask() { + @Override + protected Lyrics doInBackground(Void... params) { + String data = MusicUtil.getLyrics(song); + if (TextUtils.isEmpty(data)) { + return null; + } + return Lyrics.parse(song, data); + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + lyrics = null; + } + + @Override + protected void onPostExecute(Lyrics l) { + lyrics = l; + offlineLyrics.setVisibility(View.VISIBLE); + if (l == null) { + offlineLyrics.setText(R.string.no_lyrics_found); + return; + } + offlineLyrics.setText(l.data); + } + + @Override + protected void onCancelled(Lyrics s) { + onPostExecute(null); + } + }.execute(); + } + + private void showSyncedLyrics() { + String content = ""; + try { + content = LyricUtil.getStringFromFile(song.title, song.artistName); + } catch (Exception e) { + e.printStackTrace(); + } + new MaterialDialog.Builder(this) + .title("Add lyrics") + .neutralText("Search") + .content("Add time frame lyrics") + .negativeText("Delete") + .onNegative((dialog, which) -> { + LyricUtil.deleteLrcFile(song.title, song.artistName); + loadLrcFile(); + }) + .onNeutral((dialog, which) -> RetroUtil.openUrl(LyricsActivity.this, getGoogleSearchLrcUrl())) + .inputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE) + .input("Paste lyrics here", content, (dialog, input) -> { + LyricUtil.writeLrcToLoc(song.title, song.artistName, input.toString()); + loadLrcFile(); + }).show(); + } + + private String getGoogleSearchLrcUrl() { + String baseUrl = "http://www.google.com/search?"; + String query = song.title + "+" + song.artistName; + query = "q=" + query.replace(" ", "+") + " .lrc"; + baseUrl += query; + return baseUrl; + } + + private void showLyricsSaveDialog() { + String content = ""; + if (lyrics == null) { + content = ""; + } else { + content = lyrics.data; + } + new MaterialDialog.Builder(this) + .title("Add lyrics") + .neutralText("Search") + .onNeutral(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { + RetroUtil.openUrl(LyricsActivity.this, getGoogleSearchUrl(song.title, song.artistName)); + } + }) + .inputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE) + .input("Paste lyrics here", content, (dialog, input) -> { + Map fieldKeyValueMap = new EnumMap<>(FieldKey.class); + fieldKeyValueMap.put(FieldKey.LYRICS, input.toString()); + + new WriteTagsAsyncTask(LyricsActivity.this) + .execute(new WriteTagsAsyncTask.LoadingInfo(getSongPaths(song), fieldKeyValueMap, null)); + loadLrcFile(); + }) + .show(); + } + + private ArrayList getSongPaths(Song song) { + ArrayList paths = new ArrayList<>(1); + paths.add(song.data); + return paths; + } + + private String getGoogleSearchUrl(String title, String text) { + String baseUrl = "http://www.google.com/search?"; + String query = title + "+" + text; + query = "q=" + query.replace(" ", "+") + " lyrics"; + baseUrl += query; + return baseUrl; + } + + /* + private void loadLyricsWIki(String title, String artist) { + offlineLyrics.setVisibility(View.GONE); + if (lyricsWikiTask != null) { + lyricsWikiTask.cancel(false); + } + lyricsWikiTask = new ParseLyrics(new ParseLyrics.LyricsCallback() { + @Override + public void onShowLyrics(String lyrics) { + offlineLyrics.setVisibility(View.VISIBLE); + offlineLyrics.setText(lyrics); + } + + @Override + public void onError() { + loadSongLyrics(); + } + }).execute(title, artist); + } + + private void callAgain(final String title, final String artist) { + disposable.clear(); + disposable.add(loadLyrics.downloadLrcFile(title, artist, MusicPlayerRemote.getSongDurationMillis()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeOn(Schedulers.io()) + .doOnSubscribe(disposable -> { + refresh.startAnimation(rotateAnimation); + }) + .subscribe(this::showLyricsLocal, throwable -> { + refresh.clearAnimation(); + showLyricsLocal(null); + //loadLyricsWIki(songTitle, artist); + toggleSyncLyrics(View.GONE); + }, () -> { + refresh.clearAnimation(); + Toast.makeText(this, "Lyrics downloaded", Toast.LENGTH_SHORT).show(); + })); + } +*/ +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/MainActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/MainActivity.java new file mode 100644 index 00000000..71b12467 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/MainActivity.java @@ -0,0 +1,336 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.annotation.SuppressLint; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.BottomNavigationView; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.afollestad.materialdialogs.MaterialDialog; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +import butterknife.BindView; +import butterknife.ButterKnife; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.SearchQueryHelper; +import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks; +import code.name.monkey.retromusic.loaders.AlbumLoader; +import code.name.monkey.retromusic.loaders.ArtistLoader; +import code.name.monkey.retromusic.loaders.PlaylistSongsLoader; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity; +import code.name.monkey.retromusic.ui.fragments.mainactivity.LibraryFragment; +import code.name.monkey.retromusic.ui.fragments.mainactivity.home.HomeFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; +import io.reactivex.Observable; +import io.reactivex.disposables.CompositeDisposable; + +public class MainActivity extends AbsSlidingMusicPanelActivity implements + SharedPreferences.OnSharedPreferenceChangeListener, + BottomNavigationView.OnNavigationItemSelectedListener { + + public static final int APP_INTRO_REQUEST = 2323; + private static final String TAG = "MainActivity"; + private static final int APP_USER_INFO_REQUEST = 9003; + private static final int REQUEST_CODE_THEME = 9002; + + @Nullable + MainActivityFragmentCallbacks currentFragment; + + @BindView(R.id.parent_container) + FrameLayout drawerLayout; + + private boolean blockRequestPermissions; + private CompositeDisposable disposable = new CompositeDisposable(); + + private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action != null && action.equals(Intent.ACTION_SCREEN_OFF)) { + if (PreferenceUtil.getInstance(context).getLockScreen() && MusicPlayerRemote.isPlaying()) { + Intent activity = new Intent(context, LockScreenActivity.class); + activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + ActivityCompat.startActivity(context, activity, null); + } + } + } + }; + + + @Override + protected View createContentView() { + @SuppressLint("InflateParams") + View contentView = getLayoutInflater().inflate(R.layout.activity_main_drawer_layout, null); + ViewGroup drawerContent = contentView.findViewById(R.id.drawer_content_container); + drawerContent.addView(wrapSlidingMusicPanel(R.layout.activity_main_content)); + return contentView; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + setDrawUnderStatusbar(true); + super.onCreate(savedInstanceState); + + ButterKnife.bind(this); + + setBottomBarVisibility(View.VISIBLE); + + drawerLayout.setOnApplyWindowInsetsListener((view, windowInsets) -> + windowInsets.replaceSystemWindowInsets(0, 0, 0, 0)); + + if (savedInstanceState == null) { + setCurrentFragment(PreferenceUtil.getInstance(this).getLastPage()); + } else { + restoreCurrentFragment(); + } + /*if (!RetroApplication.isProVersion() && + !PreferenceManager.getDefaultSharedPreferences(this) + .getBoolean("shown", false)) { + showPromotionalOffer(); + }*/ + getBottomNavigationView().setOnNavigationItemSelectedListener(this); + } + + @Override + protected void onResume() { + super.onResume(); + IntentFilter screenOnOff = new IntentFilter(); + screenOnOff.addAction(Intent.ACTION_SCREEN_OFF); + registerReceiver(broadcastReceiver, screenOnOff); + + PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this); + + if (getIntent().hasExtra("expand")) { + if (getIntent().getBooleanExtra("expand", false)) { + expandPanel(); + getIntent().putExtra("expand", false); + } + } + + } + + @Override + public void onDestroy() { + super.onDestroy(); + disposable.clear(); + if (broadcastReceiver == null) { + return; + } + unregisterReceiver(broadcastReceiver); + PreferenceUtil.getInstance(this).unregisterOnSharedPreferenceChangedListener(this); + } + + public void setCurrentFragment(@Nullable Fragment fragment, boolean isStackAdd) { + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.replace(R.id.fragment_container, fragment, TAG); + if (isStackAdd) { + fragmentTransaction.addToBackStack(TAG); + } + fragmentTransaction.commit(); + currentFragment = (MainActivityFragmentCallbacks) fragment; + } + + private void restoreCurrentFragment() { + currentFragment = (MainActivityFragmentCallbacks) getSupportFragmentManager() + .findFragmentById(R.id.fragment_container); + } + + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + PreferenceUtil.getInstance(this).setLastPage(item.getItemId()); + disposable.add(Observable.just(item.getItemId()) + .throttleFirst(3, TimeUnit.SECONDS) + .subscribe(this::setCurrentFragment)); + return true; + } + + private void setCurrentFragment(int menuItem) { + switch (menuItem) { + case R.id.action_song: + case R.id.action_album: + case R.id.action_artist: + case R.id.action_playlist: + setCurrentFragment(LibraryFragment.newInstance(menuItem), false); + break; + default: + case R.id.action_home: + setCurrentFragment(HomeFragment.newInstance(), false); + break; + } + } + + private void handlePlaybackIntent(@Nullable Intent intent) { + if (intent == null) { + return; + } + + Uri uri = intent.getData(); + String mimeType = intent.getType(); + boolean handled = false; + + if (intent.getAction() != null && intent.getAction() + .equals(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH)) { + final ArrayList songs = SearchQueryHelper.getSongs(this, intent.getExtras()); + + if (MusicPlayerRemote.getShuffleMode() == MusicService.SHUFFLE_MODE_SHUFFLE) { + MusicPlayerRemote.openAndShuffleQueue(songs, true); + } else { + MusicPlayerRemote.openQueue(songs, 0, true); + } + handled = true; + } + + if (uri != null && uri.toString().length() > 0) { + MusicPlayerRemote.playFromUri(uri); + handled = true; + } else if (MediaStore.Audio.Playlists.CONTENT_TYPE.equals(mimeType)) { + final int id = (int) parseIdFromIntent(intent, "playlistId", "playlist"); + if (id >= 0) { + int position = intent.getIntExtra("position", 0); + ArrayList songs = new ArrayList<>( + PlaylistSongsLoader.getPlaylistSongList(this, id).blockingFirst()); + MusicPlayerRemote.openQueue(songs, position, true); + handled = true; + } + } else if (MediaStore.Audio.Albums.CONTENT_TYPE.equals(mimeType)) { + final int id = (int) parseIdFromIntent(intent, "albumId", "album"); + if (id >= 0) { + int position = intent.getIntExtra("position", 0); + MusicPlayerRemote + .openQueue(AlbumLoader.getAlbum(this, id).blockingFirst().songs, position, true); + handled = true; + } + } else if (MediaStore.Audio.Artists.CONTENT_TYPE.equals(mimeType)) { + final int id = (int) parseIdFromIntent(intent, "artistId", "artist"); + if (id >= 0) { + int position = intent.getIntExtra("position", 0); + MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).blockingFirst().getSongs(), position, true); + handled = true; + } + } + if (handled) { + setIntent(new Intent()); + } + } + + private long parseIdFromIntent(@NonNull Intent intent, String longKey, String stringKey) { + long id = intent.getLongExtra(longKey, -1); + if (id < 0) { + String idString = intent.getStringExtra(stringKey); + if (idString != null) { + try { + id = Long.parseLong(idString); + } catch (NumberFormatException e) { + Log.e(TAG, e.getMessage()); + } + } + } + return id; + } + + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + switch (requestCode) { + case APP_INTRO_REQUEST: + blockRequestPermissions = false; + if (!hasPermissions()) { + requestPermissions(); + } + + break; + case REQUEST_CODE_THEME: + case APP_USER_INFO_REQUEST: + postRecreate(); + break; + } + + } + + @Override + public boolean handleBackPress() { + return super.handleBackPress() || (currentFragment != null && + currentFragment.handleBackPress()); + } + + @Override + public void onServiceConnected() { + super.onServiceConnected(); + handlePlaybackIntent(getIntent()); + } + + @Override + protected void requestPermissions() { + if (!blockRequestPermissions) { + super.requestPermissions(); + } + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + return super.onOptionsItemSelected(item); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equalsIgnoreCase(PreferenceUtil.GENERAL_THEME) || + key.equalsIgnoreCase(PreferenceUtil.ADAPTIVE_COLOR_APP) || + key.equalsIgnoreCase(PreferenceUtil.DOMINANT_COLOR) || + key.equalsIgnoreCase(PreferenceUtil.USER_NAME) || + key.equalsIgnoreCase(PreferenceUtil.TOGGLE_FULL_SCREEN) || + key.equalsIgnoreCase(PreferenceUtil.TOGGLE_VOLUME) || + key.equalsIgnoreCase(PreferenceUtil.TOGGLE_TAB_TITLES) || + key.equalsIgnoreCase(PreferenceUtil.ROUND_CORNERS) || + key.equals(PreferenceUtil.CAROUSEL_EFFECT) || + key.equals(PreferenceUtil.NOW_PLAYING_SCREEN_ID) || + key.equals(PreferenceUtil.TOGGLE_GENRE) || + key.equals(PreferenceUtil.BANNER_IMAGE_PATH) || + key.equals(PreferenceUtil.PROFILE_IMAGE_PATH) || + key.equals(PreferenceUtil.CIRCULAR_ALBUM_ART) || + key.equals(PreferenceUtil.KEEP_SCREEN_ON) || + key.equals(PreferenceUtil.TOGGLE_SEPARATE_LINE)) { + postRecreate(); + } + } + + private void showPromotionalOffer() { + new MaterialDialog.Builder(this) + .positiveText("Buy") + .onPositive((dialog, which) -> + startActivity(new Intent(MainActivity.this, ProVersionActivity.class))) + .negativeText(android.R.string.cancel) + .customView(R.layout.dialog_promotional_offer, false) + .dismissListener(dialog -> { + PreferenceManager.getDefaultSharedPreferences(MainActivity.this) + .edit() + .putBoolean("shown", true) + .apply(); + }) + .show(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlayingQueueActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlayingQueueActivity.java new file mode 100644 index 00000000..f29967a9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlayingQueueActivity.java @@ -0,0 +1,68 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.design.widget.AppBarLayout; +import android.support.v7.widget.Toolbar; +import android.widget.TextView; +import butterknife.BindDrawable; +import butterknife.BindString; +import butterknife.BindView; +import butterknife.ButterKnife; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.ui.activities.base.AbsMusicServiceActivity; +import code.name.monkey.retromusic.ui.fragments.PlayingQueueFragment; +import code.name.monkey.retromusic.util.MusicUtil; + + +public class PlayingQueueActivity extends AbsMusicServiceActivity { + + @BindView(R.id.toolbar) + Toolbar mToolbar; + @BindDrawable(R.drawable.ic_close_white_24dp) + Drawable mClose; + @BindView(R.id.player_queue_sub_header) + TextView mPlayerQueueSubHeader; + @BindString(R.string.queue) + String queue; + @BindView(R.id.app_bar) + AppBarLayout mAppBarLayout; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_playing_queue); + ButterKnife.bind(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + setupToolbar(); + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction() + .replace(R.id.fragment_container, new PlayingQueueFragment()) + .commit(); + } + } + + protected String getUpNextAndQueueTime() { + return getResources().getString(R.string.up_next) + " • " + MusicUtil + .getReadableDurationString( + MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.getPosition())); + } + + private void setupToolbar() { + mPlayerQueueSubHeader.setText(getUpNextAndQueueTime()); + mPlayerQueueSubHeader.setTextColor(ThemeStore.accentColor(this)); + mAppBarLayout.setBackgroundColor(ThemeStore.primaryColor(this)); + mToolbar.setBackgroundColor(ThemeStore.primaryColor(this)); + mToolbar.setNavigationIcon(mClose); + setSupportActionBar(mToolbar); + setTitle(queue); + mToolbar.setNavigationOnClickListener(v -> onBackPressed()); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlaylistDetailActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlaylistDetailActivity.java new file mode 100644 index 00000000..1f383fcf --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlaylistDetailActivity.java @@ -0,0 +1,353 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CollapsingToolbarLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.widget.TextView; + +import com.afollestad.materialcab.MaterialCab; +import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator; +import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator; +import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager; +import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils; +import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.loaders.PlaylistLoader; +import code.name.monkey.retromusic.misc.AppBarStateChangeListener; +import code.name.monkey.retromusic.model.AbsCustomPlaylist; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.PlaylistSong; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.mvp.contract.PlaylistSongsContract; +import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsPresenter; +import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity; +import code.name.monkey.retromusic.ui.adapter.song.OrderablePlaylistSongAdapter; +import code.name.monkey.retromusic.ui.adapter.song.PlaylistSongAdapter; +import code.name.monkey.retromusic.ui.adapter.song.SongAdapter; +import code.name.monkey.retromusic.util.PlaylistsUtil; +import code.name.monkey.retromusic.util.RetroColorUtil; +import code.name.monkey.retromusic.util.RetroUtil; +import code.name.monkey.retromusic.util.ViewUtil; + +public class PlaylistDetailActivity extends AbsSlidingMusicPanelActivity implements CabHolder, + PlaylistSongsContract.PlaylistSongsView { + + @NonNull + public static String EXTRA_PLAYLIST = "extra_playlist"; + + @BindView(R.id.recycler_view) + RecyclerView recyclerView; + + @BindView(R.id.toolbar) + Toolbar toolbar; + + @BindView(android.R.id.empty) + TextView empty; + + @BindView(R.id.action_shuffle) + FloatingActionButton shuffleButton; + + @BindView(R.id.app_bar) + AppBarLayout appBarLayout; + + @BindView(R.id.collapsing_toolbar) + CollapsingToolbarLayout toolbarLayout; + + @BindView(R.id.status_bar) + View statusBar; + + private Playlist playlist; + private MaterialCab cab; + private SongAdapter adapter; + private RecyclerView.Adapter wrappedAdapter; + private RecyclerViewDragDropManager recyclerViewDragDropManager; + private PlaylistSongsPresenter songsPresenter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + setDrawUnderStatusbar(true); + super.onCreate(savedInstanceState); + ButterKnife.bind(this); + + RetroUtil.statusBarHeight(statusBar); + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + setBottomBarVisibility(View.GONE); + + playlist = getIntent().getExtras().getParcelable(EXTRA_PLAYLIST); + + if (playlist != null) { + songsPresenter = new PlaylistSongsPresenter(this, playlist); + } + + setUpToolBar(); + setUpRecyclerView(); + } + + public void showHeartAnimation() { + shuffleButton.clearAnimation(); + + shuffleButton.setScaleX(0.9f); + shuffleButton.setScaleY(0.9f); + shuffleButton.setVisibility(View.VISIBLE); + shuffleButton.setPivotX(shuffleButton.getWidth() / 2); + shuffleButton.setPivotY(shuffleButton.getHeight() / 2); + + shuffleButton.animate() + .setDuration(200) + .setInterpolator(new DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(() -> shuffleButton.animate() + .setDuration(200) + .setInterpolator(new AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .start()) + .start(); + } + + + @Override + protected View createContentView() { + return wrapSlidingMusicPanel(R.layout.activity_playlist_detail); + } + + private void setUpRecyclerView() { + ViewUtil.setUpFastScrollRecyclerViewColor(this, ((FastScrollRecyclerView) recyclerView), + ThemeStore.accentColor(this)); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + if (playlist instanceof AbsCustomPlaylist) { + adapter = new PlaylistSongAdapter(this, new ArrayList(), R.layout.item_list, false, + this); + recyclerView.setAdapter(adapter); + } else { + recyclerViewDragDropManager = new RecyclerViewDragDropManager(); + final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator(); + adapter = new OrderablePlaylistSongAdapter(this, new ArrayList(), + R.layout.item_list, false, this, (fromPosition, toPosition) -> { + if (PlaylistsUtil + .moveItem(PlaylistDetailActivity.this, playlist.id, fromPosition, toPosition)) { + Song song = adapter.getDataSet().remove(fromPosition); + adapter.getDataSet().add(toPosition, song); + adapter.notifyItemMoved(fromPosition, toPosition); + } + }); + wrappedAdapter = recyclerViewDragDropManager.createWrappedAdapter(adapter); + + recyclerView.setAdapter(wrappedAdapter); + recyclerView.setItemAnimator(animator); + + recyclerViewDragDropManager.attachRecyclerView(recyclerView); + } + adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { + @Override + public void onChanged() { + super.onChanged(); + checkIsEmpty(); + } + }); + } + + @Override + protected void onResume() { + super.onResume(); + songsPresenter.subscribe(); + } + + private void setUpToolBar() { + int primaryColor = ThemeStore.primaryColor(this); + toolbar.setBackgroundColor(primaryColor); + appBarLayout.setBackgroundColor(primaryColor); + + toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); + + setSupportActionBar(toolbar); + //noinspection ConstantConditions + getSupportActionBar().setTitle(playlist.name); + + appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { + @Override + public void onStateChanged(AppBarLayout appBarLayout, AppBarStateChangeListener.State state) { + int color; + switch (state) { + default: + case COLLAPSED: + case EXPANDED: + case IDLE: + color = ThemeStore.textColorPrimary(PlaylistDetailActivity.this); + break; + } + toolbarLayout.setExpandedTitleColor(color); + ToolbarContentTintHelper.colorizeToolbar(toolbar, color, PlaylistDetailActivity.this); + } + }); + TintHelper.setTintAuto(shuffleButton, ThemeStore.accentColor(this), true); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate( + playlist instanceof AbsCustomPlaylist ? R.menu.menu_smart_playlist_detail + : R.menu.menu_playlist_detail, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + int id = item.getItemId(); + switch (id) { + case android.R.id.home: + onBackPressed(); + return true; + } + return PlaylistMenuHelper.handleMenuClick(this, playlist, item); + } + + @NonNull + @Override + public MaterialCab openCab(final int menu, final MaterialCab.Callback callback) { + if (cab != null && cab.isActive()) { + cab.finish(); + } + cab = new MaterialCab(this, R.id.cab_stub) + .setMenu(menu) + .setCloseDrawableRes(R.drawable.ic_close_white_24dp) + .setBackgroundColor( + RetroColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(this))) + .start(callback); + return cab; + } + + @Override + public void onBackPressed() { + if (cab != null && cab.isActive()) { + cab.finish(); + } else { + recyclerView.stopScroll(); + super.onBackPressed(); + } + } + + @Override + public void onMediaStoreChanged() { + super.onMediaStoreChanged(); + + if (!(playlist instanceof AbsCustomPlaylist)) { + // Playlist deleted + if (!PlaylistsUtil.doesPlaylistExist(this, playlist.id)) { + finish(); + return; + } + + // Playlist renamed + final String playlistName = PlaylistsUtil.getNameForPlaylist(this, playlist.id); + if (!playlistName.equals(playlist.name)) { + playlist = PlaylistLoader.getPlaylist(this, playlist.id).blockingFirst(); + setToolbarTitle(playlist.name); + } + } + songsPresenter.subscribe(); + } + + private void setToolbarTitle(String title) { + //noinspection ConstantConditions + getSupportActionBar().setTitle(title); + } + + private void checkIsEmpty() { + empty.setVisibility( + adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE + ); + } + + @Override + public void onPause() { + if (recyclerViewDragDropManager != null) { + recyclerViewDragDropManager.cancelDrag(); + } + super.onPause(); + songsPresenter.unsubscribe(); + } + + @Override + public void onDestroy() { + if (recyclerViewDragDropManager != null) { + recyclerViewDragDropManager.release(); + recyclerViewDragDropManager = null; + } + + if (recyclerView != null) { + recyclerView.setItemAnimator(null); + recyclerView.setAdapter(null); + recyclerView = null; + } + + if (wrappedAdapter != null) { + WrapperAdapterUtils.releaseAll(wrappedAdapter); + wrappedAdapter = null; + } + adapter = null; + + super.onDestroy(); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + songsPresenter.subscribe(); + } + + @Override + public void loading() { + } + + @Override + public void showEmptyView() { + empty.setVisibility(View.VISIBLE); + } + + @Override + public void completed() { + } + + @Override + public void showData(ArrayList songs) { + adapter.swapDataSet(songs); + } + + @OnClick(R.id.action_shuffle) + public void onViewClicked() { + showHeartAnimation(); + if (adapter.getDataSet().isEmpty()) { + return; + } + MusicPlayerRemote.openAndShuffleQueue(adapter.getDataSet(), true); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.java new file mode 100644 index 00000000..5381a064 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.java @@ -0,0 +1,203 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.AppBarLayout; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.widget.Toast; + +import com.anjlab.android.iab.v3.BillingProcessor; +import com.anjlab.android.iab.v3.TransactionDetails; + +import java.lang.ref.WeakReference; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.BuildConfig; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.ui.activities.base.AbsBaseActivity; +import code.name.monkey.retromusic.util.RetroUtil; + +/** + * @author Hemanth S (h4h13). + */ + +public class ProVersionActivity extends AbsBaseActivity implements + BillingProcessor.IBillingHandler { + + private static final String TAG = "ProVersionActivity"; + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.restore_button) + View restoreButton; + @BindView(R.id.purchase_button) + View purchaseButton; + @BindView(R.id.app_bar) + AppBarLayout appBar; + @BindView(R.id.status_bar) + View statusBar; + + private BillingProcessor billingProcessor; + private AsyncTask restorePurchaseAsyncTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_pro_version); + setDrawUnderStatusbar(true); + ButterKnife.bind(this); + RetroUtil.statusBarHeight(statusBar); + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + int primaryColor = ThemeStore.primaryColor(this); + toolbar.setBackgroundColor(primaryColor); + appBar.setBackgroundColor(primaryColor); + + toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); + toolbar.setNavigationOnClickListener(v -> onBackPressed()); + setSupportActionBar(toolbar); + //noinspection ConstantConditions + getSupportActionBar().setTitle("RetroMusic Pro"); + + restoreButton.setEnabled(false); + purchaseButton.setEnabled(false); + + billingProcessor = new BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSE_KEY, this); + + } + + private void restorePurchase() { + if (restorePurchaseAsyncTask != null) { + restorePurchaseAsyncTask.cancel(false); + } + restorePurchaseAsyncTask = new RestorePurchaseAsyncTask(this).execute(); + } + + @OnClick({R.id.restore_button, R.id.purchase_button}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.restore_button: + if (restorePurchaseAsyncTask == null + || restorePurchaseAsyncTask.getStatus() != AsyncTask.Status.RUNNING) { + restorePurchase(); + } + break; + case R.id.purchase_button: + billingProcessor.purchase(ProVersionActivity.this, RetroApplication.PRO_VERSION_PRODUCT_ID); + break; + } + } + + @Override + public void onProductPurchased(@NonNull String productId, @Nullable TransactionDetails details) { + Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show(); + setResult(RESULT_OK); + } + + @Override + public void onPurchaseHistoryRestored() { + if (RetroApplication.isProVersion()) { + Toast.makeText(this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG) + .show(); + setResult(RESULT_OK); + } else { + Toast.makeText(this, R.string.no_purchase_found, Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onBillingError(int errorCode, @Nullable Throwable error) { + Log.e(TAG, "Billing error: code = " + errorCode, error); + } + + + @Override + public void onBillingInitialized() { + restoreButton.setEnabled(true); + purchaseButton.setEnabled(true); + } + + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (!billingProcessor.handleActivityResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + break; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onDestroy() { + if (billingProcessor != null) { + billingProcessor.release(); + } + super.onDestroy(); + } + + private static class RestorePurchaseAsyncTask extends AsyncTask { + + private final WeakReference buyActivityWeakReference; + + RestorePurchaseAsyncTask(ProVersionActivity purchaseActivity) { + this.buyActivityWeakReference = new WeakReference<>(purchaseActivity); + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + ProVersionActivity purchaseActivity = buyActivityWeakReference.get(); + if (purchaseActivity != null) { + Toast.makeText(purchaseActivity, R.string.restoring_purchase, Toast.LENGTH_SHORT).show(); + } else { + cancel(false); + } + } + + @Override + protected Boolean doInBackground(Void... params) { + ProVersionActivity purchaseActivity = buyActivityWeakReference.get(); + if (purchaseActivity != null) { + return purchaseActivity.billingProcessor.loadOwnedPurchasesFromGoogle(); + } + cancel(false); + return null; + } + + @Override + protected void onPostExecute(Boolean b) { + super.onPostExecute(b); + ProVersionActivity purchaseActivity = buyActivityWeakReference.get(); + if (purchaseActivity == null || b == null) { + return; + } + + if (b) { + purchaseActivity.onPurchaseHistoryRestored(); + } else { + Toast.makeText(purchaseActivity, R.string.could_not_restore_purchase, Toast.LENGTH_SHORT) + .show(); + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/SearchActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SearchActivity.java new file mode 100644 index 00000000..961b5b64 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SearchActivity.java @@ -0,0 +1,267 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.app.SearchManager; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.support.annotation.NonNull; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CoordinatorLayout; +import android.support.transition.TransitionManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.SearchView.OnQueryTextListener; +import android.support.v7.widget.Toolbar; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.MenuItem; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.TextView.BufferType; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Locale; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.mvp.contract.SearchContract; +import code.name.monkey.retromusic.mvp.presenter.SearchPresenter; +import code.name.monkey.retromusic.ui.activities.base.AbsMusicServiceActivity; +import code.name.monkey.retromusic.ui.adapter.SearchAdapter; +import code.name.monkey.retromusic.util.RetroUtil; +import code.name.monkey.retromusic.util.ViewUtil; + +public class SearchActivity extends AbsMusicServiceActivity implements OnQueryTextListener, + SearchContract.SearchView, TextWatcher { + + public static final String TAG = SearchActivity.class.getSimpleName(); + public static final String QUERY = "query"; + private static final int REQ_CODE_SPEECH_INPUT = 9002; + @BindView(R.id.voice_search) + View micIcon; + @BindView(R.id.recycler_view) + RecyclerView recyclerView; + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(android.R.id.empty) + TextView empty; + @BindView(R.id.search_view) + EditText searchView; + @BindView(R.id.root) + CoordinatorLayout container; + @BindView(R.id.appbar) + AppBarLayout appbar; + @BindView(R.id.status_bar) + View statusBar; + private SearchPresenter searchPresenter; + private SearchAdapter adapter; + private String query; + + private boolean isMicSearch = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + setDrawUnderStatusbar(true); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_search); + + ButterKnife.bind(this); + + ViewUtil.setStatusBarHeight(this, statusBar); + + searchPresenter = new SearchPresenter(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + setupRecyclerview(); + setUpToolBar(); + setupSearchView(); + + if (savedInstanceState != null) { + query = savedInstanceState.getString(QUERY); + searchPresenter.search(query); + } + + if (getIntent().getBooleanExtra("mic_search", false)) { + startMicSearch(); + isMicSearch = true; + } + } + + private void setupRecyclerview() { + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + adapter = new SearchAdapter(this, Collections.emptyList()); + adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { + @Override + public void onChanged() { + super.onChanged(); + empty.setVisibility(adapter.getItemCount() < 1 ? View.VISIBLE : View.GONE); + } + }); + recyclerView.setAdapter(adapter); + } + + private void setupSearchView() { + SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE); + if (searchManager != null) { + searchView.addTextChangedListener(this); + } + } + + @Override + protected void onResume() { + super.onResume(); + //Log.i(TAG, "onResume: " + query); + searchPresenter.subscribe(); + searchPresenter.search(query); + } + + @Override + public void onDestroy() { + super.onDestroy(); + searchPresenter.unsubscribe(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString(QUERY, query); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + searchPresenter.search(savedInstanceState.getString(QUERY, "")); + } + + private void setUpToolBar() { + int primaryColor = ThemeStore.primaryColor(this); + toolbar.setBackgroundColor(primaryColor); + appbar.setBackgroundColor(primaryColor); + setSupportActionBar(toolbar); + //noinspection ConstantConditions + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + } + return super.onOptionsItemSelected(item); + } + + private void search(@NonNull String query) { + this.query = query.trim(); + TransitionManager.beginDelayedTransition(toolbar); + micIcon.setVisibility(query.length() > 0 ? View.GONE : View.VISIBLE); + searchPresenter.search(query); + } + + @Override + public void onMediaStoreChanged() { + super.onMediaStoreChanged(); + searchPresenter.search(query); + } + + @Override + public boolean onQueryTextSubmit(String query) { + hideSoftKeyboard(); + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + search(newText); + return false; + } + + private void hideSoftKeyboard() { + RetroUtil.hideSoftKeyboard(SearchActivity.this); + if (searchView != null) { + searchView.clearFocus(); + } + } + + @Override + public void loading() { + + } + + @Override + public void showEmptyView() { + adapter.swapDataSet(new ArrayList<>()); + } + + @Override + public void completed() { + + } + + @Override + public void showData(ArrayList list) { + adapter.swapDataSet(list); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + switch (requestCode) { + case REQ_CODE_SPEECH_INPUT: { + if (resultCode == RESULT_OK && null != data) { + + ArrayList result = data + .getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + query = result.get(0); + searchView.setText(query, BufferType.EDITABLE); + searchPresenter.search(query); + } + break; + } + } + } + + @OnClick(R.id.voice_search) + void searchImageView() { + startMicSearch(); + } + + private void startMicSearch() { + Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent + .putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault()); + intent.putExtra(RecognizerIntent.EXTRA_PROMPT, getString(R.string.speech_prompt)); + try { + startActivityForResult(intent, REQ_CODE_SPEECH_INPUT); + } catch (ActivityNotFoundException e) { + e.printStackTrace(); + Toast.makeText(this, getString(R.string.speech_not_supported), Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence newText, int start, int before, int count) { + search(newText.toString()); + } + + @Override + public void afterTextChanged(Editable s) { + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.java new file mode 100755 index 00000000..4bdd7df1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.java @@ -0,0 +1,150 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.AppBarLayout; +import android.support.transition.TransitionManager; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.widget.FrameLayout; + +import com.afollestad.materialdialogs.color.ColorChooserDialog; + +import butterknife.BindView; +import butterknife.ButterKnife; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager; +import code.name.monkey.retromusic.ui.activities.base.AbsBaseActivity; +import code.name.monkey.retromusic.ui.fragments.settings.MainSettingsFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; + +public class SettingsActivity extends AbsBaseActivity implements ColorChooserDialog.ColorCallback { + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.app_bar) + AppBarLayout appBarLayout; + @BindView(R.id.detail_content_frame) + @Nullable + FrameLayout detailsFrame; + + private FragmentManager fragmentManager = getSupportFragmentManager(); + + @Override + public void onColorSelection(@NonNull ColorChooserDialog dialog, @ColorInt int selectedColor) { + switch (dialog.getTitle()) { + case R.string.primary_color: + int theme = ColorUtil.isColorLight(selectedColor) ? + PreferenceUtil.getThemeResFromPrefValue("light") : + PreferenceUtil.getThemeResFromPrefValue("dark"); + + ThemeStore.editTheme(this).activityTheme(theme).primaryColor(selectedColor).commit(); + break; + case R.string.accent_color: + ThemeStore.editTheme(this).accentColor(selectedColor).commit(); + break; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + new DynamicShortcutManager(this).updateDynamicShortcuts(); + } + recreate(); + } + + @Override + public void onColorChooserDismissed(@NonNull ColorChooserDialog dialog) { + + } + + @Override + protected void onCreate(@Nullable Bundle bundle) { + super.onCreate(bundle); + setContentView(R.layout.activity_settings); + ButterKnife.bind(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + setupToolbar(); + + if (bundle == null) { + fragmentManager.beginTransaction().replace(R.id.content_frame, new MainSettingsFragment()).commit(); + } else { + restoreFragment(); + } + } + + private void setupToolbar() { + appBarLayout.setBackgroundColor(ThemeStore.primaryColor(this)); + toolbar.setBackgroundColor(ThemeStore.primaryColor(this)); + toolbar.setNavigationOnClickListener(v -> onBackPressed()); + setTitle(R.string.action_settings); + setSupportActionBar(toolbar); + } + + private void restoreFragment() { + toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); + if (fragmentManager.getBackStackEntryCount() > 0) { + appBarLayout.setExpanded(false, true); + } else { + appBarLayout.setExpanded(true, true); + } + setupToolbar(); + } + + public void setupFragment(Fragment fragment) { + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction() + .setCustomAnimations(R.animator.slide_up, 0, 0, R.animator.slide_down); + + if (detailsFrame == null) { + fragmentTransaction.replace(R.id.content_frame, fragment, fragment.getTag()); + fragmentTransaction.addToBackStack(null); + fragmentTransaction.commit(); + } else { + fragmentTransaction.replace(R.id.detail_content_frame, fragment, fragment.getTag()); + fragmentTransaction.commit(); + } + + fragmentManager.addOnBackStackChangedListener(() -> { + if (fragmentManager.getBackStackEntryCount() > 0) { + appBarLayout.setExpanded(false, true); + } else { + appBarLayout.setExpanded(true, true); + } + setupToolbar(); + }); + } + + + @Override + public void onBackPressed() { + if (fragmentManager.getBackStackEntryCount() == 0) { + super.onBackPressed(); + } else { + fragmentManager.popBackStack(); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + public void addAppbarLayoutElevation(float v) { + TransitionManager.beginDelayedTransition(appBarLayout); + appBarLayout.setElevation(v); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/SupportDevelopmentActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SupportDevelopmentActivity.java new file mode 100644 index 00000000..604a0998 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SupportDevelopmentActivity.java @@ -0,0 +1,318 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.content.Intent; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.AppBarLayout; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import com.afollestad.materialdialogs.internal.MDTintHelper; +import com.anjlab.android.iab.v3.BillingProcessor; +import com.anjlab.android.iab.v3.SkuDetails; +import com.anjlab.android.iab.v3.TransactionDetails; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.retromusic.BuildConfig; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.ui.activities.base.AbsBaseActivity; +import code.name.monkey.retromusic.util.RetroUtil; +import code.name.monkey.retromusic.views.IconImageView; + +import static code.name.monkey.retromusic.Constants.PAYPAL_ME_URL; + +/** + * @author Hemanth S (h4h13). + */ + +public class SupportDevelopmentActivity extends AbsBaseActivity implements BillingProcessor.IBillingHandler { + public static final String TAG = SupportDevelopmentActivity.class.getSimpleName(); + private static final int DONATION_PRODUCT_IDS = R.array.donation_ids; + @BindView(R.id.progress) + ProgressBar mProgressBar; + @BindView(R.id.progress_container) + View mProgressContainer; + @BindView(R.id.list) + RecyclerView mListView; + @BindView(R.id.toolbar) + Toolbar mToolbar; + @BindView(R.id.app_bar) + AppBarLayout mAppBarLayout; + @BindView(R.id.root) + ViewGroup mViewGroup; + private BillingProcessor mBillingProcessor; + private AsyncTask skuDetailsLoadAsyncTask; + + private static List getDetails() { + List skuDetails = new ArrayList<>(); + JSONObject jsonObject = new JSONObject(); + try { + for (int i = 0; i < 6; i++) { + jsonObject.put("songTitle", "Coffee"); + jsonObject.put("price", "$100"); + jsonObject.put("description", "" + i); + skuDetails.add(new SkuDetails(jsonObject)); + } + + } catch (JSONException e) { + e.printStackTrace(); + } + + return skuDetails; + } + + private void donate(int i) { + final String[] ids = getResources().getStringArray(DONATION_PRODUCT_IDS); + mBillingProcessor.purchase(this, ids[i]); + } + + @OnClick(R.id.donate) + void donate() { + RetroUtil.openUrl(this, PAYPAL_ME_URL); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_donation); + ButterKnife.bind(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + int primaryColor = ThemeStore.primaryColor(this); + mAppBarLayout.setBackgroundColor(primaryColor); + mToolbar.setBackgroundColor(primaryColor); + setSupportActionBar(mToolbar); + //noinspection ConstantConditions + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mToolbar.setNavigationOnClickListener(view -> onBackPressed()); + + mBillingProcessor + = new BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSE_KEY, this); + MDTintHelper.setTint(mProgressBar, ThemeStore.accentColor(this)); + + ((TextView) findViewById(R.id.donation)).setTextColor(ThemeStore.accentColor(this)); + } + + @Override + public void onBillingInitialized() { + loadSkuDetails(); + } + + private void loadSkuDetails() { + if (skuDetailsLoadAsyncTask != null) { + skuDetailsLoadAsyncTask.cancel(false); + } + skuDetailsLoadAsyncTask = new SkuDetailsLoadAsyncTask(this).execute(); + + } + + @Override + public void onProductPurchased(@NonNull String productId, TransactionDetails details) { + //loadSkuDetails(); + Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onBillingError(int errorCode, Throwable error) { + Log.e(TAG, "Billing error: code = " + errorCode, error); + } + + @Override + public void onPurchaseHistoryRestored() { + //loadSkuDetails(); + Toast.makeText(this, R.string.restored_previous_purchases, Toast.LENGTH_SHORT).show(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (!mBillingProcessor.handleActivityResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data); + } + } + + @Override + public void onDestroy() { + if (mBillingProcessor != null) { + mBillingProcessor.release(); + } + if (skuDetailsLoadAsyncTask != null) { + skuDetailsLoadAsyncTask.cancel(true); + } + super.onDestroy(); + } + + private static class SkuDetailsLoadAsyncTask extends AsyncTask> { + private final WeakReference donationDialogWeakReference; + + public SkuDetailsLoadAsyncTask(SupportDevelopmentActivity donationsDialog) { + this.donationDialogWeakReference = new WeakReference<>(donationsDialog); + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + SupportDevelopmentActivity dialog = donationDialogWeakReference.get(); + if (dialog == null) return; + + dialog.mProgressContainer.setVisibility(View.VISIBLE); + dialog.mListView.setVisibility(View.GONE); + } + + @Override + protected List doInBackground(Void... params) { + SupportDevelopmentActivity dialog = donationDialogWeakReference.get(); + if (dialog != null) { + final String[] ids = dialog.getResources().getStringArray(DONATION_PRODUCT_IDS); + return dialog.mBillingProcessor.getPurchaseListingDetails(new ArrayList<>(Arrays.asList(ids))); + } + cancel(false); + return null; + } + + @Override + protected void onPostExecute(List skuDetails) { + super.onPostExecute(skuDetails); + SupportDevelopmentActivity dialog = donationDialogWeakReference.get(); + if (dialog == null) return; + + if (skuDetails == null || skuDetails.isEmpty()) { + //Toast.makeText(dialog, "Error loading items", Toast.LENGTH_SHORT).show(); + //dialog.finish(); + dialog.mProgressContainer.setVisibility(View.GONE); + return; + } + + //noinspection ConstantConditions + dialog.mProgressContainer.setVisibility(View.GONE); + dialog.mListView.setItemAnimator(new DefaultItemAnimator()); + dialog.mListView.setLayoutManager(new GridLayoutManager(dialog, 2)); + dialog.mListView.setAdapter(new SkuDetailsAdapter(dialog, skuDetails)); + dialog.mListView.setVisibility(View.VISIBLE); + } + + + } + + static class SkuDetailsAdapter extends RecyclerView.Adapter { + @LayoutRes + private static int LAYOUT_RES_ID = R.layout.item_donation_option; + + SupportDevelopmentActivity donationsDialog; + List skuDetailsList = new ArrayList<>(); + + public SkuDetailsAdapter(@NonNull SupportDevelopmentActivity donationsDialog, @NonNull List objects) { + this.donationsDialog = donationsDialog; + skuDetailsList = objects; + } + + private static void strikeThrough(TextView textView, boolean strikeThrough) { + textView.setPaintFlags(strikeThrough ? textView.getPaintFlags() | + Paint.STRIKE_THRU_TEXT_FLAG : textView.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG); + } + + private int getIcon(int position) { + switch (position) { + case 0: + return R.drawable.ic_cookie_white_24dp; + case 1: + return R.drawable.ic_take_away_white_24dp; + case 2: + return R.drawable.ic_take_away_coffe_white_24dp; + case 3: + return R.drawable.ic_beer_white_24dp; + case 4: + return R.drawable.ic_fast_food_meal_white_24dp; + case 5: + return R.drawable.ic_popcorn_white_24dp; + case 6: + return R.drawable.ic_card_giftcard_white_24dp; + default: + return R.drawable.ic_card_giftcard_white_24dp; + } + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + return new ViewHolder(LayoutInflater.from(donationsDialog) + .inflate(LAYOUT_RES_ID, viewGroup, false)); + } + + @Override + public void onBindViewHolder(ViewHolder viewHolder, int i) { + SkuDetails skuDetails = skuDetailsList.get(i); + if (skuDetails != null) { + viewHolder.title.setText(skuDetails.title.replace("(Retro Music Player)", "").trim()); + viewHolder.text.setText(skuDetails.description); + viewHolder.text.setVisibility(View.GONE); + viewHolder.price.setText(skuDetails.priceText); + viewHolder.image.setImageResource(getIcon(i)); + + final boolean purchased = donationsDialog.mBillingProcessor.isPurchased(skuDetails.productId); + int titleTextColor = purchased ? ATHUtil.resolveColor(donationsDialog, android.R.attr.textColorHint) : ThemeStore.textColorPrimary(donationsDialog); + int contentTextColor = purchased ? titleTextColor : ThemeStore.textColorSecondary(donationsDialog); + + //noinspection ResourceAsColor + viewHolder.title.setTextColor(titleTextColor); + viewHolder.text.setTextColor(contentTextColor); + viewHolder.price.setTextColor(titleTextColor); + + strikeThrough(viewHolder.title, purchased); + strikeThrough(viewHolder.text, purchased); + strikeThrough(viewHolder.price, purchased); + + viewHolder.itemView.setOnTouchListener((v, event) -> purchased); + viewHolder.itemView.setOnClickListener(v -> donationsDialog.donate(i)); + } + } + + @Override + public int getItemCount() { + return skuDetailsList.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.title) + TextView title; + @BindView(R.id.text) + TextView text; + @BindView(R.id.price) + TextView price; + @BindView(R.id.image) + IconImageView image; + + public ViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/UserInfoActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/UserInfoActivity.java new file mode 100644 index 00000000..303d1cf9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/UserInfoActivity.java @@ -0,0 +1,33 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.os.Bundle; + +import butterknife.ButterKnife; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.ui.activities.base.AbsBaseActivity; +import code.name.monkey.retromusic.ui.fragments.intro.NameFragment; + +public class UserInfoActivity extends AbsBaseActivity { + private static final String TAG = "UserInfoActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + setDrawUnderStatusbar(true); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_user_info); + + ButterKnife.bind(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + setLightNavigationBar(true); + + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction() + .replace(R.id.fragment_container, new NameFragment(), TAG) + .commit(); + } + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.java new file mode 100644 index 00000000..3c16824e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.java @@ -0,0 +1,156 @@ +package code.name.monkey.retromusic.ui.activities.base; + +import android.Manifest; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; +import android.support.v4.app.ActivityCompat; +import android.view.KeyEvent; +import android.view.View; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; + + +public abstract class AbsBaseActivity extends AbsThemeActivity { + public static final int PERMISSION_REQUEST = 100; + private boolean hadPermissions; + private String[] permissions; + private String permissionDeniedMessage; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setVolumeControlStream(AudioManager.STREAM_MUSIC); + + permissions = getPermissionsToRequest(); + hadPermissions = hasPermissions(); + + setPermissionDeniedMessage(null); + + + } + + @Override + protected void onPostCreate(@Nullable Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + if (!hasPermissions()) { + requestPermissions(); + } + } + + @Override + protected void onResume() { + super.onResume(); + final boolean hasPermissions = hasPermissions(); + if (hasPermissions != hadPermissions) { + hadPermissions = hasPermissions; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + onHasPermissionsChanged(hasPermissions); + } + } + + } + + protected void onHasPermissionsChanged(boolean hasPermissions) { + // implemented by sub classes + } + + @Override + public boolean dispatchKeyEvent(@NonNull KeyEvent event) { + if (event.getKeyCode() == KeyEvent.KEYCODE_MENU && event.getAction() == KeyEvent.ACTION_UP) { + showOverflowMenu(); + return true; + } + return super.dispatchKeyEvent(event); + } + + protected void showOverflowMenu() { + + } + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + + @Nullable + protected String[] getPermissionsToRequest() { + return null; + } + + protected View getSnackBarContainer() { + return getWindow().getDecorView(); + } + + private String getPermissionDeniedMessage() { + return permissionDeniedMessage == null ? getString(R.string.permissions_denied) : permissionDeniedMessage; + } + + protected void setPermissionDeniedMessage(String message) { + permissionDeniedMessage = message; + } + + protected void requestPermissions() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permissions != null) { + requestPermissions(permissions, PERMISSION_REQUEST); + } + } + + protected boolean hasPermissions() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permissions != null) { + for (String permission : permissions) { + if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + } + return true; + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == PERMISSION_REQUEST) { + for (int grantResult : grantResults) { + if (grantResult != PackageManager.PERMISSION_GRANTED) { + if (ActivityCompat.shouldShowRequestPermissionRationale(AbsBaseActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + //User has deny from permission dialog + Snackbar.make(getSnackBarContainer(), getPermissionDeniedMessage(), + Snackbar.LENGTH_INDEFINITE) + .setAction(R.string.action_grant, view -> requestPermissions()) + .setActionTextColor(ThemeStore.accentColor(this)) + .show(); + } else { + // User has deny permission and checked never show permission dialog so you can redirect to Application settings page + Snackbar.make(getSnackBarContainer(), getPermissionDeniedMessage(), + Snackbar.LENGTH_INDEFINITE) + .setAction(R.string.action_settings, view -> { + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", AbsBaseActivity.this.getPackageName(), null); + intent.setData(uri); + startActivity(intent); + }) + .setActionTextColor(ThemeStore.accentColor(this)) + .show(); + } + return; + } + } + hadPermissions = true; + onHasPermissionsChanged(true); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsMusicServiceActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsMusicServiceActivity.java new file mode 100644 index 00000000..4d0f28a6 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsMusicServiceActivity.java @@ -0,0 +1,222 @@ +package code.name.monkey.retromusic.ui.activities.base; + +import android.Manifest; +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 android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +import code.name.monkey.retromusic.interfaces.MusicServiceEventListener; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; + +import static code.name.monkey.retromusic.Constants.MEDIA_STORE_CHANGED; +import static code.name.monkey.retromusic.Constants.META_CHANGED; +import static code.name.monkey.retromusic.Constants.PLAY_STATE_CHANGED; +import static code.name.monkey.retromusic.Constants.QUEUE_CHANGED; +import static code.name.monkey.retromusic.Constants.REPEAT_MODE_CHANGED; +import static code.name.monkey.retromusic.Constants.SHUFFLE_MODE_CHANGED; + + +public abstract class AbsMusicServiceActivity extends AbsBaseActivity implements MusicServiceEventListener { + public static final String TAG = AbsMusicServiceActivity.class.getSimpleName(); + + private final ArrayList mMusicServiceEventListeners = new ArrayList<>(); + + private MusicPlayerRemote.ServiceToken serviceToken; + private MusicStateReceiver musicStateReceiver; + private boolean receiverRegistered; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + serviceToken = MusicPlayerRemote.bindToService(this, new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + AbsMusicServiceActivity.this.onServiceConnected(); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + AbsMusicServiceActivity.this.onServiceDisconnected(); + } + }); + + setPermissionDeniedMessage(getString(R.string.permission_external_storage_denied)); + } + + @Override + public void onDestroy() { + super.onDestroy(); + MusicPlayerRemote.unbindFromService(serviceToken); + if (receiverRegistered) { + unregisterReceiver(musicStateReceiver); + receiverRegistered = false; + } + } + + public void addMusicServiceEventListener(final MusicServiceEventListener listener) { + if (listener != null) { + mMusicServiceEventListeners.add(listener); + } + } + + public void removeMusicServiceEventListener(final MusicServiceEventListener listener) { + if (listener != null) { + mMusicServiceEventListeners.remove(listener); + } + } + + @Override + public void onServiceConnected() { + if (!receiverRegistered) { + musicStateReceiver = new MusicStateReceiver(this); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(PLAY_STATE_CHANGED); + filter.addAction(SHUFFLE_MODE_CHANGED); + filter.addAction(REPEAT_MODE_CHANGED); + filter.addAction(META_CHANGED); + filter.addAction(QUEUE_CHANGED); + filter.addAction(MEDIA_STORE_CHANGED); + + registerReceiver(musicStateReceiver, filter); + + receiverRegistered = true; + } + + for (MusicServiceEventListener listener : mMusicServiceEventListeners) { + if (listener != null) { + listener.onServiceConnected(); + } + } + } + + @Override + public void onServiceDisconnected() { + if (receiverRegistered) { + unregisterReceiver(musicStateReceiver); + receiverRegistered = false; + } + + for (MusicServiceEventListener listener : mMusicServiceEventListeners) { + if (listener != null) { + listener.onServiceDisconnected(); + } + } + } + + @Override + public void onPlayingMetaChanged() { + for (MusicServiceEventListener listener : mMusicServiceEventListeners) { + if (listener != null) { + listener.onPlayingMetaChanged(); + } + } + } + + @Override + public void onQueueChanged() { + for (MusicServiceEventListener listener : mMusicServiceEventListeners) { + if (listener != null) { + listener.onQueueChanged(); + } + } + } + + @Override + public void onPlayStateChanged() { + for (MusicServiceEventListener listener : mMusicServiceEventListeners) { + if (listener != null) { + listener.onPlayStateChanged(); + } + } + } + + @Override + public void onMediaStoreChanged() { + for (MusicServiceEventListener listener : mMusicServiceEventListeners) { + if (listener != null) { + listener.onMediaStoreChanged(); + } + } + } + + @Override + public void onRepeatModeChanged() { + for (MusicServiceEventListener listener : mMusicServiceEventListeners) { + if (listener != null) { + listener.onRepeatModeChanged(); + } + } + } + + @Override + public void onShuffleModeChanged() { + for (MusicServiceEventListener listener : mMusicServiceEventListeners) { + if (listener != null) { + listener.onShuffleModeChanged(); + } + } + } + + @Override + protected void onHasPermissionsChanged(boolean hasPermissions) { + super.onHasPermissionsChanged(hasPermissions); + Intent intent = new Intent(MEDIA_STORE_CHANGED); + intent.putExtra("from_permissions_changed", true); // just in case we need to know this at some point + sendBroadcast(intent); + } + + @Nullable + @Override + protected String[] getPermissionsToRequest() { + return new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; + } + + private static final class MusicStateReceiver extends BroadcastReceiver { + + private final WeakReference reference; + + public MusicStateReceiver(final AbsMusicServiceActivity activity) { + reference = new WeakReference<>(activity); + } + + @Override + public void onReceive(final Context context, @NonNull final Intent intent) { + final String action = intent.getAction(); + AbsMusicServiceActivity activity = reference.get(); + if (activity != null && action != null) { + switch (action) { + case META_CHANGED: + activity.onPlayingMetaChanged(); + break; + case QUEUE_CHANGED: + activity.onQueueChanged(); + break; + case PLAY_STATE_CHANGED: + activity.onPlayStateChanged(); + break; + case REPEAT_MODE_CHANGED: + activity.onRepeatModeChanged(); + break; + case SHUFFLE_MODE_CHANGED: + activity.onShuffleModeChanged(); + break; + case MEDIA_STORE_CHANGED: + activity.onMediaStoreChanged(); + break; + } + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsSlidingMusicPanelActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsSlidingMusicPanelActivity.java new file mode 100644 index 00000000..402b7fc1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsSlidingMusicPanelActivity.java @@ -0,0 +1,434 @@ +package code.name.monkey.retromusic.ui.activities.base; + +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.annotation.FloatRange; +import android.support.annotation.LayoutRes; +import android.support.v4.app.Fragment; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.animation.PathInterpolator; + +import com.sothree.slidinguppanel.SlidingUpPanelLayout; +import com.sothree.slidinguppanel.SlidingUpPanelLayout.PanelState; + +import butterknife.BindView; +import butterknife.ButterKnife; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.ui.fragments.MiniPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.NowPlayingScreen; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.adaptive.AdaptiveFragment; +import code.name.monkey.retromusic.ui.fragments.player.blur.BlurPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.card.CardFragment; +import code.name.monkey.retromusic.ui.fragments.player.cardblur.CardBlurFragment; +import code.name.monkey.retromusic.ui.fragments.player.color.ColorFragment; +import code.name.monkey.retromusic.ui.fragments.player.flat.FlatPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.full.FullPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.hmm.HmmPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.material.MaterialFragment; +import code.name.monkey.retromusic.ui.fragments.player.normal.PlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.plain.PlainPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.simple.SimplePlayerFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.ViewUtil; +import code.name.monkey.retromusic.views.BottomNavigationViewEx; + +public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivity implements + SlidingUpPanelLayout.PanelSlideListener, + PlayerFragment.Callbacks { + + public static final String TAG = AbsSlidingMusicPanelActivity.class.getSimpleName(); + + @BindView(R.id.bottom_navigation) + BottomNavigationViewEx bottomNavigationView; + @BindView(R.id.sliding_layout) + SlidingUpPanelLayout slidingUpPanelLayout; + + private int navigationbarColor; + private int taskColor; + private boolean lightStatusBar; + private boolean lightNavigationBar; + private NowPlayingScreen currentNowPlayingScreen; + private AbsPlayerFragment playerFragment; + private MiniPlayerFragment miniPlayerFragment; + private ValueAnimator navigationBarColorAnimator; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(createContentView()); + ButterKnife.bind(this); + choosFragmentForTheme(); + //noinspection ConstantConditions + miniPlayerFragment.getView().setOnClickListener(v -> expandPanel()); + slidingUpPanelLayout.getViewTreeObserver() + .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + slidingUpPanelLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); + + if (getPanelState() == PanelState.EXPANDED) { + onPanelSlide(slidingUpPanelLayout, 1); + onPanelExpanded(slidingUpPanelLayout); + } else if (getPanelState() == PanelState.COLLAPSED) { + onPanelCollapsed(slidingUpPanelLayout); + } else { + playerFragment.onHide(); + } + } + }); + + setupBottomView(); + slidingUpPanelLayout.addPanelSlideListener(this); + + } + + private void choosFragmentForTheme() { + currentNowPlayingScreen = PreferenceUtil.getInstance(this).getNowPlayingScreen(); + + Fragment fragment; // must implement AbsPlayerFragment + switch (currentNowPlayingScreen) { + case MATERIAL: + fragment = new MaterialFragment(); + break; + case BLUR: + fragment = new BlurPlayerFragment(); + break; + case FLAT: + fragment = new FlatPlayerFragment(); + break; + case PLAIN: + fragment = new PlainPlayerFragment(); + break; + case FULL: + fragment = new FullPlayerFragment(); + break; + case COLOR: + fragment = new ColorFragment(); + break; + case CARD: + fragment = new CardFragment(); + break; + case SIMPLE: + fragment = new SimplePlayerFragment(); + break; + case TINY: + fragment = new HmmPlayerFragment(); + break; + case BLUR_CARD: + fragment = new CardBlurFragment(); + break; + case ADAPTIVE: + fragment = new AdaptiveFragment(); + break; + + case NORMAL: + default: + fragment = new PlayerFragment(); + break; + } + getSupportFragmentManager().beginTransaction().replace(R.id.player_fragment_container, fragment) + .commit(); + getSupportFragmentManager().executePendingTransactions(); + + playerFragment = (AbsPlayerFragment) getSupportFragmentManager() + .findFragmentById(R.id.player_fragment_container); + miniPlayerFragment = (MiniPlayerFragment) getSupportFragmentManager() + .findFragmentById(R.id.mini_player_fragment); + } + + private void setupBottomView() { + bottomNavigationView.setSelectedItemId(PreferenceUtil.getInstance(this).getLastPage()); + bottomNavigationView.setBackgroundColor(ThemeStore.primaryColor(this)); + bottomNavigationView.enableAnimation(false); + bottomNavigationView.enableItemShiftingMode(false); + bottomNavigationView.enableShiftingMode(false); + bottomNavigationView.setTextSize(10f); + bottomNavigationView.setTextVisibility(PreferenceUtil.getInstance(this).tabTitles()); + } + + @Override + protected void onResume() { + super.onResume(); + if (currentNowPlayingScreen != PreferenceUtil.getInstance(this).getNowPlayingScreen()) { + postRecreate(); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (navigationBarColorAnimator != null) { + navigationBarColorAnimator.cancel(); // just in case + } + } + + + protected abstract View createContentView(); + + @Override + public void onServiceConnected() { + super.onServiceConnected(); + if (!MusicPlayerRemote.getPlayingQueue().isEmpty()) { + slidingUpPanelLayout.getViewTreeObserver() + .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + slidingUpPanelLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); + hideBottomBar(false); + } + }); + }// don't call hideBottomBar(true) here as it causes a bug with the SlidingUpPanelLayout + } + + @Override + public void onQueueChanged() { + super.onQueueChanged(); + hideBottomBar(MusicPlayerRemote.getPlayingQueue().isEmpty()); + } + + @Override + public void onPanelSlide(View panel, @FloatRange(from = 0, to = 1) float slideOffset) { + bottomNavigationView.setTranslationY(slideOffset * 400); + setMiniPlayerAlphaProgress(slideOffset); + //findViewById(R.id.player_fragment_container).setAlpha(slideOffset); + } + + @Override + public void onPanelStateChanged(View panel, PanelState previousState, PanelState newState) { + switch (newState) { + case COLLAPSED: + onPanelCollapsed(panel); + break; + case EXPANDED: + onPanelExpanded(panel); + break; + case ANCHORED: + collapsePanel(); // this fixes a bug where the panel would get stuck for some reason + break; + } + } + + public void onPanelCollapsed(View panel) { + // restore values + super.setLightStatusbar(lightStatusBar); + super.setTaskDescriptionColor(taskColor); + super.setNavigationbarColor(navigationbarColor); + super.setLightNavigationBar(lightNavigationBar); + + playerFragment.setMenuVisibility(false); + playerFragment.setUserVisibleHint(false); + playerFragment.onHide(); + } + + public void onPanelExpanded(View panel) { + // setting fragments values + int playerFragmentColor = playerFragment.getPaletteColor(); + super.setTaskDescriptionColor(playerFragmentColor); + + if (currentNowPlayingScreen == NowPlayingScreen.COLOR) { + super.setNavigationbarColor(playerFragmentColor); + } else { + super.setNavigationbarColor(ThemeStore.primaryColor(this)); + } + + setLightStatusBar(); + + playerFragment.setMenuVisibility(true); + playerFragment.setUserVisibleHint(true); + playerFragment.onShow(); + } + + private void setLightStatusBar() { + super.setLightStatusbar(!PreferenceUtil.getInstance(this).getAdaptiveColor() && + ColorUtil.isColorLight(ThemeStore.primaryColor(this)) && ( + currentNowPlayingScreen == NowPlayingScreen.FLAT + || currentNowPlayingScreen == NowPlayingScreen.PLAIN + || currentNowPlayingScreen == NowPlayingScreen.SIMPLE + || currentNowPlayingScreen == NowPlayingScreen.NORMAL + || currentNowPlayingScreen == NowPlayingScreen.ADAPTIVE) + || currentNowPlayingScreen == NowPlayingScreen.TINY); + } + + @Override + public void setLightStatusbar(boolean enabled) { + lightStatusBar = enabled; + if (getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) { + super.setLightStatusbar(enabled); + } + } + + @Override + public void setLightNavigationBar(boolean enabled) { + lightNavigationBar = enabled; + /*if (getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) { + super.setLightNavigationBar(enabled); + }*/ + } + + @Override + public void setTaskDescriptionColor(@ColorInt int color) { + taskColor = color; + if (getPanelState() == null || getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) { + super.setTaskDescriptionColor(color); + } + } + + @Override + public void setNavigationbarColor(int color) { + navigationbarColor = color; + if (getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) { + if (navigationBarColorAnimator != null) { + navigationBarColorAnimator.cancel(); + } + super.setNavigationbarColor(color); + } + } + + @Override + public void onPaletteColorChanged() { + int playerFragmentColor = playerFragment.getPaletteColor(); + + if (getPanelState() == PanelState.EXPANDED) { + super.setTaskDescriptionColor(playerFragmentColor); + if (currentNowPlayingScreen == NowPlayingScreen.COLOR) { + super.setNavigationbarColor(playerFragmentColor); + } + } + } + + private void setMiniPlayerAlphaProgress(@FloatRange(from = 0, to = 1) float progress) { + if (miniPlayerFragment == null) { + return; + } + float alpha = 1 - progress; + miniPlayerFragment.getView().setAlpha(alpha); + // necessary to make the views below clickable + miniPlayerFragment.getView().setVisibility(alpha == 0 ? View.GONE : View.VISIBLE); + + } + + public void hideBottomBar(final boolean hide) { + + int heightOfBar = + getResources().getDimensionPixelSize(R.dimen.mini_player_height); + int heightOfBarWithTabs = + getResources().getDimensionPixelSize(R.dimen.mini_player_height_expanded); + + if (hide) { + slidingUpPanelLayout.setPanelHeight(0); + collapsePanel(); + } else { + if (!MusicPlayerRemote.getPlayingQueue().isEmpty()) { + slidingUpPanelLayout.setPanelHeight(bottomNavigationView.getVisibility() == View.VISIBLE ? + heightOfBarWithTabs : heightOfBar); + } + } + } + + public void setBottomBarVisibility(int gone) { + if (bottomNavigationView != null) { + //TransitionManager.beginDelayedTransition(bottomNavigationView); + bottomNavigationView.setVisibility(gone); + hideBottomBar(false); + } + } + + protected View wrapSlidingMusicPanel(@LayoutRes int resId) { + @SuppressLint("InflateParams") + View slidingMusicPanelLayout = getLayoutInflater() + .inflate(R.layout.sliding_music_panel_layout, null); + ViewGroup contentContainer = slidingMusicPanelLayout.findViewById(R.id.content_container); + getLayoutInflater().inflate(resId, contentContainer); + return slidingMusicPanelLayout; + } + + @Override + public void onBackPressed() { + if (!handleBackPress()) { + super.onBackPressed(); + } + } + + public boolean handleBackPress() { + if (slidingUpPanelLayout.getPanelHeight() != 0 && playerFragment.onBackPressed()) { + return true; + } + if (getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) { + collapsePanel(); + return true; + } + return false; + } + + private void animateNavigationBarColor(int color) { + if (navigationBarColorAnimator != null) { + navigationBarColorAnimator.cancel(); + } + navigationBarColorAnimator = ValueAnimator.ofArgb(getWindow().getNavigationBarColor(), color) + .setDuration(ViewUtil.RETRO_MUSIC_ANIM_TIME); + navigationBarColorAnimator.setInterpolator(new PathInterpolator(0.4f, 0f, 1f, 1f)); + navigationBarColorAnimator.addUpdateListener(animation -> { + int playerFragmentColorDark = ColorUtil.darkenColor((Integer) animation.getAnimatedValue()); + + bottomNavigationView.setBackgroundColor(playerFragmentColorDark); + miniPlayerFragment.setColor(playerFragmentColorDark); + AbsSlidingMusicPanelActivity.super.setNavigationbarColor(playerFragmentColorDark); + + View view = getWindow().getDecorView().getRootView(); + view.setBackgroundColor(playerFragmentColorDark); + + if (view.findViewById(R.id.toolbar) != null) { + view.findViewById(R.id.toolbar).setBackgroundColor(playerFragmentColorDark); + } + if (view.findViewById(R.id.appbar) != null) { + view.findViewById(R.id.appbar).setBackgroundColor(playerFragmentColorDark); + } + if (view.findViewById(R.id.status_bar) != null) { + view.findViewById(R.id.status_bar) + .setBackgroundColor(ColorUtil.darkenColor(playerFragmentColorDark)); + } + }); + navigationBarColorAnimator.start(); + } + + @Override + protected View getSnackBarContainer() { + return findViewById(R.id.content_container); + } + + public SlidingUpPanelLayout getSlidingUpPanelLayout() { + return slidingUpPanelLayout; + } + + public MiniPlayerFragment getMiniPlayerFragment() { + return miniPlayerFragment; + } + + public AbsPlayerFragment getPlayerFragment() { + return playerFragment; + } + + public BottomNavigationViewEx getBottomNavigationView() { + return bottomNavigationView; + } + + public SlidingUpPanelLayout.PanelState getPanelState() { + return slidingUpPanelLayout == null ? null : slidingUpPanelLayout.getPanelState(); + } + + public void collapsePanel() { + slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); + } + + public void expandPanel() { + slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsThemeActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsThemeActivity.java new file mode 100644 index 00000000..1a4632ac --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsThemeActivity.java @@ -0,0 +1,213 @@ +package code.name.monkey.retromusic.ui.activities.base; + +import android.graphics.Color; +import android.graphics.drawable.GradientDrawable; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.ColorInt; +import android.view.KeyEvent; +import android.view.View; +import android.view.WindowManager; + +import code.name.monkey.appthemehelper.ATH; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.common.ATHToolbarActivity; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialDialogsUtil; +import code.name.monkey.appthemehelper.util.VersionUtils; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroUtil; + +public abstract class AbsThemeActivity extends ATHToolbarActivity implements Runnable { + + private Handler handler = new Handler(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + setTheme(PreferenceUtil.getInstance(this).getGeneralTheme()); + hideStatusBar(); + super.onCreate(savedInstanceState); + MaterialDialogsUtil.updateMaterialDialogsThemeSingleton(this); + + changeBackgroundShape(); + setImmersiveFullscreen(); + registerSystemUiVisibility(); + toggleScreenOn(); + + } + + private void toggleScreenOn() { + if (PreferenceUtil.getInstance(this).isScreenOnEnabled()) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } else { + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (hasFocus) { + hideStatusBar(); + handler.removeCallbacks(this); + handler.postDelayed(this, 300); + } else { + handler.removeCallbacks(this); + } + } + + public void hideStatusBar() { + hideStatusBar(PreferenceUtil.getInstance(this).getFullScreenMode()); + } + + private void hideStatusBar(boolean fullscreen) { + final View statusBar = getWindow().getDecorView().getRootView().findViewById(R.id.status_bar); + if (statusBar != null) { + statusBar.setVisibility(fullscreen ? View.GONE : View.VISIBLE); + } + } + + + private void changeBackgroundShape() { + if (PreferenceUtil.getInstance(this).isRoundCorners()) { + getWindow().setBackgroundDrawableResource(R.drawable.round_window); + } else { + getWindow().setBackgroundDrawableResource(R.drawable.square_window); + } + View decor = getWindow().getDecorView(); + GradientDrawable gradientDrawable = (GradientDrawable) decor.getBackground(); + gradientDrawable.setColor(ThemeStore.primaryColor(this)); + } + + protected void setDrawUnderStatusbar(boolean drawUnderStatusbar) { + if (VersionUtils.hasLollipop()) { + RetroUtil.setAllowDrawUnderStatusBar(getWindow()); + } else if (VersionUtils.hasKitKat()) { + RetroUtil.setStatusBarTranslucent(getWindow()); + } + } + + /** + * This will set the color of the view with the id "status_bar" on KitKat and Lollipop. On + * Lollipop if no such view is found it will set the statusbar color using the native method. + * + * @param color the new statusbar color (will be shifted down on Lollipop and above) + */ + public void setStatusbarColor(int color) { + if (VersionUtils.hasKitKat()) { + final View statusBar = getWindow().getDecorView().getRootView().findViewById(R.id.status_bar); + if (statusBar != null) { + if (VersionUtils.hasLollipop()) { + statusBar.setBackgroundColor(ColorUtil.darkenColor(color)); + setLightStatusbarAuto(color); + } else { + statusBar.setBackgroundColor(color); + } + } else if (Build.VERSION.SDK_INT >= 21) { + getWindow().setStatusBarColor(ColorUtil.darkenColor(color)); + setLightStatusbarAuto(color); + } + } + } + + public void setStatusbarColorAuto() { + // we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat + setStatusbarColor(ThemeStore.primaryColor(this)); + } + + public void setTaskDescriptionColor(@ColorInt int color) { + ATH.setTaskDescriptionColor(this, color); + } + + public void setTaskDescriptionColorAuto() { + setTaskDescriptionColor(ThemeStore.primaryColor(this)); + } + + public void setNavigationbarColor(int color) { + if (ThemeStore.coloredNavigationBar(this)) { + ATH.setNavigationbarColor(this, color); + } else { + ATH.setNavigationbarColor(this, Color.BLACK); + } + } + + public void setNavigationbarColorAuto() { + setNavigationbarColor(ThemeStore.navigationBarColor(this)); + } + + public void setLightStatusbar(boolean enabled) { + ATH.setLightStatusbar(this, enabled); + } + + public void setLightStatusbarAuto(int bgColor) { + setLightStatusbar(ColorUtil.isColorLight(bgColor)); + } + + public void setLightNavigationBar(boolean enabled) { + if (!ATHUtil.isWindowBackgroundDark(this) && ThemeStore.coloredNavigationBar(this)) { + ATH.setLightNavigationbar(this, enabled); + } + } + + private void registerSystemUiVisibility() { + final View decorView = getWindow().getDecorView(); + decorView.setOnSystemUiVisibilityChangeListener(visibility -> { + if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { + setImmersiveFullscreen(); + } + }); + } + + private void unregisterSystemUiVisibility() { + final View decorView = getWindow().getDecorView(); + decorView.setOnSystemUiVisibilityChangeListener(null); + } + + public void setImmersiveFullscreen() { + int flags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + if (PreferenceUtil.getInstance(this).getFullScreenMode()) { + getWindow().getDecorView().setSystemUiVisibility(flags); + } + } + + public void exitFullscreen() { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } + + @Override + public void run() { + setImmersiveFullscreen(); + } + + @Override + protected void onStop() { + handler.removeCallbacks(this); + super.onStop(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + unregisterSystemUiVisibility(); + exitFullscreen(); + } + + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) { + handler.removeCallbacks(this); + handler.postDelayed(this, 500); + } + return super.onKeyDown(keyCode, event); + + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/AbsTagEditorActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/AbsTagEditorActivity.java new file mode 100755 index 00000000..1a6580b3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/AbsTagEditorActivity.java @@ -0,0 +1,367 @@ +package code.name.monkey.retromusic.ui.activities.tageditor; + +import android.app.SearchManager; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.FloatingActionButton; +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.afollestad.materialdialogs.MaterialDialog; + +import org.jaudiotagger.audio.AudioFile; +import org.jaudiotagger.audio.AudioFileIO; +import org.jaudiotagger.tag.FieldKey; +import org.jaudiotagger.tag.images.Artwork; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.ui.activities.base.AbsBaseActivity; +import code.name.monkey.retromusic.util.RetroUtil; + +public abstract class AbsTagEditorActivity extends AbsBaseActivity { + + public static final String EXTRA_ID = "extra_id"; + public static final String EXTRA_PALETTE = "extra_palette"; + private static final String TAG = AbsTagEditorActivity.class.getSimpleName(); + private static final int REQUEST_CODE_SELECT_IMAGE = 1000; + @BindView(R.id.save_fab) + FloatingActionButton save; + @BindView(R.id.image) + ImageView image; + @BindView(R.id.image_container) + FrameLayout imageContainer; + CharSequence[] items; + private int id; + private int paletteColorPrimary; + private boolean isInNoImageMode; + private List songPaths; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getContentViewLayout()); + ButterKnife.bind(this); + + getIntentExtras(); + + songPaths = getSongPaths(); + if (songPaths.isEmpty()) { + finish(); + return; + } + + setUpViews(); + setTaskDescriptionColorAuto(); + } + + private void setUpViews() { + setUpScrollView(); + setUpFab(); + setUpImageView(); + } + + private void setUpScrollView() { + //observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks); + } + + private void setUpImageView() { + loadCurrentImage(); + items = new CharSequence[]{ + getString(R.string.download_from_last_fm), + getString(R.string.pick_from_local_storage), + getString(R.string.web_search), + getString(R.string.remove_cover) + }; + image.setOnClickListener(v -> getShow()); + } + + protected MaterialDialog getShow() { + return new MaterialDialog.Builder(AbsTagEditorActivity.this) + .title(R.string.update_image) + .items(items) + .itemsCallback((dialog, itemView, position, text) -> { + switch (position) { + case 0: + getImageFromLastFM(); + break; + case 1: + startImagePicker(); + break; + case 2: + searchImageOnWeb(); + break; + case 3: + deleteImage(); + break; + } + }).show(); + } + + private void startImagePicker() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("image/*"); + startActivityForResult( + Intent.createChooser(intent, getString(R.string.pick_from_local_storage)), + REQUEST_CODE_SELECT_IMAGE); + } + + protected abstract void loadCurrentImage(); + + protected abstract void getImageFromLastFM(); + + protected abstract void searchImageOnWeb(); + + protected abstract void deleteImage(); + + private void setUpFab() { + save.setScaleX(0); + save.setScaleY(0); + save.setEnabled(false); + save.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + save(); + } + }); + + TintHelper.setTintAuto(save, ThemeStore.accentColor(this), true); + } + + protected abstract void save(); + + private void getIntentExtras() { + Bundle intentExtras = getIntent().getExtras(); + if (intentExtras != null) { + id = intentExtras.getInt(EXTRA_ID); + } + } + + protected abstract int getContentViewLayout(); + + @NonNull + protected abstract List getSongPaths(); + + protected void searchWebFor(String... keys) { + StringBuilder stringBuilder = new StringBuilder(); + for (String key : keys) { + stringBuilder.append(key); + stringBuilder.append(" "); + } + Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); + intent.putExtra(SearchManager.QUERY, stringBuilder.toString()); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + startActivity(intent); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + int id = item.getItemId(); + switch (id) { + case android.R.id.home: + super.onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + protected void setNoImageMode() { + isInNoImageMode = true; + imageContainer.setVisibility(View.GONE); + image.setVisibility(View.GONE); + image.setEnabled(false); + + setColors(getIntent().getIntExtra(EXTRA_PALETTE, ThemeStore.primaryColor(this))); + } + + protected void dataChanged() { + showFab(); + } + + private void showFab() { + save.animate() + .setDuration(500) + .setInterpolator(new OvershootInterpolator()) + .scaleX(1) + .scaleY(1) + .start(); + save.setEnabled(true); + } + + protected void setImageBitmap(@Nullable final Bitmap bitmap, int bgColor) { + if (bitmap == null) { + image.setImageResource(R.drawable.default_album_art); + } else { + image.setImageBitmap(bitmap); + } + setColors(bgColor); + } + + protected void setColors(int color) { + paletteColorPrimary = color; + } + + protected void writeValuesToFiles(@NonNull final Map fieldKeyValueMap, + @Nullable final ArtworkInfo artworkInfo) { + RetroUtil.hideSoftKeyboard(this); + + new WriteTagsAsyncTask(this) + .execute(new WriteTagsAsyncTask.LoadingInfo(getSongPaths(), fieldKeyValueMap, artworkInfo)); + } + + protected int getId() { + return id; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, + @NonNull Intent imageReturnedIntent) { + super.onActivityResult(requestCode, resultCode, imageReturnedIntent); + switch (requestCode) { + case REQUEST_CODE_SELECT_IMAGE: + if (resultCode == RESULT_OK) { + Uri selectedImage = imageReturnedIntent.getData(); + loadImageFromFile(selectedImage); + } + break; + } + } + + protected abstract void loadImageFromFile(Uri selectedFile); + + @NonNull + private AudioFile getAudioFile(@NonNull String path) { + try { + return AudioFileIO.read(new File(path)); + } catch (Exception e) { + Log.e(TAG, "Could not read audio file " + path, e); + return new AudioFile(); + } + } + + @Nullable + String getAlbumArtist() { + try { + return getAudioFile(songPaths.get(0)).getTagOrCreateAndSetDefault() + .getFirst(FieldKey.ALBUM_ARTIST); + } catch (Exception ignored) { + return null; + } + } + + @Nullable + protected String getSongTitle() { + try { + return getAudioFile(songPaths.get(0)).getTagOrCreateAndSetDefault().getFirst(FieldKey.TITLE); + } catch (Exception ignored) { + return null; + } + } + + @Nullable + protected String getAlbumTitle() { + try { + return getAudioFile(songPaths.get(0)).getTagOrCreateAndSetDefault().getFirst(FieldKey.ALBUM); + } catch (Exception ignored) { + return null; + } + } + + @Nullable + protected String getArtistName() { + try { + return getAudioFile(songPaths.get(0)).getTagOrCreateAndSetDefault().getFirst(FieldKey.ARTIST); + } catch (Exception ignored) { + return null; + } + } + + @Nullable + protected String getAlbumArtistName() { + try { + return getAudioFile(songPaths.get(0)).getTagOrCreateAndSetDefault() + .getFirst(FieldKey.ALBUM_ARTIST); + } catch (Exception ignored) { + return null; + } + } + + @Nullable + protected String getGenreName() { + try { + return getAudioFile(songPaths.get(0)).getTagOrCreateAndSetDefault().getFirst(FieldKey.GENRE); + } catch (Exception ignored) { + return null; + } + } + + @Nullable + protected String getSongYear() { + try { + return getAudioFile(songPaths.get(0)).getTagOrCreateAndSetDefault().getFirst(FieldKey.YEAR); + } catch (Exception ignored) { + return null; + } + } + + @Nullable + protected String getTrackNumber() { + try { + return getAudioFile(songPaths.get(0)).getTagOrCreateAndSetDefault().getFirst(FieldKey.TRACK); + } catch (Exception ignored) { + return null; + } + } + + @Nullable + protected String getLyrics() { + try { + return getAudioFile(songPaths.get(0)).getTagOrCreateAndSetDefault().getFirst(FieldKey.LYRICS); + } catch (Exception ignored) { + return null; + } + } + + @Nullable + protected Bitmap getAlbumArt() { + try { + Artwork artworkTag = getAudioFile(songPaths.get(0)).getTagOrCreateAndSetDefault() + .getFirstArtwork(); + if (artworkTag != null) { + byte[] artworkBinaryData = artworkTag.getBinaryData(); + return BitmapFactory.decodeByteArray(artworkBinaryData, 0, artworkBinaryData.length); + } + return null; + } catch (Exception ignored) { + return null; + } + } + + public static class ArtworkInfo { + + public final int albumId; + final Bitmap artwork; + + ArtworkInfo(int albumId, Bitmap artwork) { + this.albumId = albumId; + this.artwork = artwork; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/AlbumTagEditorActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/AlbumTagEditorActivity.java new file mode 100755 index 00000000..a83a17f4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/AlbumTagEditorActivity.java @@ -0,0 +1,281 @@ +package code.name.monkey.retromusic.ui.activities.tageditor; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.AppBarLayout; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.Toolbar; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.widget.EditText; +import android.widget.Toast; + +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 org.jaudiotagger.tag.FieldKey; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.loaders.AlbumLoader; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.rest.LastFMRestClient; +import code.name.monkey.retromusic.rest.model.LastFmAlbum; +import code.name.monkey.retromusic.util.ImageUtil; +import code.name.monkey.retromusic.util.LastFMUtil; +import code.name.monkey.retromusic.util.RetroColorUtil; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + + +public class AlbumTagEditorActivity extends AbsTagEditorActivity implements TextWatcher { + + public static final String TAG = AlbumTagEditorActivity.class.getSimpleName(); + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.app_bar) + AppBarLayout appBarLayout; + @BindView(R.id.title) + EditText albumTitle; + @BindView(R.id.album_artist) + EditText albumArtist; + @BindView(R.id.genre) + EditText genre; + @BindView(R.id.year) + EditText year; + @BindView(R.id.gradient_background) + View background; + private Bitmap albumArtBitmap; + private boolean deleteAlbumArt; + private LastFMRestClient lastFMRestClient; + + private void setupToolbar() { + //toolbar.setBackgroundColor(ThemeStore.primaryColor(this)); + toolbar.setNavigationOnClickListener(v -> onBackPressed()); + setTitle(R.string.action_tag_editor); + setSupportActionBar(toolbar); + } + + @OnClick(R.id.edit) + void edit() { + getShow(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ButterKnife.bind(this); + + lastFMRestClient = new LastFMRestClient(this); + + setUpViews(); + setupToolbar(); + } + + @Override + protected int getContentViewLayout() { + return R.layout.activity_album_tag_editor; + } + + private void setUpViews() { + fillViewsWithFileTags(); + albumTitle.addTextChangedListener(this); + albumArtist.addTextChangedListener(this); + genre.addTextChangedListener(this); + year.addTextChangedListener(this); + } + + + private void fillViewsWithFileTags() { + albumTitle.setText(getAlbumTitle()); + albumArtist.setText(getAlbumArtistName()); + genre.setText(getGenreName()); + year.setText(getSongYear()); + } + + @Override + protected void loadCurrentImage() { + Bitmap bitmap = getAlbumArt(); + setImageBitmap(bitmap, RetroColorUtil.getColor(RetroColorUtil.generatePalette(bitmap), + ATHUtil.resolveColor(this, R.attr.defaultFooterColor))); + deleteAlbumArt = false; + } + + @Override + protected void getImageFromLastFM() { + String albumTitleStr = albumTitle.getText().toString(); + String albumArtistNameStr = albumArtist.getText().toString(); + if (albumArtistNameStr.trim().equals("") || albumTitleStr.trim().equals("")) { + Toast.makeText(this, getResources().getString(R.string.album_or_artist_empty), + Toast.LENGTH_SHORT).show(); + return; + } + + lastFMRestClient.getApiService() + .getAlbumInfo(albumTitleStr, albumArtistNameStr, null) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeOn(Schedulers.computation()) + .subscribe(this::extractDetails); + } + + private void extractDetails(@NonNull LastFmAlbum lastFmAlbum) { + if (lastFmAlbum.getAlbum() != null) { + + String url = LastFMUtil.getLargestAlbumImageUrl(lastFmAlbum.getAlbum().getImage()); + + if (!TextUtils.isEmpty(url) && url.trim().length() > 0) { + Glide.with(this) + .load(url) + .asBitmap() + .transcode(new BitmapPaletteTranscoder(this), BitmapPaletteWrapper.class) + .diskCacheStrategy(DiskCacheStrategy.SOURCE) + .error(R.drawable.default_album_art) + .into(new SimpleTarget() { + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + e.printStackTrace(); + Toast.makeText(AlbumTagEditorActivity.this, e.toString(), Toast.LENGTH_LONG).show(); + } + + @Override + public void onResourceReady(BitmapPaletteWrapper resource, + GlideAnimation glideAnimation) { + albumArtBitmap = ImageUtil.resizeBitmap(resource.getBitmap(), 2048); + setImageBitmap(albumArtBitmap, RetroColorUtil.getColor(resource.getPalette(), + ContextCompat.getColor(AlbumTagEditorActivity.this, R.color.md_grey_500))); + deleteAlbumArt = false; + dataChanged(); + setResult(RESULT_OK); + } + }); + return; + } + if (lastFmAlbum.getAlbum().getTags().getTag().size() > 0) { + genre.setText(lastFmAlbum.getAlbum().getTags().getTag().get(0).getName()); + } + + } + toastLoadingFailed(); + } + + private void toastLoadingFailed() { + Toast.makeText(AlbumTagEditorActivity.this, + R.string.could_not_download_album_cover, Toast.LENGTH_SHORT).show(); + } + + @Override + protected void searchImageOnWeb() { + searchWebFor(albumTitle.getText().toString(), albumArtist.getText().toString()); + } + + @Override + protected void deleteImage() { + setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.default_album_art), + ATHUtil.resolveColor(this, R.attr.defaultFooterColor)); + deleteAlbumArt = true; + dataChanged(); + } + + @Override + protected void save() { + Map fieldKeyValueMap = new EnumMap<>(FieldKey.class); + fieldKeyValueMap.put(FieldKey.ALBUM, albumTitle.getText().toString()); + //android seems not to recognize album_artist field so we additionally write the normal artist field + fieldKeyValueMap.put(FieldKey.ARTIST, albumArtist.getText().toString()); + fieldKeyValueMap.put(FieldKey.ALBUM_ARTIST, albumArtist.getText().toString()); + fieldKeyValueMap.put(FieldKey.GENRE, genre.getText().toString()); + fieldKeyValueMap.put(FieldKey.YEAR, year.getText().toString()); + + writeValuesToFiles(fieldKeyValueMap, deleteAlbumArt ? new ArtworkInfo(getId(), null) + : albumArtBitmap == null ? null : new ArtworkInfo(getId(), albumArtBitmap)); + } + + @NonNull + @Override + protected List getSongPaths() { + ArrayList songs = AlbumLoader.getAlbum(this, getId()).blockingFirst().songs; + ArrayList paths = new ArrayList<>(songs.size()); + for (Song song : songs) { + paths.add(song.data); + } + return paths; + } + + @Override + protected void loadImageFromFile(@NonNull final Uri selectedFileUri) { + Glide.with(AlbumTagEditorActivity.this) + .load(selectedFileUri) + .asBitmap() + .transcode(new BitmapPaletteTranscoder(AlbumTagEditorActivity.this), + BitmapPaletteWrapper.class) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(true) + .into(new SimpleTarget() { + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + e.printStackTrace(); + Toast.makeText(AlbumTagEditorActivity.this, e.toString(), Toast.LENGTH_LONG).show(); + } + + @Override + public void onResourceReady(BitmapPaletteWrapper resource, + GlideAnimation glideAnimation) { + RetroColorUtil.getColor(resource.getPalette(), Color.TRANSPARENT); + albumArtBitmap = ImageUtil.resizeBitmap(resource.getBitmap(), 2048); + setImageBitmap(albumArtBitmap, RetroColorUtil.getColor(resource.getPalette(), + ATHUtil.resolveColor(AlbumTagEditorActivity.this, R.attr.defaultFooterColor))); + deleteAlbumArt = false; + dataChanged(); + setResult(RESULT_OK); + } + }); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + dataChanged(); + } + + @Override + protected void setColors(int color) { + super.setColors(color); + background.setBackgroundColor(color); + toolbar.setBackgroundColor(color); + setStatusbarColor(ColorUtil.darkenColor(color)); + setNavigationbarColor(ColorUtil.darkenColor(color)); + setSupportActionBar(toolbar); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/SongTagEditorActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/SongTagEditorActivity.java new file mode 100755 index 00000000..7c194d9e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/SongTagEditorActivity.java @@ -0,0 +1,167 @@ +package code.name.monkey.retromusic.ui.activities.tageditor; + +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.AppBarLayout; +import android.support.v7.widget.Toolbar; +import android.text.Editable; +import android.text.TextWatcher; +import android.widget.EditText; + +import org.jaudiotagger.tag.FieldKey; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.loaders.SongLoader; + + +public class SongTagEditorActivity extends AbsTagEditorActivity implements TextWatcher { + + public static final String TAG = SongTagEditorActivity.class.getSimpleName(); + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.app_bar) + AppBarLayout appBarLayout; + @BindView(R.id.title1) + EditText songTitle; + @BindView(R.id.title2) + EditText albumTitle; + @BindView(R.id.artist) + EditText artist; + @BindView(R.id.genre) + EditText genre; + @BindView(R.id.year) + EditText year; + @BindView(R.id.image_text) + EditText trackNumber; + @BindView(R.id.lyrics) + EditText lyrics; + @BindView(R.id.album_artist) + EditText albumArtist; + + private void setupToolbar() { + appBarLayout.setBackgroundColor(ThemeStore.primaryColor(this)); + toolbar.setBackgroundColor(ThemeStore.primaryColor(this)); + toolbar.setNavigationOnClickListener(v -> onBackPressed()); + setTitle(R.string.action_tag_editor); + setSupportActionBar(toolbar); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ButterKnife.bind(this); + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + + setNoImageMode(); + setUpViews(); + setupToolbar(); + } + + private void setUpViews() { + fillViewsWithFileTags(); + albumArtist.addTextChangedListener(this); + songTitle.addTextChangedListener(this); + albumTitle.addTextChangedListener(this); + artist.addTextChangedListener(this); + genre.addTextChangedListener(this); + year.addTextChangedListener(this); + trackNumber.addTextChangedListener(this); + lyrics.addTextChangedListener(this); + + } + + private void fillViewsWithFileTags() { + songTitle.setText(getSongTitle()); + albumArtist.setText(getAlbumArtist()); + albumTitle.setText(getAlbumTitle()); + artist.setText(getArtistName()); + genre.setText(getGenreName()); + year.setText(getSongYear()); + trackNumber.setText(getTrackNumber()); + lyrics.setText(getLyrics()); + } + + @Override + protected void loadCurrentImage() { + + } + + @Override + protected void getImageFromLastFM() { + + } + + @Override + protected void searchImageOnWeb() { + + } + + @Override + protected void deleteImage() { + + } + + @Override + protected void save() { + Map fieldKeyValueMap = new EnumMap<>(FieldKey.class); + fieldKeyValueMap.put(FieldKey.TITLE, songTitle.getText().toString()); + fieldKeyValueMap.put(FieldKey.ALBUM, albumTitle.getText().toString()); + fieldKeyValueMap.put(FieldKey.ARTIST, artist.getText().toString()); + fieldKeyValueMap.put(FieldKey.GENRE, genre.getText().toString()); + fieldKeyValueMap.put(FieldKey.YEAR, year.getText().toString()); + fieldKeyValueMap.put(FieldKey.TRACK, trackNumber.getText().toString()); + fieldKeyValueMap.put(FieldKey.LYRICS, lyrics.getText().toString()); + fieldKeyValueMap.put(FieldKey.ALBUM_ARTIST, albumArtist.getText().toString()); + writeValuesToFiles(fieldKeyValueMap, null); + } + + @Override + protected int getContentViewLayout() { + return R.layout.activity_song_tag_editor; + } + + @NonNull + @Override + protected List getSongPaths() { + ArrayList paths = new ArrayList<>(1); + paths.add(SongLoader.getSong(this, getId()).blockingFirst().data); + return paths; + } + + @Override + protected void loadImageFromFile(Uri imageFilePath) { + + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + dataChanged(); + } + + @Override + protected void setColors(int color) { + super.setColors(color); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/WriteTagsAsyncTask.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/WriteTagsAsyncTask.java new file mode 100644 index 00000000..32c54688 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/tageditor/WriteTagsAsyncTask.java @@ -0,0 +1,163 @@ +package code.name.monkey.retromusic.ui.activities.tageditor; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.graphics.Bitmap; +import android.media.MediaScannerConnection; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.misc.DialogAsyncTask; +import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener; +import code.name.monkey.retromusic.util.MusicUtil; +import com.afollestad.materialdialogs.MaterialDialog; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +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; + +public class WriteTagsAsyncTask extends + DialogAsyncTask { + + private Context applicationContext; + + public WriteTagsAsyncTask(Context context) { + super(context); + applicationContext = context; + } + + @Override + protected String[] doInBackground(LoadingInfo... params) { + try { + LoadingInfo info = params[0]; + + Artwork artwork = null; + File albumArtFile = null; + if (info.artworkInfo != null && info.artworkInfo.artwork != null) { + try { + albumArtFile = MusicUtil.createAlbumArtFile().getCanonicalFile(); + info.artworkInfo.artwork + .compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(albumArtFile)); + artwork = ArtworkFactory.createArtworkFromFile(albumArtFile); + } catch (IOException e) { + e.printStackTrace(); + } + } + + int counter = 0; + boolean wroteArtwork = false; + boolean deletedArtwork = false; + for (String filePath : info.filePaths) { + publishProgress(++counter, info.filePaths.size()); + try { + AudioFile audioFile = AudioFileIO.read(new File(filePath)); + Tag tag = audioFile.getTagOrCreateAndSetDefault(); + + if (info.fieldKeyValueMap != null) { + for (Map.Entry entry : info.fieldKeyValueMap.entrySet()) { + try { + tag.setField(entry.getKey(), entry.getValue()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + if (info.artworkInfo != null) { + if (info.artworkInfo.artwork == null) { + tag.deleteArtworkField(); + deletedArtwork = true; + } else if (artwork != null) { + tag.deleteArtworkField(); + tag.setField(artwork); + wroteArtwork = true; + } + } + + audioFile.commit(); + } catch (@NonNull CannotReadException | IOException | CannotWriteException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) { + e.printStackTrace(); + } + } + + Context context = getContext(); + if (context != null) { + if (wroteArtwork) { + MusicUtil.insertAlbumArt(context, info.artworkInfo.albumId, albumArtFile.getPath()); + } else if (deletedArtwork) { + MusicUtil.deleteAlbumArt(context, info.artworkInfo.albumId); + } + } + + return info.filePaths.toArray(new String[info.filePaths.size()]); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + @Override + protected void onPostExecute(String[] toBeScanned) { + super.onPostExecute(toBeScanned); + scan(toBeScanned); + } + + @Override + protected void onCancelled(String[] toBeScanned) { + super.onCancelled(toBeScanned); + scan(toBeScanned); + } + + private void scan(String[] toBeScanned) { + Context context = getContext(); + MediaScannerConnection.scanFile(applicationContext, toBeScanned, 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]); + } + + public static class LoadingInfo { + + final Collection filePaths; + @Nullable + final Map fieldKeyValueMap; + @Nullable + private AbsTagEditorActivity.ArtworkInfo artworkInfo; + + public LoadingInfo(Collection filePaths, + @Nullable Map fieldKeyValueMap, + @Nullable AbsTagEditorActivity.ArtworkInfo artworkInfo) { + this.filePaths = filePaths; + this.fieldKeyValueMap = fieldKeyValueMap; + this.artworkInfo = artworkInfo; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/CollageSongAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/CollageSongAdapter.java new file mode 100644 index 00000000..aa574b10 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/CollageSongAdapter.java @@ -0,0 +1,96 @@ +package code.name.monkey.retromusic.ui.adapter; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import butterknife.BindViews; +import butterknife.ButterKnife; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.ui.adapter.CollageSongAdapter.CollageSongViewHolder; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; +import code.name.monkey.retromusic.util.NavigationUtil; +import com.bumptech.glide.Glide; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Hemanth S (h4h13). + */ +public class CollageSongAdapter extends RecyclerView.Adapter { + + private AppCompatActivity activity; + private ArrayList dataSet; + private int itemLayoutRes; + + public CollageSongAdapter(AppCompatActivity activity, ArrayList dataSet, + int itemLayoutRes) { + this.activity = activity; + this.dataSet = dataSet; + this.itemLayoutRes = itemLayoutRes; + } + + @Override + public void onBindViewHolder(@NonNull CollageSongViewHolder holder, int position) { + ArrayList albums = dataSet; + + holder.bindSongs(albums); + + if (albums.size() > 9) { + for (int i = 0; i < albums.subList(0, 9).size(); i++) { + if (holder.imageViews != null) { + SongGlideRequest.Builder.from(Glide.with(activity), albums.get(i).safeGetFirstSong()) + .checkIgnoreMediaStore(activity).build().into(holder.imageViews.get(i)); + } + } + } + } + + @Override + public int getItemCount() { + return 1; + } + + @NonNull + @Override + public CollageSongViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new CollageSongViewHolder( + LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)); + } + + class CollageSongViewHolder extends MediaEntryViewHolder { + + @BindViews({R.id.image_1, R.id.image_2, R.id.image_3, R.id.image_4, R.id.image_5, R.id.image_6, + R.id.image_7, R.id.image_8, R.id.image_9}) + @Nullable + List imageViews; + + CollageSongViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + + @Override + public void onClick(View v) { + super.onClick(v); + NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition() + 1).getId()); + } + + void bindSongs(ArrayList albums) { + if (imageViews != null) { + for (int i = 0; i < imageViews.size(); i++) { + final int startPosition = i; + ImageView imageView = imageViews.get(i); + imageView.setOnClickListener( + v -> NavigationUtil.goToAlbum(activity, albums.get(startPosition).getId())); + } + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/GenreAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/GenreAdapter.java new file mode 100644 index 00000000..9f45384d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/GenreAdapter.java @@ -0,0 +1,93 @@ +package code.name.monkey.retromusic.ui.adapter; + +import android.app.Activity; +import android.graphics.PorterDuff; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.Locale; + +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; +import code.name.monkey.retromusic.util.NavigationUtil; + +/** + * @author Hemanth S (h4h13). + */ + +public class GenreAdapter extends RecyclerView.Adapter { + private ArrayList mGenres = new ArrayList<>(); + private Activity mActivity; + private int mItemLayoutRes; + + public GenreAdapter(@NonNull Activity activity, ArrayList dataSet, int itemLayoutRes) { + mActivity = activity; + mGenres = dataSet; + mItemLayoutRes = itemLayoutRes; + } + + public ArrayList getDataSet() { + return mGenres; + } + + @Override + public GenreAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ViewHolder(LayoutInflater.from(mActivity).inflate(mItemLayoutRes, parent, false)); + } + + @Override + public void onBindViewHolder(GenreAdapter.ViewHolder holder, int position) { + Genre genre = mGenres.get(position); + if (holder.title != null) { + holder.title.setText(genre.name); + } + if (holder.text != null) { + holder.text.setText(String.format(Locale.getDefault(), "%d %s", genre.songCount, genre.songCount > 1 ? + mActivity.getString(R.string.songs) : + mActivity.getString(R.string.song))); + } + if (holder.image != null) { + holder.image.setImageResource(R.drawable.ic_recent_actors_white_24dp); + } + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.VISIBLE); + } + } + + @Override + public int getItemCount() { + return mGenres.size(); + } + + public void swapDataSet(ArrayList list) { + mGenres = list; + notifyDataSetChanged(); + } + + public class ViewHolder extends MediaEntryViewHolder { + public ViewHolder(View itemView) { + super(itemView); + if (menu != null) { + menu.setVisibility(View.GONE); + } + if (image != null) { + int iconPadding = mActivity.getResources().getDimensionPixelSize(R.dimen.list_item_image_icon_padding); + image.setPadding(iconPadding, iconPadding, iconPadding, iconPadding); + image.setColorFilter(ATHUtil.resolveColor(mActivity, R.attr.iconColor), PorterDuff.Mode.SRC_IN); + } + } + + @Override + public void onClick(View v) { + super.onClick(v); + Genre genre = mGenres.get(getAdapterPosition()); + NavigationUtil.goToGenre(mActivity, genre); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/SearchAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/SearchAdapter.java new file mode 100644 index 00000000..75706a95 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/SearchAdapter.java @@ -0,0 +1,163 @@ +package code.name.monkey.retromusic.ui.adapter; + +import android.support.annotation.NonNull; +import android.support.v4.util.Pair; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.bumptech.glide.Glide; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; +import java.util.List; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.ArtistGlideRequest; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.menu.SongMenuHelper; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.NavigationUtil; + + +public class SearchAdapter extends RecyclerView.Adapter { + + private static final int HEADER = 0; + private static final int ALBUM = 1; + private static final int ARTIST = 2; + private static final int SONG = 3; + + private final AppCompatActivity activity; + private List dataSet; + + public SearchAdapter(@NonNull AppCompatActivity activity, @NonNull List dataSet) { + this.activity = activity; + this.dataSet = dataSet; + } + + public void swapDataSet(@NonNull ArrayList dataSet) { + this.dataSet = dataSet; + notifyDataSetChanged(); + } + + @Override + public int getItemViewType(int position) { + if (dataSet.get(position) instanceof Album) return ALBUM; + if (dataSet.get(position) instanceof Artist) return ARTIST; + if (dataSet.get(position) instanceof Song) return SONG; + return HEADER; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (viewType == HEADER) + return new ViewHolder(LayoutInflater.from(activity).inflate(R.layout.sub_header, parent, false), viewType); + return new ViewHolder(LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false), viewType); + } + + @SuppressWarnings("ConstantConditions") + @Override + public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { + switch (getItemViewType(position)) { + case ALBUM: + final Album album = (Album) dataSet.get(position); + holder.title.setText(album.getTitle()); + holder.text.setText(album.getArtistName()); + SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) + .checkIgnoreMediaStore(activity).build() + .into(holder.image); + break; + case ARTIST: + final Artist artist = (Artist) dataSet.get(position); + holder.title.setText(artist.getName()); + holder.text.setText(MusicUtil.getArtistInfoString(activity, artist)); + ArtistGlideRequest.Builder.from(Glide.with(activity), artist) + .build().into(holder.image); + break; + case SONG: + final Song song = (Song) dataSet.get(position); + holder.title.setText(song.title); + holder.text.setText(song.albumName); + break; + default: + holder.title.setText(dataSet.get(position).toString()); + holder.title.setTextColor(ThemeStore.accentColor(activity)); + break; + } + } + + @Override + public int getItemCount() { + return dataSet.size(); + } + + public class ViewHolder extends MediaEntryViewHolder { + public ViewHolder(@NonNull View itemView, int itemViewType) { + super(itemView); + itemView.setOnLongClickListener(null); + + if (itemViewType != HEADER) { + if (separator != null) { + separator.setVisibility(View.GONE); + } + } + + if (menu != null) { + if (itemViewType == SONG) { + menu.setVisibility(View.VISIBLE); + menu.setOnClickListener(new SongMenuHelper.OnClickSongMenu(activity) { + @Override + public Song getSong() { + return (Song) dataSet.get(getAdapterPosition()); + } + }); + } else { + menu.setVisibility(View.GONE); + } + } + + switch (itemViewType) { + case ALBUM: + setImageTransitionName(activity.getString(R.string.transition_album_art)); + break; + case ARTIST: + setImageTransitionName(activity.getString(R.string.transition_artist_image)); + break; + default: + View container = itemView.findViewById(R.id.image_container); + if (container != null) { + container.setVisibility(View.GONE); + } + break; + } + } + + @Override + public void onClick(View view) { + Object item = dataSet.get(getAdapterPosition()); + switch (getItemViewType()) { + case ALBUM: + NavigationUtil.goToAlbum(activity, + ((Album) item).getId(), Pair.create(image, activity.getResources().getString(R.string.transition_album_art))); + break; + case ARTIST: + NavigationUtil.goToArtist(activity, + ((Artist) item).getId(), Pair.create(image, activity.getResources().getString(R.string.transition_artist_image))); + break; + case SONG: + ArrayList playList = new ArrayList<>(); + playList.add((Song) item); + MusicPlayerRemote.openQueue(playList, 0, true); + break; + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/SongFileAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/SongFileAdapter.java new file mode 100644 index 00000000..c44a8184 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/SongFileAdapter.java @@ -0,0 +1,214 @@ +package code.name.monkey.retromusic.ui.adapter; + +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.signature.MediaStoreSignature; +import code.name.monkey.appthemehelper.util.ATHUtil; +import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; + +import java.io.File; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.audiocover.AudioFileCover; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.ui.adapter.base.AbsMultiSelectAdapter; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; +import code.name.monkey.retromusic.util.RetroUtil; + +public class SongFileAdapter extends AbsMultiSelectAdapter implements FastScrollRecyclerView.SectionedAdapter { + + private static final int FILE = 0; + private static final int FOLDER = 1; + + private final AppCompatActivity activity; + private List dataSet; + private final int itemLayoutRes; + @Nullable + private final Callbacks callbacks; + + public SongFileAdapter(@NonNull AppCompatActivity activity, @NonNull List songFiles, @LayoutRes int itemLayoutRes, @Nullable Callbacks callback, @Nullable CabHolder cabHolder) { + super(activity, cabHolder, R.menu.menu_media_selection); + this.activity = activity; + this.dataSet = songFiles; + this.itemLayoutRes = itemLayoutRes; + this.callbacks = callback; + setHasStableIds(true); + } + + @Override + public int getItemViewType(int position) { + return dataSet.get(position).isDirectory() ? FOLDER : FILE; + } + + @Override + public long getItemId(int position) { + return dataSet.get(position).hashCode(); + } + + public void swapDataSet(@NonNull List songFiles) { + this.dataSet = songFiles; + notifyDataSetChanged(); + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ViewHolder(LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)); + } + + @Override + public void onBindViewHolder(final ViewHolder holder, int index) { + final File file = dataSet.get(index); + + holder.itemView.setActivated(isChecked(file)); + + if (holder.getAdapterPosition() == getItemCount() - 1) { + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.GONE); + } + } else { + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.VISIBLE); + } + } + + if (holder.title != null) { + holder.title.setText(getFileTitle(file)); + } + if (holder.text != null) { + if (holder.getItemViewType() == FILE) { + holder.text.setText(getFileText(file)); + } else { + holder.text.setVisibility(View.GONE); + } + } + + if (holder.image != null) { + loadFileImage(file, holder); + } + } + + protected String getFileTitle(File file) { + return file.getName(); + } + + protected String getFileText(File file) { + return file.isDirectory() ? null : readableFileSize(file.length()); + } + + @SuppressWarnings("ConstantConditions") + protected void loadFileImage(File file, final ViewHolder holder) { + final int iconColor = ATHUtil.resolveColor(activity, R.attr.iconColor); + if (file.isDirectory()) { + holder.image.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + holder.image.setImageResource(R.drawable.ic_folder_white_24dp); + } else { + Drawable error = RetroUtil.getTintedVectorDrawable(activity, R.drawable.ic_file_music_white_24dp, iconColor); + Glide.with(activity) + .load(new AudioFileCover(file.getPath())) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .error(error) + .placeholder(error) + .animate(android.R.anim.fade_in) + .signature(new MediaStoreSignature("", file.lastModified(), 0)) + .into(holder.image); + } + } + + public static String readableFileSize(long size) { + if (size <= 0) return size + " B"; + final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"}; + int digitGroups = (int) (Math.log10(size) / Math.log10(1024)); + return new DecimalFormat("#,##0.##").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups]; + } + + @Override + public int getItemCount() { + return dataSet.size(); + } + + @Override + protected File getIdentifier(int position) { + return dataSet.get(position); + } + + @Override + protected String getName(File object) { + return getFileTitle(object); + } + + @Override + protected void onMultipleItemAction(MenuItem menuItem, ArrayList selection) { + if (callbacks == null) return; + callbacks.onMultipleItemAction(menuItem, selection); + } + + @NonNull + @Override + public String getSectionName(int position) { + return String.valueOf(dataSet.get(position).getName().charAt(0)).toUpperCase(); + } + + public class ViewHolder extends MediaEntryViewHolder { + + public ViewHolder(View itemView) { + super(itemView); + if (menu != null && callbacks != null) { + menu.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + int position = getAdapterPosition(); + if (isPositionInRange(position)) { + callbacks.onFileMenuClicked(dataSet.get(position), v); + } + } + }); + } + } + + @Override + public void onClick(View v) { + int position = getAdapterPosition(); + if (isPositionInRange(position)) { + if (isInQuickSelectMode()) { + toggleChecked(position); + } else { + if (callbacks != null) { + callbacks.onFileSelected(dataSet.get(position)); + } + } + } + } + + @Override + public boolean onLongClick(View view) { + int position = getAdapterPosition(); + return isPositionInRange(position) && toggleChecked(position); + } + + private boolean isPositionInRange(int position) { + return position >= 0 && position < dataSet.size(); + } + } + + public interface Callbacks { + void onFileSelected(File file); + + void onFileMenuClicked(File file, View view); + + void onMultipleItemAction(MenuItem item, ArrayList files); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumAdapter.java new file mode 100644 index 00000000..eb0eff06 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumAdapter.java @@ -0,0 +1,258 @@ +package code.name.monkey.retromusic.ui.adapter.album; + +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.util.Pair; +import android.support.v7.app.AppCompatActivity; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import com.bumptech.glide.Glide; +import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; + +import java.util.ArrayList; +import java.util.List; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.SortOrder; +import code.name.monkey.retromusic.helper.menu.SongsMenuHelper; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.adapter.base.AbsMultiSelectAdapter; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; + + +public class AlbumAdapter extends AbsMultiSelectAdapter implements + FastScrollRecyclerView.SectionedAdapter { + + public static final String TAG = AlbumAdapter.class.getSimpleName(); + + protected final AppCompatActivity activity; + protected ArrayList dataSet; + + protected int itemLayoutRes; + + protected boolean usePalette = false; + private int textColor; + + public AlbumAdapter(@NonNull AppCompatActivity activity, ArrayList dataSet, + @LayoutRes int itemLayoutRes, boolean usePalette, + @Nullable CabHolder cabHolder) { + super(activity, cabHolder, R.menu.menu_media_selection); + this.activity = activity; + this.dataSet = dataSet; + this.itemLayoutRes = itemLayoutRes; + this.usePalette = usePalette; + setHasStableIds(true); + this.textColor = ThemeStore.textColorPrimary(activity); + Typeface mTypeface = Typeface + .createFromAsset(activity.getAssets(), activity.getString(R.string.sans_regular)); + } + + public void useItemLayout(int itemLayoutRes) { + this.itemLayoutRes = itemLayoutRes; + notifyDataSetChanged(); + } + + public void usePalette(boolean usePalette) { + this.usePalette = usePalette; + notifyDataSetChanged(); + } + + public void swapDataSet(ArrayList dataSet) { + this.dataSet = dataSet; + notifyDataSetChanged(); + } + + public ArrayList getDataSet() { + return dataSet; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false); + return createViewHolder(view, viewType); + } + + protected ViewHolder createViewHolder(View view, int viewType) { + return new ViewHolder(view); + } + + private String getAlbumTitle(Album album) { + return album.getTitle(); + } + + protected String getAlbumText(Album album) { + return album.getArtistName(); + } + + @Override + public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { + final Album album = dataSet.get(position); + + final boolean isChecked = isChecked(album); + holder.itemView.setActivated(isChecked); + + if (holder.getAdapterPosition() == getItemCount() - 1) { + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.GONE); + } + } else { + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.VISIBLE); + } + } + + if (holder.title != null) { + holder.title.setText(getAlbumTitle(album)); + holder.title.setTextColor(textColor); + } + if (holder.text != null) { + holder.text.setText(getAlbumText(album)); + } + if (holder.playSongs != null) { + holder.playSongs.setOnClickListener(v -> MusicPlayerRemote.openQueue(album.songs, 0, true)); + } + loadAlbumCover(album, holder); + } + + protected void setColors(int color, ViewHolder holder) { + if (holder.paletteColorContainer != null) { + holder.paletteColorContainer.setBackgroundColor(color); + if (holder.title != null) { + holder.title.setTextColor( + MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color))); + } + if (holder.text != null) { + holder.text.setTextColor( + MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color))); + } + } + } + + protected void loadAlbumCover(Album album, final ViewHolder holder) { + if (holder.image == null) { + return; + } + + SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) + .checkIgnoreMediaStore(activity) + .generatePalette(activity).build() + .into(new RetroMusicColoredTarget(holder.image) { + @Override + public void onLoadCleared(Drawable placeholder) { + super.onLoadCleared(placeholder); + setColors(getDefaultFooterColor(), holder); + } + + @Override + public void onColorReady(int color) { + setColors(color, holder); + } + }); + } + + @Override + public int getItemCount() { + return dataSet.size(); + } + + @Override + public long getItemId(int position) { + return dataSet.get(position).getId(); + } + + @Override + protected Album getIdentifier(int position) { + return dataSet.get(position); + } + + @Override + protected String getName(Album album) { + return album.getTitle(); + } + + @Override + protected void onMultipleItemAction(@NonNull MenuItem menuItem, + @NonNull ArrayList selection) { + SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.getItemId()); + } + + @NonNull + private ArrayList getSongList(@NonNull List albums) { + final ArrayList songs = new ArrayList<>(); + for (Album album : albums) { + songs.addAll(album.songs); + } + return songs; + } + + @NonNull + @Override + public String getSectionName(int position) { + @Nullable String sectionName = null; + switch (PreferenceUtil.getInstance(activity).getAlbumSortOrder()) { + case SortOrder.AlbumSortOrder.ALBUM_A_Z: + case SortOrder.AlbumSortOrder.ALBUM_Z_A: + sectionName = dataSet.get(position).getTitle(); + break; + case SortOrder.AlbumSortOrder.ALBUM_ARTIST: + sectionName = dataSet.get(position).getArtistName(); + break; + case SortOrder.AlbumSortOrder.ALBUM_YEAR: + return MusicUtil.getYearString(dataSet.get(position).getYear()); + } + + return MusicUtil.getSectionName(sectionName); + } + + public void setTextColor(int textColor) { + this.textColor = textColor; + notifyDataSetChanged(); + } + + + public class ViewHolder extends MediaEntryViewHolder { + + public ViewHolder(@NonNull final View itemView) { + super(itemView); + setImageTransitionName(activity.getString(R.string.transition_album_art)); + if (menu != null) { + menu.setVisibility(View.GONE); + } + } + + @Override + public void onClick(View v) { + if (isInQuickSelectMode()) { + toggleChecked(getAdapterPosition()); + } else { + Pair[] albumPairs = new Pair[]{ + Pair.create(image, activity.getResources().getString(R.string.transition_album_art))}; + NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()).getId(), albumPairs); + } + } + + @Override + public boolean onLongClick(View view) { + toggleChecked(getAdapterPosition()); + return true; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumCoverPagerAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumCoverPagerAdapter.java new file mode 100644 index 00000000..17b12b05 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumCoverPagerAdapter.java @@ -0,0 +1,208 @@ +package code.name.monkey.retromusic.ui.adapter.album; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.activities.LyricsActivity; +import code.name.monkey.retromusic.ui.fragments.NowPlayingScreen; +import code.name.monkey.retromusic.util.PreferenceUtil; + + +public class AlbumCoverPagerAdapter extends CustomFragmentStatePagerAdapter { + + public static final String TAG = AlbumCoverPagerAdapter.class.getSimpleName(); + + private ArrayList dataSet; + + private AlbumCoverFragment.ColorReceiver currentColorReceiver; + private int currentColorReceiverPosition = -1; + + public AlbumCoverPagerAdapter(FragmentManager fm, ArrayList dataSet) { + super(fm); + this.dataSet = dataSet; + } + + @Override + public Fragment getItem(final int position) { + return AlbumCoverFragment.newInstance(dataSet.get(position)); + } + + @Override + public int getCount() { + return dataSet.size(); + } + + @NonNull + @Override + public Object instantiateItem(ViewGroup container, int position) { + Object o = super.instantiateItem(container, position); + if (currentColorReceiver != null && currentColorReceiverPosition == position) { + receiveColor(currentColorReceiver, currentColorReceiverPosition); + } + return o; + } + + /** + * Only the latest passed {@link AlbumCoverFragment.ColorReceiver} is guaranteed to receive a + * response + */ + public void receiveColor(AlbumCoverFragment.ColorReceiver colorReceiver, int position) { + AlbumCoverFragment fragment = (AlbumCoverFragment) getFragment(position); + if (fragment != null) { + currentColorReceiver = null; + currentColorReceiverPosition = -1; + fragment.receiveColor(colorReceiver, position); + } else { + currentColorReceiver = colorReceiver; + currentColorReceiverPosition = position; + } + } + + public static class AlbumCoverFragment extends Fragment { + + private static final String SONG_ARG = "song"; + @BindView(R.id.player_image) + ImageView albumCover; + private Unbinder unbinder; + private boolean isColorReady; + private int color; + private Song song; + private ColorReceiver colorReceiver; + private int request; + + public static AlbumCoverFragment newInstance(final Song song) { + AlbumCoverFragment frag = new AlbumCoverFragment(); + final Bundle args = new Bundle(); + args.putParcelable(SONG_ARG, song); + frag.setArguments(args); + return frag; + } + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + song = getArguments().getParcelable(SONG_ARG); + } + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + int layout = getLayout(); + View view = inflater.inflate(layout, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + private int getLayout() { + int layout; + //noinspection ConstantConditions + switch (PreferenceUtil.getInstance(getContext()).getNowPlayingScreen()) { + case BLUR_CARD: + layout = R.layout.fragment_album_card_cover; + break; + case MATERIAL: + layout = R.layout.fragment_album_material_cover; + break; + case PLAIN: + case FLAT: + layout = R.layout.fragment_album_flat_cover; + break; + case CARD: + case FULL: + case ADAPTIVE: + layout = R.layout.fragment_album_full_cover; + break; + default: + case NORMAL: + layout = R.layout.fragment_album_cover; + break; + + } + if (PreferenceUtil.getInstance(getContext()).carouselEffect() && + !(PreferenceUtil.getInstance(getContext()).getNowPlayingScreen() + == NowPlayingScreen.FULL)) { + layout = R.layout.fragment_carousal_album_cover; + } + if (PreferenceUtil.getInstance(getContext()).circularAlbumArt()) { + layout = R.layout.fragment_album_circle_cover; + } + return layout; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + loadAlbumCover(); + } + + @OnClick(R.id.player_image) + void showLyrics() { + startActivity(new Intent(getContext(), LyricsActivity.class)); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + colorReceiver = null; + } + + private void loadAlbumCover() { + SongGlideRequest.Builder.from(Glide.with(this), song) + .checkIgnoreMediaStore(getActivity()) + .generatePalette(getActivity()).build() + .into(new RetroMusicColoredTarget(albumCover) { + @Override + public void onColorReady(int color) { + setColor(color); + } + }); + } + + private void setColor(int color) { + this.color = color; + isColorReady = true; + if (colorReceiver != null) { + colorReceiver.onColorReady(color, request); + colorReceiver = null; + } + } + + public void receiveColor(ColorReceiver colorReceiver, int request) { + if (isColorReady) { + colorReceiver.onColorReady(color, request); + } else { + this.colorReceiver = colorReceiver; + this.request = request; + } + } + + public interface ColorReceiver { + + void onColorReady(int color, int request); + } + } +} + diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumFullWithAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumFullWithAdapter.java new file mode 100644 index 00000000..57d2b2a1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/AlbumFullWithAdapter.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2017. Alexander Bilchuk + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 code.name.monkey.retromusic.ui.adapter.album; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.support.annotation.NonNull; +import android.support.v4.util.Pair; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.views.MetalRecyclerViewPager; +import com.bumptech.glide.Glide; +import java.util.ArrayList; +import java.util.List; + +public class AlbumFullWithAdapter extends + MetalRecyclerViewPager.MetalAdapter { + + private Activity activity; + private List dataSet = new ArrayList<>(); + + public AlbumFullWithAdapter(@NonNull Activity activity, + @NonNull DisplayMetrics metrics) { + super(metrics); + this.activity = activity; + } + + public void swapData(ArrayList list) { + dataSet = list; + notifyDataSetChanged(); + } + + @Override + public FullMetalViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View viewItem = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.pager_item, parent, false); + return new FullMetalViewHolder(viewItem); + } + + private Bitmap combineImageIntoOne(ArrayList bitmap) { + int w = 0, h = 0; + for (int i = 0; i < bitmap.size(); i++) { + if (i < bitmap.size() - 1) { + h = bitmap.get(i).getWidth() > bitmap.get(i + 1).getWidth() ? bitmap.get(i).getWidth() + : bitmap.get(i + 1).getWidth(); + } + w += bitmap.get(i).getHeight(); + } + + Bitmap temp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(temp); + int top = 0, left = 0; + for (int i = 0; i < bitmap.size(); i++) { + Log.d("HTML", "Combine: " + i + "/" + bitmap.size() + 1); + + top = (i == 0 ? 0 : top + bitmap.get(i).getHeight()); + left = (i == 0 ? 0 : top + bitmap.get(i).getWidth()); + canvas.drawBitmap(bitmap.get(i), left, 0f, null); + } + return temp; + } + + @Override + public void onBindViewHolder(FullMetalViewHolder holder, int position) { + // don't forget about calling supper.onBindViewHolder! + super.onBindViewHolder(holder, position); + + final Album album = dataSet.get(position); + + if (holder.title != null) { + holder.title.setText(getAlbumTitle(album)); + } + if (holder.text != null) { + holder.text.setText(getAlbumText(album)); + } + if (holder.playSongs != null) { + holder.playSongs.setOnClickListener(v -> MusicPlayerRemote.openQueue(album.songs, 0, true)); + } + loadAlbumCover(album, holder); + } + + private String getAlbumTitle(Album album) { + return album.getTitle(); + } + + private String getAlbumText(Album album) { + return album.getArtistName(); + } + + private void loadAlbumCover(Album album, FullMetalViewHolder holder) { + if (holder.image == null) { + return; + } + + SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) + .checkIgnoreMediaStore(activity) + .generatePalette(activity).build() + .into(new RetroMusicColoredTarget(holder.image) { + @Override + public void onColorReady(int color) { + + } + }); + } + + @Override + public int getItemCount() { + return dataSet.size(); + } + + class FullMetalViewHolder extends MetalRecyclerViewPager.MetalViewHolder { + + FullMetalViewHolder(View itemView) { + super(itemView); + } + + @Override + public void onClick(View v) { + Pair[] albumPairs = new Pair[]{ + Pair.create(image, activity.getResources().getString(R.string.transition_album_art))}; + NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()).getId(), albumPairs); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/HorizontalAlbumAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/HorizontalAlbumAdapter.java new file mode 100644 index 00000000..3007e6db --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/album/HorizontalAlbumAdapter.java @@ -0,0 +1,83 @@ +package code.name.monkey.retromusic.ui.adapter.album; + +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.ViewGroup; + +import com.bumptech.glide.Glide; + +import java.util.ArrayList; + +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.HorizontalAdapterHelper; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.util.MusicUtil; + + +public class HorizontalAlbumAdapter extends AlbumAdapter { + public static final String TAG = AlbumAdapter.class.getSimpleName(); + + public HorizontalAlbumAdapter(@NonNull AppCompatActivity activity, ArrayList dataSet, boolean usePalette, @Nullable CabHolder cabHolder) { + super(activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, usePalette, cabHolder); + } + + @Override + protected ViewHolder createViewHolder(View view, int viewType) { + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); + HorizontalAdapterHelper.applyMarginToLayoutParams(activity, params, viewType); + return new ViewHolder(view); + } + + @Override + protected void setColors(int color, ViewHolder holder) { + if (holder.itemView != null) { + if (holder.title != null) { + holder.title.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color))); + } + if (holder.text != null) { + holder.text.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color))); + } + } + } + + @Override + protected void loadAlbumCover(Album album, final ViewHolder holder) { + if (holder.image == null) return; + + SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) + .checkIgnoreMediaStore(activity) + .generatePalette(activity).build() + .into(new RetroMusicColoredTarget(holder.image) { + @Override + public void onLoadCleared(Drawable placeholder) { + super.onLoadCleared(placeholder); + setColors(getAlbumArtistFooterColor(), holder); + } + + @Override + public void onColorReady(int color) { + if (usePalette) + setColors(color, holder); + else + setColors(getAlbumArtistFooterColor(), holder); + } + }); + } + + @Override + protected String getAlbumText(Album album) { + return MusicUtil.getYearString(album.getYear()); + } + + @Override + public int getItemViewType(int position) { + return HorizontalAdapterHelper.getItemViewtype(position, getItemCount()); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/artist/ArtistAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/artist/ArtistAdapter.java new file mode 100644 index 00000000..58f921e7 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/artist/ArtistAdapter.java @@ -0,0 +1,188 @@ +package code.name.monkey.retromusic.ui.adapter.artist; + +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.util.Pair; +import android.support.v7.app.AppCompatActivity; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.ArtistGlideRequest; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.helper.menu.SongsMenuHelper; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.adapter.base.AbsMultiSelectAdapter; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.NavigationUtil; +import com.bumptech.glide.Glide; +import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; +import java.util.ArrayList; +import java.util.List; + + +public class ArtistAdapter extends + AbsMultiSelectAdapter implements + FastScrollRecyclerView.SectionedAdapter { + + protected final AppCompatActivity activity; + protected ArrayList dataSet; + + protected int itemLayoutRes; + + protected boolean usePalette = false; + + + public ArtistAdapter(@NonNull AppCompatActivity activity, ArrayList dataSet, + @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) { + super(activity, cabHolder, R.menu.menu_media_selection); + this.activity = activity; + this.dataSet = dataSet; + this.itemLayoutRes = itemLayoutRes; + this.usePalette = usePalette; + //setHasStableIds(true); + } + + public void swapDataSet(ArrayList dataSet) { + this.dataSet = dataSet; + notifyDataSetChanged(); + } + + public ArrayList getDataSet() { + return dataSet; + } + + public void usePalette(boolean usePalette) { + this.usePalette = usePalette; + notifyDataSetChanged(); + } + + @Override + public long getItemId(int position) { + return dataSet.get(position).getId(); + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false); + return createViewHolder(view); + } + + protected ViewHolder createViewHolder(View view) { + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { + final Artist artist = dataSet.get(position); + + boolean isChecked = isChecked(artist); + holder.itemView.setActivated(isChecked); + + if (holder.title != null) { + holder.title.setText(artist.getName()); + } + if (holder.text != null) { + holder.text.setVisibility(View.GONE); + } + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.VISIBLE); + } + loadArtistImage(artist, holder); + } + + protected void setColors(int color, ViewHolder holder) { + if (holder.paletteColorContainer != null) { + holder.paletteColorContainer.setBackgroundColor(color); + if (holder.title != null) { + holder.title.setTextColor( + MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color))); + } + } + } + + private void loadArtistImage(Artist artist, final ViewHolder holder) { + if (holder.image == null) { + return; + } + ArtistGlideRequest.Builder.from(Glide.with(activity), artist) + .generatePalette(activity).build() + .into(new RetroMusicColoredTarget(holder.image) { + @Override + public void onColorReady(int color) { + setColors(color, holder); + } + }); + } + + @Override + public int getItemCount() { + return dataSet.size(); + } + + @Override + protected Artist getIdentifier(int position) { + return dataSet.get(position); + } + + @Override + protected String getName(Artist artist) { + return artist.getName(); + } + + @Override + protected void onMultipleItemAction(@NonNull MenuItem menuItem, + @NonNull ArrayList selection) { + SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.getItemId()); + } + + @NonNull + private ArrayList getSongList(@NonNull List artists) { + final ArrayList songs = new ArrayList<>(); + for (Artist artist : artists) { + songs.addAll(artist.getSongs()); // maybe async in future? + } + return songs; + } + + @NonNull + @Override + public String getSectionName(int position) { + return MusicUtil.getSectionName(dataSet.get(position).getName()); + } + + public class ViewHolder extends MediaEntryViewHolder { + + public ViewHolder(@NonNull View itemView) { + super(itemView); + setImageTransitionName(activity.getString(R.string.transition_artist_image)); + if (menu != null) { + menu.setVisibility(View.GONE); + } + } + + @Override + public void onClick(View v) { + if (isInQuickSelectMode()) { + toggleChecked(getAdapterPosition()); + } else { + Pair[] artistPairs = new Pair[]{Pair.create(image, + activity.getResources().getString(R.string.transition_artist_image))}; + NavigationUtil.goToArtist(activity, dataSet.get(getAdapterPosition()).getId(), artistPairs); + } + } + + @Override + public boolean onLongClick(View view) { + toggleChecked(getAdapterPosition()); + return true; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/AbsMultiSelectAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/AbsMultiSelectAdapter.java new file mode 100644 index 00000000..acb29829 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/AbsMultiSelectAdapter.java @@ -0,0 +1,121 @@ +package code.name.monkey.retromusic.ui.adapter.base; + +import android.content.Context; +import android.support.annotation.MenuRes; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.view.Menu; +import android.view.MenuItem; + +import com.afollestad.materialcab.MaterialCab; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.interfaces.CabHolder; + + +public abstract class AbsMultiSelectAdapter extends RecyclerView.Adapter implements MaterialCab.Callback { + @Nullable + private final CabHolder cabHolder; + private final Context context; + private MaterialCab cab; + private ArrayList checked; + private int menuRes; + + public AbsMultiSelectAdapter(Context context, @Nullable CabHolder cabHolder, @MenuRes int menuRes) { + this.cabHolder = cabHolder; + checked = new ArrayList<>(); + this.menuRes = menuRes; + this.context = context; + } + + 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; + } + return false; + } + + 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(); + } + } + + 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)); + } + } + + private void clearChecked() { + checked.clear(); + notifyDataSetChanged(); + } + + protected boolean isChecked(I identifier) { + return checked.contains(identifier); + } + + protected boolean isInQuickSelectMode() { + return cab != null && cab.isActive(); + } + + @Override + public boolean onCabCreated(MaterialCab materialCab, Menu menu) { + 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 onCabFinished(MaterialCab materialCab) { + clearChecked(); + return true; + } + + protected String getName(I object) { + return object.toString(); + } + + @Nullable + protected abstract I getIdentifier(int position); + + protected abstract void onMultipleItemAction(MenuItem menuItem, ArrayList selection); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/MediaEntryViewHolder.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/MediaEntryViewHolder.java new file mode 100644 index 00000000..5659aac7 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/MediaEntryViewHolder.java @@ -0,0 +1,98 @@ +package code.name.monkey.retromusic.ui.adapter.base; + +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.CardView; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; +import butterknife.BindView; +import butterknife.ButterKnife; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; + + +public class MediaEntryViewHolder extends RecyclerView.ViewHolder + implements View.OnClickListener, View.OnLongClickListener { + + @Nullable + @BindView(R.id.image) + public ImageView image; + @Nullable + @BindView(R.id.image_text) + public TextView imageText; + @Nullable + @BindView(R.id.title) + public TextView title; + @Nullable + @BindView(R.id.text) + public TextView text; + @Nullable + @BindView(R.id.image_container) + public ViewGroup imageContainer; + @Nullable + @BindView(R.id.image_container_card) + public CardView imageContainerCard; + @Nullable + @BindView(R.id.menu) + public View menu; + @Nullable + @BindView(R.id.separator) + public View separator; + @Nullable + @BindView(R.id.short_separator) + public View shortSeparator; + @Nullable + @BindView(R.id.drag_view) + public View dragView; + @Nullable + @BindView(R.id.palette_color_container) + public View paletteColorContainer; + @BindView(R.id.time) + @Nullable + public TextView time; + @BindView(R.id.recycler_view) + @Nullable + public RecyclerView recyclerView; + @BindView(R.id.play_songs) + @Nullable + public ImageButton playSongs; + @BindView(R.id.image_text_container) + @Nullable + public CardView imageTextContainer; + + + public MediaEntryViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + + itemView.setOnClickListener(this); + itemView.setOnLongClickListener(this); + + if (imageTextContainer != null) { + imageTextContainer.setCardBackgroundColor(ThemeStore.primaryColor(itemView.getContext())); + } + if (imageContainerCard != null) { + imageContainerCard.setCardBackgroundColor(ThemeStore.primaryColor(itemView.getContext())); + } + } + + protected void setImageTransitionName(@NonNull String transitionName) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && image != null) { + image.setTransitionName(transitionName); + } + } + + @Override + public boolean onLongClick(View v) { + return false; + } + + @Override + public void onClick(View v) { + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/home/HomeAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/home/HomeAdapter.java new file mode 100644 index 00000000..d8ac7f7e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/home/HomeAdapter.java @@ -0,0 +1,169 @@ +package code.name.monkey.retromusic.ui.adapter.home; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import butterknife.BindView; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.model.smartplaylist.HistoryPlaylist; +import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist; +import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist; +import code.name.monkey.retromusic.ui.adapter.album.AlbumAdapter; +import code.name.monkey.retromusic.ui.adapter.artist.ArtistAdapter; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; +import code.name.monkey.retromusic.ui.adapter.song.SongAdapter; +import code.name.monkey.retromusic.util.NavigationUtil; +import java.util.ArrayList; + +public class HomeAdapter extends RecyclerView.Adapter { + + private static final int SUB_HEADER = 0; + private static final int ABS_PLAYLITS = 1; + private static final int DATA = 2; + private ArrayList dataSet = new ArrayList<>(); + private AppCompatActivity activity; + + public HomeAdapter(@NonNull AppCompatActivity activity) { + this.activity = activity; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + switch (i) { + + case ABS_PLAYLITS: + return new ViewHolder(LayoutInflater.from(activity) + .inflate(R.layout.abs_playlists, viewGroup, false)); + default: + case DATA: + return new ViewHolder(LayoutInflater.from(activity) + .inflate(R.layout.recycler_view_sec, viewGroup, false)); + case SUB_HEADER: + return new ViewHolder(LayoutInflater.from(activity) + .inflate(R.layout.sub_header, viewGroup, false)); + } + } + + @Override + public int getItemViewType(int position) { + if (dataSet.get(position) instanceof String) { + return SUB_HEADER; + } else if (dataSet.get(position) instanceof Integer) { + return ABS_PLAYLITS; + } else if (dataSet.get(position) instanceof ArrayList) { + return DATA; + } + return super.getItemViewType(position); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { + ViewHolder viewholder = (ViewHolder) holder; + switch (getItemViewType(i)) { + case ABS_PLAYLITS: + bindAbsActions(viewholder); + break; + case SUB_HEADER: + String title = (String) dataSet.get(i); + if (viewholder.title != null) { + viewholder.title.setText(title); + } + break; + case DATA: + parseAllSections(i, viewholder); + break; + } + } + + private void bindAbsActions(ViewHolder viewholder) { + + + if (viewholder.shuffle != null) { + viewholder.shuffle.setOnClickListener(view -> MusicPlayerRemote + .openAndShuffleQueue(SongLoader.getAllSongs(activity).blockingFirst(), true)); + } + /*if (viewholder.search != null) { + viewholder.search.setBackgroundTintList(ColorStateList.valueOf(ColorUtil.withAlpha(ThemeStore.textColorPrimary(activity), 0.2f))); + viewholder.search.setOnClickListener(view -> { + activity.startActivity(new Intent(activity, SearchActivity.class)); + }); + }*/ + } + + @SuppressWarnings("unchecked") + private void parseAllSections(int i, ViewHolder viewholder) { + if (viewholder.recyclerView != null) { + ArrayList arrayList = (ArrayList) dataSet.get(i); + if (arrayList.isEmpty()) { + return; + } + Object something = arrayList.get(0); + if (something instanceof Artist) { + layoutManager(viewholder); + viewholder.recyclerView.setAdapter( + new ArtistAdapter(activity, (ArrayList) arrayList, R.layout.item_artist, false, + null)); + } else if (something instanceof Album) { + layoutManager(viewholder); + viewholder.recyclerView.setItemAnimator(new DefaultItemAnimator()); + viewholder.recyclerView.setAdapter( + new AlbumAdapter(activity, (ArrayList) arrayList, R.layout.item_image, false, + null)); + } else if (something instanceof Song) { + GridLayoutManager layoutManager = new GridLayoutManager(activity, 1, + LinearLayoutManager.HORIZONTAL, false); + viewholder.recyclerView.setLayoutManager(layoutManager); + viewholder.recyclerView.setAdapter( + new SongAdapter(activity, (ArrayList) arrayList, R.layout.item_image, false, + null)); + } + } + } + + private void layoutManager(ViewHolder viewholder) { + if (viewholder.recyclerView != null) { + viewholder.recyclerView.setLayoutManager( + new GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)); + viewholder.recyclerView.setItemAnimator(new DefaultItemAnimator()); + } + } + + + @Override + public int getItemCount() { + return dataSet.size(); + } + + public void swapDataSet(@NonNull ArrayList data) { + dataSet = data; + notifyDataSetChanged(); + } + + public ArrayList getDataset() { + return dataSet; + } + + public class ViewHolder extends MediaEntryViewHolder { + + + @BindView(R.id.action_shuffle) + @Nullable + View shuffle; + + public ViewHolder(View itemView) { + super(itemView); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/playlist/PlaylistAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/playlist/PlaylistAdapter.java new file mode 100755 index 00000000..7ae8e1a4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/playlist/PlaylistAdapter.java @@ -0,0 +1,300 @@ +package code.name.monkey.retromusic.ui.adapter.playlist; + +import android.graphics.Bitmap; +import android.graphics.PorterDuff; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.PopupMenu; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import com.bumptech.glide.Glide; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.ExecutionException; + +import butterknife.ButterKnife; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.ClearSmartPlaylistDialog; +import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog; +import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper; +import code.name.monkey.retromusic.helper.menu.SongsMenuHelper; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.loaders.PlaylistSongsLoader; +import code.name.monkey.retromusic.model.AbsCustomPlaylist; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist; +import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist; +import code.name.monkey.retromusic.ui.adapter.base.AbsMultiSelectAdapter; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.util.RetroUtil; +import io.reactivex.Observable; + +/** + * Created by BlackFootSanji on 9/19/2016. + */ +public class PlaylistAdapter extends AbsMultiSelectAdapter { + + public static final String TAG = PlaylistAdapter.class.getSimpleName(); + + private static final int SMART_PLAYLIST = 0; + private static final int DEFAULT_PLAYLIST = 1; + + protected final AppCompatActivity activity; + protected ArrayList dataSet; + protected int itemLayoutRes; + private ArrayList mSongs = new ArrayList<>(); + + + public PlaylistAdapter(AppCompatActivity activity, ArrayList dataSet, + @LayoutRes int itemLayoutRes, @Nullable CabHolder cabHolder) { + super(activity, cabHolder, R.menu.menu_playlists_selection); + this.activity = activity; + this.dataSet = dataSet; + this.itemLayoutRes = itemLayoutRes; + setHasStableIds(true); + } + + public ArrayList getDataSet() { + return dataSet; + } + + public void swapDataSet(ArrayList dataSet) { + this.dataSet = dataSet; + notifyDataSetChanged(); + } + + @Override + public long getItemId(int position) { + return dataSet.get(position).id; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(activity) + .inflate(itemLayoutRes, parent, false); + return createViewHolder(view, viewType); + } + + protected ViewHolder createViewHolder(View view, int viewType) { + return new ViewHolder(view, viewType); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + /* if (getItemViewType(position) == SMART_PLAYLIST) { + if (holder.viewList != null) { + holder.viewList.get(0).setOnClickListener( + v -> NavigationUtil.goToPlaylistNew(activity, new HistoryPlaylist(activity))); + holder.viewList.get(1).setOnClickListener( + v -> NavigationUtil.goToPlaylistNew(activity, new LastAddedPlaylist(activity))); + holder.viewList.get(2).setOnClickListener( + v -> NavigationUtil.goToPlaylistNew(activity, new MyTopTracksPlaylist(activity))); + } + return; + }*/ + final Playlist playlist = dataSet.get(position); + ArrayList songs = getSongs(playlist); + holder.itemView.setActivated(isChecked(playlist)); + + if (holder.title != null) { + holder.title.setText(playlist.name); + } + if (holder.text != null) { + holder.text.setText(String.format(Locale.getDefault(), "%d Songs", songs.size())); + } + if (holder.image != null) { + holder.image.setImageResource(getIconRes(playlist)); + } + if (holder.getAdapterPosition() == getItemCount() - 1) { + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.GONE); + } + } else { + if (holder.shortSeparator != null && !(dataSet.get(position) instanceof AbsSmartPlaylist)) { + holder.shortSeparator.setVisibility(View.VISIBLE); + } + } + } + + private int getIconRes(Playlist playlist) { + if (playlist instanceof AbsSmartPlaylist) { + return ((AbsSmartPlaylist) playlist).iconRes; + } + return MusicUtil.isFavoritePlaylist(activity, playlist) ? R.drawable.ic_favorite_white_24dp + : R.drawable.ic_playlist_play_white_24dp; + } + + @Override + public int getItemViewType(int position) { + return dataSet.get(position) instanceof AbsSmartPlaylist ? SMART_PLAYLIST : DEFAULT_PLAYLIST; + } + + @Override + public int getItemCount() { + return dataSet.size(); + } + + @Override + protected Playlist getIdentifier(int position) { + return dataSet.get(position); + } + + @Override + protected String getName(Playlist playlist) { + return playlist.name; + } + + @Override + protected void onMultipleItemAction(@NonNull MenuItem menuItem, + @NonNull ArrayList selection) { + switch (menuItem.getItemId()) { + case R.id.action_delete_playlist: + for (int i = 0; i < selection.size(); i++) { + Playlist playlist = selection.get(i); + if (playlist instanceof AbsSmartPlaylist) { + AbsSmartPlaylist absSmartPlaylist = (AbsSmartPlaylist) playlist; + ClearSmartPlaylistDialog.create(absSmartPlaylist) + .show(activity.getSupportFragmentManager(), + "CLEAR_PLAYLIST_" + absSmartPlaylist.name); + selection.remove(playlist); + i--; + } + } + if (selection.size() > 0) { + DeletePlaylistDialog.create(selection) + .show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST"); + } + break; + default: + SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.getItemId()); + break; + } + } + + public ArrayList getSongs() { + return mSongs; + } + + public void setSongs(ArrayList songs) { + mSongs = songs; + } + + @NonNull + private ArrayList getSongList(@NonNull List playlists) { + final ArrayList songs = new ArrayList<>(); + for (Playlist playlist : playlists) { + if (playlist instanceof AbsCustomPlaylist) { + songs.addAll(((AbsCustomPlaylist) playlist).getSongs(activity).blockingFirst()); + //((AbsCustomPlaylist) playlist).getSongs(activity).subscribe(this::setSongs); + } else { + songs + .addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id).blockingFirst()); + } + } + return songs; + } + + @Nullable + private ArrayList getSongs(@NonNull Playlist playlist) { + final ArrayList songs = new ArrayList<>(); + if (playlist instanceof AbsSmartPlaylist) { + songs.addAll(((AbsSmartPlaylist) playlist).getSongs(activity).blockingFirst()); + } else { + songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id).blockingFirst()); + } + return songs; + } + + private Observable> loadBitmaps(@NonNull ArrayList songs) { + return Observable.create(e -> { + ArrayList bitmaps = new ArrayList(); + for (Song song : songs) { + try { + Bitmap bitmap = Glide.with(activity) + .load(RetroUtil.getAlbumArtUri(song.albumId)) + .asBitmap() + .into(500, 500) + .get(); + if (bitmap != null) { + Log.i(TAG, "loadBitmaps: has"); + bitmaps.add(bitmap); + } + if (bitmaps.size() == 4) { + break; + } + } catch (InterruptedException | ExecutionException ex) { + ex.printStackTrace(); + } + } + e.onNext(bitmaps); + e.onComplete(); + }); + } + + public class ViewHolder extends MediaEntryViewHolder { + public ViewHolder(@NonNull View itemView, int itemViewType) { + super(itemView); + ButterKnife.bind(this, itemView); + if (image != null) { + int iconPadding = activity.getResources() + .getDimensionPixelSize(R.dimen.list_item_image_icon_padding); + image.setPadding(iconPadding, iconPadding, iconPadding, iconPadding); + image.setColorFilter(ATHUtil.resolveColor(activity, R.attr.iconColor), + PorterDuff.Mode.SRC_IN); + } + if (menu != null) { + menu.setOnClickListener(view -> { + final Playlist playlist = dataSet.get(getAdapterPosition()); + final PopupMenu popupMenu = new PopupMenu(activity, view); + popupMenu.inflate(getItemViewType() == SMART_PLAYLIST ? R.menu.menu_item_smart_playlist + : R.menu.menu_item_playlist); + if (playlist instanceof LastAddedPlaylist) { + popupMenu.getMenu().findItem(R.id.action_clear_playlist).setVisible(false); + } + popupMenu.setOnMenuItemClickListener(item -> { + if (item.getItemId() == R.id.action_clear_playlist) { + if (playlist instanceof AbsSmartPlaylist) { + ClearSmartPlaylistDialog.create((AbsSmartPlaylist) playlist) + .show(activity.getSupportFragmentManager(), + "CLEAR_SMART_PLAYLIST_" + playlist.name); + return true; + } + } + return PlaylistMenuHelper.handleMenuClick( + activity, dataSet.get(getAdapterPosition()), item); + }); + popupMenu.show(); + }); + } + } + + @Override + public void onClick(View view) { + if (isInQuickSelectMode()) { + toggleChecked(getAdapterPosition()); + } else { + Playlist playlist = dataSet.get(getAdapterPosition()); + NavigationUtil.goToPlaylistNew(activity, playlist); + } + } + + @Override + public boolean onLongClick(View view) { + toggleChecked(getAdapterPosition()); + return true; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/AbsOffsetSongAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/AbsOffsetSongAdapter.java new file mode 100644 index 00000000..bcbf6cc0 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/AbsOffsetSongAdapter.java @@ -0,0 +1,110 @@ +package code.name.monkey.retromusic.ui.adapter.song; + +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.model.Song; + + +public abstract class AbsOffsetSongAdapter extends SongAdapter { + + protected static final int OFFSET_ITEM = 0; + protected static final int SONG = 1; + + public AbsOffsetSongAdapter(AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) { + super(activity, dataSet, itemLayoutRes, usePalette, cabHolder); + } + + public AbsOffsetSongAdapter(AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, boolean showSectionName) { + super(activity, dataSet, itemLayoutRes, usePalette, cabHolder, showSectionName); + } + + @NonNull + @Override + public SongAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (viewType == OFFSET_ITEM) { + View view = LayoutInflater.from(activity).inflate(R.layout.item_list_single_row, parent, false); + return createViewHolder(view); + } + return super.onCreateViewHolder(parent, viewType); + } + + @Override + protected SongAdapter.ViewHolder createViewHolder(View view) { + return new AbsOffsetSongAdapter.ViewHolder(view); + } + + @Override + public long getItemId(int position) { + position--; + if (position < 0) return -2; + return super.getItemId(position); + } + + @Nullable + @Override + protected Song getIdentifier(int position) { + position--; + if (position < 0) return null; + return super.getIdentifier(position); + } + + @Override + public int getItemCount() { + int superItemCount = super.getItemCount(); + return superItemCount == 0 ? 0 : superItemCount + 1; + } + + @Override + public int getItemViewType(int position) { + return position == 0 ? OFFSET_ITEM : SONG; + } + + @NonNull + @Override + public String getSectionName(int position) { + position--; + if (position < 0) return ""; + return super.getSectionName(position); + } + + public class ViewHolder extends SongAdapter.ViewHolder { + + public ViewHolder(@NonNull View itemView) { + super(itemView); + } + + @Override + protected Song getSong() { + if (getItemViewType() == OFFSET_ITEM) + return Song.EMPTY_SONG; // could also return null, just to be safe return empty song + return dataSet.get(getAdapterPosition() - 1); + } + + @Override + public void onClick(View v) { + if (isInQuickSelectMode() && getItemViewType() != OFFSET_ITEM) { + toggleChecked(getAdapterPosition()); + } else { + MusicPlayerRemote.openQueue(dataSet, getAdapterPosition() - 1, true); + } + } + + @Override + public boolean onLongClick(View view) { + if (getItemViewType() == OFFSET_ITEM) return false; + toggleChecked(getAdapterPosition()); + return true; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/OrderablePlaylistSongAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/OrderablePlaylistSongAdapter.java new file mode 100644 index 00000000..cadfc52f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/OrderablePlaylistSongAdapter.java @@ -0,0 +1,145 @@ +package code.name.monkey.retromusic.ui.adapter.song; + +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.MenuItem; +import android.view.View; + +import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter; +import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder; +import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange; +import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags; +import code.name.monkey.retromusic.model.PlaylistSong; +import code.name.monkey.retromusic.model.Song; + +import java.util.ArrayList; +import java.util.List; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.RemoveFromPlaylistDialog; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.util.ViewUtil; + + +@SuppressWarnings("unchecked") +public class OrderablePlaylistSongAdapter extends PlaylistSongAdapter + implements DraggableItemAdapter { + + public static final String TAG = OrderablePlaylistSongAdapter.class.getSimpleName(); + + private OnMoveItemListener onMoveItemListener; + + public OrderablePlaylistSongAdapter(@NonNull AppCompatActivity activity, + @NonNull ArrayList dataSet, + @LayoutRes int itemLayoutRes, + boolean usePalette, + @Nullable CabHolder cabHolder, + @Nullable OnMoveItemListener onMoveItemListener) { + super(activity, (ArrayList) (List) dataSet, itemLayoutRes, usePalette, cabHolder); + setMultiSelectMenuRes(R.menu.menu_playlists_songs_selection); + this.onMoveItemListener = onMoveItemListener; + } + + @Override + protected SongAdapter.ViewHolder createViewHolder(View view) { + return new ViewHolder(view); + } + + @Override + public long getItemId(int position) { + position--; + if (position < 0) return -2; + return ((ArrayList) (List) dataSet).get(position).idInPlayList; // important! + } + + @Override + protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull ArrayList selection) { + switch (menuItem.getItemId()) { + case R.id.action_remove_from_playlist: + RemoveFromPlaylistDialog.create((ArrayList) (List) selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + return; + } + super.onMultipleItemAction(menuItem, selection); + } + + @Override + public boolean onCheckCanStartDrag(ViewHolder holder, int position, int x, int y) { + return onMoveItemListener != null && position > 0 && + (ViewUtil.hitTest(holder.dragView, x, y) || ViewUtil.hitTest(holder.image, x, y)); + } + + @Override + public ItemDraggableRange onGetItemDraggableRange(ViewHolder holder, int position) { + return new ItemDraggableRange(1, dataSet.size()); + } + + @Override + public void onMoveItem(int fromPosition, int toPosition) { + if (onMoveItemListener != null && fromPosition != toPosition) { + onMoveItemListener.onMoveItem(fromPosition - 1, toPosition - 1); + } + } + + @Override + public boolean onCheckCanDrop(int draggingPosition, int dropPosition) { + return dropPosition > 0; + } + + @Override + public void onItemDragStarted(int position) { + notifyDataSetChanged(); + } + + @Override + public void onItemDragFinished(int fromPosition, int toPosition, boolean result) { + notifyDataSetChanged(); + } + + public interface OnMoveItemListener { + void onMoveItem(int fromPosition, int toPosition); + } + + public class ViewHolder extends PlaylistSongAdapter.ViewHolder implements DraggableItemViewHolder { + @DraggableItemStateFlags + private int mDragStateFlags; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + if (dragView != null) { + if (onMoveItemListener != null) { + dragView.setVisibility(View.VISIBLE); + } else { + dragView.setVisibility(View.GONE); + } + } + } + + @Override + protected int getSongMenuRes() { + return R.menu.menu_item_playlist_song; + } + + @Override + protected boolean onSongMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_remove_from_playlist: + RemoveFromPlaylistDialog.create((PlaylistSong) getSong()).show(activity.getSupportFragmentManager(), "REMOVE_FROM_PLAYLIST"); + return true; + } + return super.onSongMenuItemClick(item); + } + + @Override + @DraggableItemStateFlags + public int getDragStateFlags() { + return mDragStateFlags; + } + + @Override + public void setDragStateFlags(@DraggableItemStateFlags int flags) { + mDragStateFlags = flags; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/PlayingQueueAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/PlayingQueueAdapter.java new file mode 100644 index 00000000..027c3d7d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/PlayingQueueAdapter.java @@ -0,0 +1,209 @@ +package code.name.monkey.retromusic.ui.adapter.song; + +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.MenuItem; +import android.view.View; +import android.widget.ImageView; + +import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter; +import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder; +import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange; +import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.ViewUtil; + + +public class PlayingQueueAdapter extends SongAdapter implements + DraggableItemAdapter { + + private static final int HISTORY = 0; + private static final int CURRENT = 1; + private static final int UP_NEXT = 2; + + private int current; + + public PlayingQueueAdapter(AppCompatActivity activity, ArrayList dataSet, int current, + @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) { + super(activity, dataSet, itemLayoutRes, usePalette, cabHolder); + this.current = current; + } + + @Override + protected SongAdapter.ViewHolder createViewHolder(View view) { + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull SongAdapter.ViewHolder holder, int position) { + super.onBindViewHolder(holder, position); + if (holder.imageText != null) { + holder.imageText.setText(String.valueOf(position - current)); + } + if (holder.time != null) { + holder.time.setText(MusicUtil.getReadableDurationString(getDataSet().get(position).duration)); + } + if (holder.getItemViewType() == HISTORY || holder.getItemViewType() == CURRENT) { + setAlpha(holder, 0.5f); + } + if (usePalette) { + setColor(holder, Color.WHITE); + } + } + + private void setColor(SongAdapter.ViewHolder holder, int white) { + + if (holder.title != null) { + holder.title.setTextColor(white); + } + if (holder.text != null) { + holder.text.setTextColor(white); + } + if (holder.time != null) { + holder.time.setTextColor(white); + } + if (holder.imageText != null) { + holder.imageText.setTextColor(white); + } + if (holder.menu != null) { + ((ImageView) holder.menu).setColorFilter(white, PorterDuff.Mode.SRC_IN); + } + } + + @Override + public void usePalette(boolean color) { + super.usePalette(color); + usePalette = color; + notifyDataSetChanged(); + } + + @Override + public int getItemViewType(int position) { + if (position < current) { + return HISTORY; + } else if (position > current) { + return UP_NEXT; + } + return CURRENT; + } + + @Override + protected void loadAlbumCover(Song song, SongAdapter.ViewHolder holder) { + // We don't want to load it in this adapter + } + + public void swapDataSet(ArrayList dataSet, int position) { + this.dataSet = dataSet; + current = position; + notifyDataSetChanged(); + } + + public void setCurrent(int current) { + this.current = current; + notifyDataSetChanged(); + } + + private void setAlpha(SongAdapter.ViewHolder holder, float alpha) { + if (holder.image != null) { + holder.image.setAlpha(alpha); + } + if (holder.title != null) { + holder.title.setAlpha(alpha); + } + if (holder.text != null) { + holder.text.setAlpha(alpha); + } + if (holder.imageText != null) { + holder.imageText.setAlpha(alpha); + } + if (holder.paletteColorContainer != null) { + holder.paletteColorContainer.setAlpha(alpha); + } + } + + @Override + public boolean onCheckCanStartDrag(ViewHolder holder, int position, int x, int y) { + return ViewUtil.hitTest(holder.imageText, x, y) || (ViewUtil.hitTest(holder.dragView, x, y)); + } + + @Override + public ItemDraggableRange onGetItemDraggableRange(ViewHolder holder, int position) { + return null; + } + + @Override + public void onMoveItem(int fromPosition, int toPosition) { + MusicPlayerRemote.moveSong(fromPosition, toPosition); + } + + @Override + public boolean onCheckCanDrop(int draggingPosition, int dropPosition) { + return true; + } + + @Override + public void onItemDragStarted(int position) { + notifyDataSetChanged(); + } + + @Override + public void onItemDragFinished(int fromPosition, int toPosition, boolean result) { + notifyDataSetChanged(); + } + + public class ViewHolder extends SongAdapter.ViewHolder implements DraggableItemViewHolder { + + @DraggableItemStateFlags + private int mDragStateFlags; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + if (imageText != null) { + imageText.setVisibility(View.VISIBLE); + } + if (image != null) { + image.setVisibility(View.GONE); + } + if (dragView != null) { + dragView.setVisibility(View.VISIBLE); + } + } + + @Override + protected int getSongMenuRes() { + return R.menu.menu_item_playing_queue_song; + } + + @Override + protected boolean onSongMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_remove_from_playing_queue: + MusicPlayerRemote.removeFromQueue(getAdapterPosition()); + return true; + } + return super.onSongMenuItemClick(item); + } + + @Override + @DraggableItemStateFlags + public int getDragStateFlags() { + return mDragStateFlags; + } + + @Override + public void setDragStateFlags(@DraggableItemStateFlags int flags) { + mDragStateFlags = flags; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/PlaylistSongAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/PlaylistSongAdapter.java new file mode 100644 index 00000000..eb2ae048 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/PlaylistSongAdapter.java @@ -0,0 +1,93 @@ +package code.name.monkey.retromusic.ui.adapter.song; + +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.util.Pair; +import android.support.v7.app.AppCompatActivity; +import android.view.MenuItem; +import android.view.View; + +import java.util.ArrayList; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.NavigationUtil; + + +public class PlaylistSongAdapter extends AbsOffsetSongAdapter { + + public static final String TAG = PlaylistSongAdapter.class.getSimpleName(); + + public PlaylistSongAdapter(AppCompatActivity activity, @NonNull ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) { + super(activity, dataSet, itemLayoutRes, usePalette, cabHolder, false); + setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection); + } + + @Override + protected SongAdapter.ViewHolder createViewHolder(View view) { + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull final SongAdapter.ViewHolder holder, int position) { + if (holder.getItemViewType() == OFFSET_ITEM) { + int textColor = ThemeStore.textColorSecondary(activity); + if (holder.title != null) { + holder.title.setText(MusicUtil.getPlaylistInfoString(activity, dataSet)); + holder.title.setTextColor(textColor); + } + + + if (holder.text != null) { + holder.text.setVisibility(View.GONE); + } + if (holder.menu != null) { + holder.menu.setVisibility(View.GONE); + } + if (holder.image != null) { + final int padding = activity.getResources().getDimensionPixelSize(R.dimen.default_item_margin) / 2; + holder.image.setPadding(padding, padding, padding, padding); + holder.image.setColorFilter(textColor); + holder.image.setImageResource(R.drawable.ic_timer_white_24dp); + } + if (holder.dragView != null) { + holder.dragView.setVisibility(View.GONE); + } + if (holder.separator != null) { + holder.separator.setVisibility(View.VISIBLE); + } + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.GONE); + } + } else { + super.onBindViewHolder(holder, position - 1); + } + } + + public class ViewHolder extends AbsOffsetSongAdapter.ViewHolder { + public ViewHolder(@NonNull View itemView) { + super(itemView); + + } + + @Override + protected int getSongMenuRes() { + return R.menu.menu_item_cannot_delete_single_songs_playlist_song; + } + + @Override + protected boolean onSongMenuItemClick(MenuItem item) { + if (item.getItemId() == R.id.action_go_to_album) { + Pair[] albumPairs = new Pair[]{ + Pair.create(image, activity.getString(R.string.transition_album_art))}; + NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition() - 1).albumId, albumPairs); + return true; + } + return super.onSongMenuItemClick(item); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/ShuffleButtonSongAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/ShuffleButtonSongAdapter.java new file mode 100644 index 00000000..b2fd96c4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/ShuffleButtonSongAdapter.java @@ -0,0 +1,78 @@ +package code.name.monkey.retromusic.ui.adapter.song; + +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.model.Song; +import java.util.ArrayList; + + +public class ShuffleButtonSongAdapter extends AbsOffsetSongAdapter { + + public ShuffleButtonSongAdapter(AppCompatActivity activity, ArrayList dataSet, + @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) { + super(activity, dataSet, itemLayoutRes, usePalette, cabHolder); + } + + @Override + protected SongAdapter.ViewHolder createViewHolder(View view) { + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull final SongAdapter.ViewHolder holder, int position) { + if (holder.getItemViewType() == OFFSET_ITEM) { + int accentColor = ThemeStore.accentColor(activity); + if (holder.title != null) { + holder.title.setText(activity.getResources().getString(R.string.action_shuffle_all)); + holder.title.setTextColor(accentColor); + /*((GradientTextView) holder.title).setLinearGradient(ThemeStore.accentColor(activity), + PhonographColorUtil.getMatColor(activity, "A400"), GradientTextView.LG_VERTICAL); + */ + } + if (holder.text != null) { + holder.text.setVisibility(View.GONE); + } + if (holder.menu != null) { + holder.menu.setVisibility(View.GONE); + } + if (holder.image != null) { + final int padding = + activity.getResources().getDimensionPixelSize(R.dimen.default_item_margin) / 2; + holder.image.setPadding(padding, padding, padding, padding); + holder.image.setColorFilter(accentColor); + holder.image.setImageResource(R.drawable.ic_shuffle_white_24dp); + } + if (holder.separator != null) { + holder.separator.setVisibility(View.VISIBLE); + } + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.GONE); + } + } else { + super.onBindViewHolder(holder, position - 1); + } + } + + public class ViewHolder extends AbsOffsetSongAdapter.ViewHolder { + + public ViewHolder(@NonNull View itemView) { + super(itemView); + } + + @Override + public void onClick(View v) { + if (getItemViewType() == OFFSET_ITEM) { + MusicPlayerRemote.openAndShuffleQueue(dataSet, true); + return; + } + super.onClick(v); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SimpleSongAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SimpleSongAdapter.java new file mode 100755 index 00000000..050e8427 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SimpleSongAdapter.java @@ -0,0 +1,69 @@ +package code.name.monkey.retromusic.ui.adapter.song; + +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatActivity; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import java.util.ArrayList; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.util.MusicUtil; + +/** + * Created by Monkey D Luffy on 3/31/2016. + */ +public class SimpleSongAdapter extends SongAdapter { + + private int textColor; + + public SimpleSongAdapter(AppCompatActivity context, ArrayList songs, @LayoutRes int i) { + super(context, songs, i, false, null); + textColor = ThemeStore.textColorPrimary(context); + } + + public void swapDataSet(ArrayList arrayList) { + this.dataSet.clear(); + this.dataSet = arrayList; + notifyDataSetChanged(); + } + + @NonNull + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ViewHolder(LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + super.onBindViewHolder(holder, position); + int fixedTrackNumber = MusicUtil.getFixedTrackNumber(dataSet.get(position).trackNumber); + + if (holder.imageText != null) { + holder.imageText.setText(fixedTrackNumber > 0 ? String.valueOf(fixedTrackNumber) : "-"); + holder.imageText.setTextColor(textColor); + } + + if (holder.time != null) { + holder.time.setText(MusicUtil.getReadableDurationString(dataSet.get(position).duration)); + holder.time.setTextColor(textColor); + } + if (holder.title != null) { + holder.title.setTextColor(textColor); + } + if (holder.menu != null) { + TintHelper.setTintAuto(holder.menu, textColor, false); + } + } + + public int getItemCount() { + return dataSet.size(); + } + + public void setTextColor(int textColor) { + this.textColor = textColor; + notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SongAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SongAdapter.java new file mode 100644 index 00000000..99fadd57 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SongAdapter.java @@ -0,0 +1,294 @@ +package code.name.monkey.retromusic.ui.adapter.song; + +import android.graphics.drawable.Drawable; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.util.Pair; +import android.support.v7.app.AppCompatActivity; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import com.afollestad.materialcab.MaterialCab; +import com.bumptech.glide.Glide; +import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; + +import java.util.ArrayList; + +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.SortOrder; +import code.name.monkey.retromusic.helper.menu.SongMenuHelper; +import code.name.monkey.retromusic.helper.menu.SongsMenuHelper; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.adapter.base.AbsMultiSelectAdapter; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * Created by hemanths on 13/08/17. + */ + +public class SongAdapter extends AbsMultiSelectAdapter + implements MaterialCab.Callback, FastScrollRecyclerView.SectionedAdapter { + + public static final String TAG = SongAdapter.class.getSimpleName(); + + protected final AppCompatActivity activity; + protected ArrayList dataSet; + + protected int itemLayoutRes; + + protected boolean usePalette = false; + private boolean showSectionName = true; + + + public SongAdapter(AppCompatActivity activity, ArrayList dataSet, + @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) { + this(activity, dataSet, itemLayoutRes, usePalette, cabHolder, true); + } + + public SongAdapter(AppCompatActivity activity, ArrayList dataSet, + @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, + boolean showSectionName) { + super(activity, cabHolder, R.menu.menu_media_selection); + this.activity = activity; + this.dataSet = dataSet; + this.itemLayoutRes = itemLayoutRes; + this.usePalette = usePalette; + this.showSectionName = showSectionName; + setHasStableIds(true); + } + + public void swapDataSet(ArrayList dataSet) { + this.dataSet = dataSet; + notifyDataSetChanged(); + } + + public void usePalette(boolean usePalette) { + this.usePalette = usePalette; + notifyDataSetChanged(); + } + + public ArrayList getDataSet() { + return dataSet; + } + + @Override + public long getItemId(int position) { + return dataSet.get(position).id; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false); + return createViewHolder(view); + } + + protected ViewHolder createViewHolder(View view) { + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { + final Song song = dataSet.get(position); + + boolean isChecked = isChecked(song); + holder.itemView.setActivated(isChecked); + + if (holder.getAdapterPosition() == getItemCount() - 1) { + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.GONE); + } + } else { + if (holder.shortSeparator != null) { + holder.shortSeparator.setVisibility(View.VISIBLE); + } + } + + if (holder.title != null) { + holder.title.setText(getSongTitle(song)); + } + if (holder.text != null) { + holder.text.setText(getSongText(song)); + } + + loadAlbumCover(song, holder); + + } + + private void setColors(int color, ViewHolder holder) { + if (holder.paletteColorContainer != null) { + holder.paletteColorContainer.setBackgroundColor(color); + if (holder.title != null) { + holder.title.setTextColor( + MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color))); + } + if (holder.text != null) { + holder.text.setTextColor( + MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color))); + } + } + } + + protected void loadAlbumCover(Song song, final ViewHolder holder) { + if (holder.image == null) { + return; + } + SongGlideRequest.Builder.from(Glide.with(activity), song) + .checkIgnoreMediaStore(activity) + .generatePalette(activity).build() + .into(new RetroMusicColoredTarget(holder.image) { + @Override + public void onLoadCleared(Drawable placeholder) { + super.onLoadCleared(placeholder); + setColors(getDefaultFooterColor(), holder); + } + + @Override + public void onColorReady(int color) { + setColors(color, holder); + } + }); + } + + private String getSongTitle(Song song) { + return song.title; + } + + private String getSongText(Song song) { + return song.artistName; + } + + @Override + public int getItemCount() { + return dataSet.size(); + } + + @Override + protected Song getIdentifier(int position) { + return dataSet.get(position); + } + + @Override + protected String getName(Song song) { + return song.title; + } + + @Override + protected void onMultipleItemAction(@NonNull MenuItem menuItem, + @NonNull ArrayList selection) { + SongsMenuHelper.handleMenuClick(activity, selection, menuItem.getItemId()); + } + + @NonNull + @Override + public String getSectionName(int position) { + if (!showSectionName) { + return ""; + } + @Nullable String sectionName = null; + switch (PreferenceUtil.getInstance(activity).getSongSortOrder()) { + case SortOrder.SongSortOrder.SONG_A_Z: + case SortOrder.SongSortOrder.SONG_Z_A: + sectionName = dataSet.get(position).title; + break; + case SortOrder.SongSortOrder.SONG_ALBUM: + sectionName = dataSet.get(position).albumName; + break; + case SortOrder.SongSortOrder.SONG_ARTIST: + sectionName = dataSet.get(position).artistName; + break; + case SortOrder.SongSortOrder.SONG_YEAR: + return MusicUtil.getYearString(dataSet.get(position).year); + } + + return MusicUtil.getSectionName(sectionName); + } + + public class ViewHolder extends MediaEntryViewHolder { + + int DEFAULT_MENU_RES = SongMenuHelper.MENU_RES; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + setImageTransitionName(activity.getString(R.string.transition_album_art)); + + /*if (mItemView != null) { + mItemView.setOnMenuItemClickListener(new ListItemView.OnMenuItemClickListener() { + @Override + public void onActionMenuItemSelected(MenuItem item) { + SongMenuHelper.handleMenuClick(activity, dataSet.get(getAdapterPosition()), item.getItemId()); + } + }); + }*/ + + if (menu == null) { + return; + } + menu.setOnClickListener(new SongMenuHelper.OnClickSongMenu(activity) { + @Override + public Song getSong() { + return ViewHolder.this.getSong(); + } + + @Override + public int getMenuRes() { + return getSongMenuRes(); + } + + @Override + public boolean onMenuItemClick(MenuItem item) { + return onSongMenuItemClick(item) || super.onMenuItemClick(item); + } + }); + } + + protected Song getSong() { + return dataSet.get(getAdapterPosition()); + } + + protected int getSongMenuRes() { + return DEFAULT_MENU_RES; + } + + protected boolean onSongMenuItemClick(MenuItem item) { + if (image != null && image.getVisibility() == View.VISIBLE) { + switch (item.getItemId()) { + case R.id.action_go_to_album: + Pair[] albumPairs = new Pair[]{ + Pair.create(imageContainer, + activity.getResources().getString(R.string.transition_album_art)) + }; + NavigationUtil.goToAlbum(activity, getSong().albumId, albumPairs); + return true; + } + } + return false; + } + + @Override + public void onClick(View v) { + if (isInQuickSelectMode()) { + toggleChecked(getAdapterPosition()); + } else { + MusicPlayerRemote.openQueue(dataSet, getAdapterPosition(), true); + } + } + + @Override + public boolean onLongClick(View view) { + return toggleChecked(getAdapterPosition()); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/MiniPlayerFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/MiniPlayerFragment.java new file mode 100644 index 00000000..6035247b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/MiniPlayerFragment.java @@ -0,0 +1,176 @@ +package code.name.monkey.retromusic.ui.fragments; + +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.GestureDetector; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.widget.ImageView; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler; +import code.name.monkey.retromusic.ui.fragments.base.AbsMusicServiceFragment; +import code.name.monkey.retromusic.views.PlayPauseDrawable; +import me.zhanghai.android.materialprogressbar.MaterialProgressBar; + +public class MiniPlayerFragment extends AbsMusicServiceFragment implements + MusicProgressViewUpdateHelper.Callback { + + @BindView(R.id.mini_player_title) + TextView miniPlayerTitle; + @BindView(R.id.mini_player_play_pause_button) + ImageView miniPlayerPlayPauseButton; + @BindView(R.id.progress_bar) + MaterialProgressBar progressBar; + + private Unbinder unbinder; + private PlayPauseDrawable miniPlayerPlayPauseDrawable; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_mini_player, container, false); + unbinder = ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + view.setBackgroundColor(ThemeStore.primaryColor(getContext())); + view.setOnTouchListener(new FlingPlayBackController(getActivity())); + setUpMiniPlayer(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @SuppressWarnings({"ConstantConditions"}) + private void setUpMiniPlayer() { + setUpPlayPauseButton(); + progressBar.setProgressTintList(ColorStateList.valueOf(ThemeStore.accentColor(getActivity()))); + } + + private void setUpPlayPauseButton() { + //noinspection ConstantConditions + miniPlayerPlayPauseDrawable = new PlayPauseDrawable(getActivity()); + miniPlayerPlayPauseButton.setImageDrawable(miniPlayerPlayPauseDrawable); + miniPlayerPlayPauseButton.setColorFilter(ATHUtil.resolveColor(getActivity(), + R.attr.iconColor, + ThemeStore.textColorSecondary(getActivity())), PorterDuff.Mode.SRC_IN); + miniPlayerPlayPauseButton.setOnClickListener(new PlayPauseButtonOnClickHandler()); + } + + private void updateSongTitle() { + miniPlayerTitle.setText(MusicPlayerRemote.getCurrentSong().title); + } + + @Override + public void onServiceConnected() { + updateSongTitle(); + updatePlayPauseDrawableState(false); + } + + @Override + public void onPlayingMetaChanged() { + updateSongTitle(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressBar.setMax(total); + ObjectAnimator animator = ObjectAnimator.ofInt(progressBar, "progress", progress); + animator.setDuration(1000); + animator.setInterpolator(new DecelerateInterpolator()); + animator.start(); + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + miniPlayerPlayPauseDrawable.setPause(animate); + } else { + miniPlayerPlayPauseDrawable.setPlay(animate); + } + } + + public void setColor(int playerFragmentColor) { + //noinspection ConstantConditions + getView().setBackgroundColor(playerFragmentColor); + } + + public static class FlingPlayBackController implements View.OnTouchListener { + + GestureDetector flingPlayBackController; + + public FlingPlayBackController(Context context) { + flingPlayBackController = new GestureDetector(context, + new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + float velocityY) { + if (Math.abs(velocityX) > Math.abs(velocityY)) { + if (velocityX < 0) { + MusicPlayerRemote.playNextSong(); + return true; + } else if (velocityX > 0) { + MusicPlayerRemote.playPreviousSong(); + return true; + } + } + return false; + } + }); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouch(View v, MotionEvent event) { + return flingPlayBackController.onTouchEvent(event); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.java new file mode 100644 index 00000000..77483265 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.java @@ -0,0 +1,34 @@ +package code.name.monkey.retromusic.ui.fragments; + +import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; + +import code.name.monkey.retromusic.R; + + +public enum NowPlayingScreen { + NORMAL(R.string.normal, R.drawable.np_normal, 0), + FLAT(R.string.flat, R.drawable.np_flat, 1), + FULL(R.string.full, R.drawable.np_full, 2), + PLAIN(R.string.plain, R.drawable.np_plain, 3), + BLUR(R.string.blur, R.drawable.np_blur, 4), + COLOR(R.string.color, R.drawable.np_color, 5), + CARD(R.string.card, R.drawable.np_card, 6), + TINY(R.string.tiny, R.drawable.np_tiny, 7), + SIMPLE(R.string.simple, R.drawable.np_simple, 8), + BLUR_CARD(R.string.blur_card, R.drawable.np_blur_card, 9), + ADAPTIVE(R.string.adaptive, R.drawable.np_adaptive, 10), + MATERIAL(R.string.material, R.drawable.np_normal, 11); + + @StringRes + public final int titleRes; + @DrawableRes + public final int drawableResId; + public final int id; + + NowPlayingScreen(@StringRes int titleRes, @DrawableRes int drawableResId, int id) { + this.titleRes = titleRes; + this.drawableResId = drawableResId; + this.id = id; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/PlayingQueueFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/PlayingQueueFragment.java new file mode 100644 index 00000000..6dd59ae5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/PlayingQueueFragment.java @@ -0,0 +1,143 @@ +package code.name.monkey.retromusic.ui.fragments; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.ui.adapter.song.PlayingQueueAdapter; +import code.name.monkey.retromusic.ui.fragments.base.AbsMusicServiceFragment; +import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator; +import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator; +import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager; +import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils; + +public class PlayingQueueFragment extends AbsMusicServiceFragment { + + @BindView(R.id.recycler_view) + RecyclerView mRecyclerView; + Unbinder unbinder; + private RecyclerView.Adapter mWrappedAdapter; + private RecyclerViewDragDropManager mRecyclerViewDragDropManager; + private PlayingQueueAdapter mPlayingQueueAdapter; + private LinearLayoutManager mLayoutManager; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_main_activity_recycler_view, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setUpRecyclerView(); + } + + private void setUpRecyclerView() { + mRecyclerViewDragDropManager = new RecyclerViewDragDropManager(); + final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator(); + + mPlayingQueueAdapter = new PlayingQueueAdapter( + (AppCompatActivity) getActivity(), + MusicPlayerRemote.getPlayingQueue(), + MusicPlayerRemote.getPosition(), + R.layout.item_list, + false, + null); + mWrappedAdapter = mRecyclerViewDragDropManager.createWrappedAdapter(mPlayingQueueAdapter); + + mLayoutManager = new LinearLayoutManager(getContext()); + + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.setAdapter(mWrappedAdapter); + mRecyclerView.setItemAnimator(animator); + mRecyclerViewDragDropManager.attachRecyclerView(mRecyclerView); + mLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0); + } + + @Override + public void onQueueChanged() { + updateQueue(); + updateCurrentSong(); + } + + @Override + public void onMediaStoreChanged() { + updateQueue(); + updateCurrentSong(); + } + + @SuppressWarnings("ConstantConditions") + private void updateCurrentSong() { + } + + @Override + public void onPlayingMetaChanged() { + //updateCurrentSong(); + //updateIsFavorite(); + updateQueuePosition(); + //updateLyrics(); + } + + private void updateQueuePosition() { + mPlayingQueueAdapter.setCurrent(MusicPlayerRemote.getPosition()); + // if (slidingUpPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) { + resetToCurrentPosition(); + //} + } + + private void updateQueue() { + mPlayingQueueAdapter + .swapDataSet(MusicPlayerRemote.getPlayingQueue(), MusicPlayerRemote.getPosition()); + resetToCurrentPosition(); + } + + private void resetToCurrentPosition() { + mRecyclerView.stopScroll(); + mLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0); + } + + @Override + public void onPause() { + if (mRecyclerViewDragDropManager != null) { + mRecyclerViewDragDropManager.cancelDrag(); + } + super.onPause(); + } + + @Override + public void onDestroyView() { + if (mRecyclerViewDragDropManager != null) { + mRecyclerViewDragDropManager.release(); + mRecyclerViewDragDropManager = null; + } + + if (mRecyclerView != null) { + mRecyclerView.setItemAnimator(null); + mRecyclerView.setAdapter(null); + mRecyclerView = null; + } + + if (mWrappedAdapter != null) { + WrapperAdapterUtils.releaseAll(mWrappedAdapter); + mWrappedAdapter = null; + } + mPlayingQueueAdapter = null; + mLayoutManager = null; + super.onDestroyView(); + unbinder.unbind(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/VolumeFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/VolumeFragment.java new file mode 100755 index 00000000..f9a4e927 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/VolumeFragment.java @@ -0,0 +1,158 @@ +package code.name.monkey.retromusic.ui.fragments; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.media.AudioManager; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.SeekBar; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.volume.AudioVolumeObserver; +import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener; + +public class VolumeFragment extends Fragment implements SeekBar.OnSeekBarChangeListener, + OnAudioVolumeChangedListener { + + @BindView(R.id.volume_seekbar) + SeekBar volumeSeekbar; + @BindView(R.id.volume_down) + ImageView volumeDown; + @BindView(R.id.container) + ViewGroup viewGroup; + @BindView(R.id.volume_up) + ImageView volumeUp; + + private Unbinder unbinder; + private AudioVolumeObserver mAudioVolumeObserver; + + public static VolumeFragment newInstance() { + return new VolumeFragment(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_volume, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + //noinspection ConstantConditions + setColor(ThemeStore.textColorSecondary(getContext())); + } + + @Override + public void onResume() { + super.onResume(); + if (mAudioVolumeObserver == null) { + //noinspection ConstantConditions + mAudioVolumeObserver = new AudioVolumeObserver(getActivity()); + } + mAudioVolumeObserver.register(AudioManager.STREAM_MUSIC, this); + + AudioManager audioManager = getAudioManager(); + if (audioManager != null) { + volumeSeekbar.setMax(audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)); + volumeSeekbar.setProgress(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)); + } + volumeSeekbar.setOnSeekBarChangeListener(this); + } + + @Override + public void onAudioVolumeChanged(int currentVolume, int maxVolume) { + if (volumeSeekbar == null) { + return; + } + volumeSeekbar.setMax(maxVolume); + volumeSeekbar.setProgress(currentVolume); + volumeDown.setImageResource(currentVolume == 0 ? R.drawable.ic_volume_off_white_24dp : R.drawable.ic_volume_down_white_24dp); + } + + private AudioManager getAudioManager() { + //noinspection ConstantConditions + return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + if (mAudioVolumeObserver != null) { + mAudioVolumeObserver.unregister(); + } + } + + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) { + AudioManager audioManager = getAudioManager(); + if (audioManager != null) { + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, i, 0); + } + volumeDown.setImageResource( + i == 0 ? R.drawable.ic_volume_off_white_24dp : R.drawable.ic_volume_down_white_24dp); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + + } + + @OnClick({R.id.volume_down, R.id.volume_up}) + public void onViewClicked(View view) { + AudioManager audioManager = getAudioManager(); + switch (view.getId()) { + case R.id.volume_down: + if (audioManager != null) { + audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, 0); + } + break; + case R.id.volume_up: + if (audioManager != null) { + audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 0); + } + break; + } + } + + public void setColor(int color) { + volumeSeekbar.setProgressTintList(ColorStateList.valueOf(color)); + } + + public void tintWhiteColor() { + setProgressBarColor(Color.WHITE); + } + + public void setProgressBarColor(int newColor) { + TintHelper.setTintAuto(volumeSeekbar, newColor, false); + volumeDown.setColorFilter(newColor, PorterDuff.Mode.SRC_IN); + volumeUp.setColorFilter(newColor, PorterDuff.Mode.SRC_IN); + } + + public void setTintable(int color) { + setProgressBarColor(color); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerFragment.java new file mode 100644 index 00000000..5871de85 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerFragment.java @@ -0,0 +1,20 @@ +package code.name.monkey.retromusic.ui.fragments.base; + +import android.os.Bundle; +import android.support.v4.app.LoaderManager; + +import code.name.monkey.retromusic.ui.fragments.mainactivity.LibraryFragment; + +public class AbsLibraryPagerFragment extends AbsMusicServiceFragment { + + + public LibraryFragment getLibraryFragment() { + return (LibraryFragment) getParentFragment(); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + setHasOptionsMenu(true); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.java new file mode 100644 index 00000000..16f999ef --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.java @@ -0,0 +1,169 @@ +package code.name.monkey.retromusic.ui.fragments.base; + +import android.os.Bundle; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.util.RetroUtil; + + +public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment extends + AbsLibraryPagerRecyclerViewFragment { + + private int gridSize; + private String sortOrder; + + private boolean usePaletteInitialized; + private boolean usePalette; + private int currentLayoutRes; + + public final int getGridSize() { + if (gridSize == 0) { + if (isLandscape()) { + gridSize = loadGridSizeLand(); + } else { + gridSize = loadGridSize(); + } + } + return gridSize; + } + + protected abstract void setGridSize(int gridSize); + + public final String getSortOrder() { + if (sortOrder == null) { + sortOrder = loadSortOrder(); + } + return sortOrder; + } + + protected abstract void setSortOrder(String sortOrder); + + public void setAndSaveSortOrder(final String sortOrder) { + this.sortOrder = sortOrder; + saveSortOrder(sortOrder); + setSortOrder(sortOrder); + } + + public int getMaxGridSize() { + if (isLandscape()) { + return getResources().getInteger(R.integer.max_columns_land); + } else { + return getResources().getInteger(R.integer.max_columns); + } + } + + /** + * @return whether the palette should be used at all or not + */ + public final boolean usePalette() { + if (!usePaletteInitialized) { + usePalette = loadUsePalette(); + usePaletteInitialized = true; + } + return usePalette; + } + + public void setAndSaveGridSize(final int gridSize) { + int oldLayoutRes = getItemLayoutRes(); + this.gridSize = gridSize; + if (isLandscape()) { + saveGridSizeLand(gridSize); + } else { + saveGridSize(gridSize); + } + // only recreate the adapter and layout manager if the layout currentLayoutRes has changed + if (oldLayoutRes != getItemLayoutRes()) { + invalidateLayoutManager(); + invalidateAdapter(); + } else { + setGridSize(gridSize); + } + } + + public void setAndSaveUsePalette(final boolean usePalette) { + this.usePalette = usePalette; + saveUsePalette(usePalette); + setUsePalette(usePalette); + } + + /** + * @return whether the palette option should be available for the current item layout or not + */ + public boolean canUsePalette() { + return getItemLayoutRes() == R.layout.item_color; + } + + /** + * Override to customize which item layout currentLayoutRes should be used. You might also want to + * override {@link #canUsePalette()} then. + * + * @see #getGridSize() + */ + @LayoutRes + protected int getItemLayoutRes() { + if (getGridSize() > getMaxGridSizeForList()) { + return R.layout.item_grid; + } + return R.layout.item_list; + } + + protected final void notifyLayoutResChanged(@LayoutRes int res) { + this.currentLayoutRes = res; + RecyclerView recyclerView = getRecyclerView(); + if (recyclerView != null) { + applyRecyclerViewPaddingForLayoutRes(recyclerView, currentLayoutRes); + } + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + applyRecyclerViewPaddingForLayoutRes(getRecyclerView(), currentLayoutRes); + } + + protected void applyRecyclerViewPaddingForLayoutRes(@NonNull RecyclerView recyclerView, + @LayoutRes int res) { + int padding; + if (res == R.layout.item_grid) { + padding = (int) (getResources().getDisplayMetrics().density * 2); + } else { + padding = 0; + } + recyclerView.setPadding(padding, padding, padding, padding); + } + + protected abstract String loadSortOrder(); + + protected abstract void saveSortOrder(String sortOrder); + + protected abstract int loadGridSize(); + + protected abstract void saveGridSize(int gridColumns); + + protected abstract int loadGridSizeLand(); + + protected abstract void saveGridSizeLand(int gridColumns); + + protected abstract void saveUsePalette(boolean usePalette); + + protected abstract boolean loadUsePalette(); + + protected abstract void setUsePalette(boolean usePalette); + + protected int getMaxGridSizeForList() { + if (isLandscape()) { + return getActivity().getResources().getInteger(R.integer.default_list_columns_land); + } + return getActivity().getResources().getInteger(R.integer.default_list_columns); + } + + protected final boolean isLandscape() { + return RetroUtil.isLandscape(getResources()); + } + + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewFragment.java new file mode 100644 index 00000000..76210cf9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewFragment.java @@ -0,0 +1,162 @@ +package code.name.monkey.retromusic.ui.fragments.base; + +import android.os.Bundle; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.StringRes; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.AppBarLayout.OnOffsetChangedListener; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.util.ViewUtil; + + +public abstract class AbsLibraryPagerRecyclerViewFragment extends + AbsLibraryPagerFragment implements OnOffsetChangedListener { + + public static final String TAG = AbsLibraryPagerRecyclerViewFragment.class.getSimpleName(); + @BindView(R.id.container) + ViewGroup container; + @BindView(R.id.recycler_view) + RecyclerView recyclerView; + @BindView(android.R.id.empty) + TextView empty; + + private Unbinder unbinder; + private A adapter; + private LM layoutManager; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(getLayoutRes(), container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + getLibraryFragment().addOnAppBarOffsetChangedListener(this); + initLayoutManager(); + initAdapter(); + setUpRecyclerView(); + } + + private void setUpRecyclerView() { + if (recyclerView instanceof FastScrollRecyclerView) { + //noinspection ConstantConditions + ViewUtil.setUpFastScrollRecyclerViewColor(getActivity(), + ((FastScrollRecyclerView) recyclerView), ThemeStore.accentColor(getActivity())); + } + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(adapter); + } + + @Override + public void onQueueChanged() { + super.onQueueChanged(); + checkForPadding(); + } + + @Override + public void onServiceConnected() { + super.onServiceConnected(); + checkForPadding(); + } + + private void checkForPadding() { + int height = (MusicPlayerRemote.getPlayingQueue().isEmpty() ? getResources().getDimensionPixelSize(R.dimen.mini_player_height) : 0); + recyclerView.setPadding(0, 0, 0, height); + } + + protected void invalidateLayoutManager() { + initLayoutManager(); + recyclerView.setLayoutManager(layoutManager); + } + + protected void invalidateAdapter() { + initAdapter(); + checkIsEmpty(); + recyclerView.setAdapter(adapter); + } + + private void initAdapter() { + adapter = createAdapter(); + adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { + @Override + public void onChanged() { + super.onChanged(); + checkIsEmpty(); + checkForPadding(); + } + }); + } + + private void initLayoutManager() { + layoutManager = createLayoutManager(); + } + + protected A getAdapter() { + return adapter; + } + + protected LM getLayoutManager() { + return layoutManager; + } + + protected RecyclerView getRecyclerView() { + return recyclerView; + } + + public ViewGroup getContainer() { + return container; + } + + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int i) { + container.setPadding(container.getPaddingLeft(), container.getPaddingTop(), + container.getPaddingRight(), getLibraryFragment().getTotalAppBarScrollingRange() + i); + } + + private void checkIsEmpty() { + empty.setText(getEmptyMessage()); + empty.setVisibility(adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); + } + + @StringRes + protected int getEmptyMessage() { + return R.string.empty; + } + + @LayoutRes + protected int getLayoutRes() { + return R.layout.fragment_main_activity_recycler_view; + } + + protected abstract LM createLayoutManager(); + + @NonNull + protected abstract A createAdapter(); + + @Override + public void onDestroyView() { + super.onDestroyView(); + getLibraryFragment().removeOnAppBarOffsetChangedListener(this); + unbinder.unbind(); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsMainActivityFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsMainActivityFragment.java new file mode 100644 index 00000000..8d82a715 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsMainActivityFragment.java @@ -0,0 +1,52 @@ +package code.name.monkey.retromusic.ui.fragments.base; + +import android.os.Build; +import android.os.Bundle; +import android.view.View; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.ui.activities.MainActivity; +import code.name.monkey.retromusic.util.RetroUtil; + + +public abstract class AbsMainActivityFragment extends AbsMusicServiceFragment { + + public MainActivity getMainActivity() { + return (MainActivity) getActivity(); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + setHasOptionsMenu(true); + + getMainActivity().setNavigationbarColorAuto(); + getMainActivity().setLightNavigationBar(true); + getMainActivity().setTaskDescriptionColorAuto(); + getMainActivity().hideStatusBar(); + } + + + // WORKAROUND + public void setStatusbarColor(View view, int color) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + final View statusBar = view.findViewById(R.id.status_bar); + if (statusBar != null) { + RetroUtil.statusBarHeight(statusBar); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + statusBar.setBackgroundColor(ColorUtil.darkenColor(color)); + getMainActivity().setLightStatusbarAuto(color); + } else { + statusBar.setBackgroundColor(color); + } + } + } + } + + public void setStatusbarColorAuto(View view) { + // we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat + setStatusbarColor(view, ThemeStore.primaryColor(getContext())); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsMusicServiceFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsMusicServiceFragment.java new file mode 100644 index 00000000..5d8ee787 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsMusicServiceFragment.java @@ -0,0 +1,89 @@ +package code.name.monkey.retromusic.ui.fragments.base; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.view.View; + +import code.name.monkey.retromusic.interfaces.MusicServiceEventListener; + +import code.name.monkey.retromusic.ui.activities.base.AbsMusicServiceActivity; + +/** + * Created by hemanths on 18/08/17. + */ + +public class AbsMusicServiceFragment extends Fragment implements MusicServiceEventListener { + + private AbsMusicServiceActivity activity; + + + @Override + public void onAttach(Context context) { + super.onAttach(context); + try { + activity = (AbsMusicServiceActivity) context; + } catch (ClassCastException e) { + throw new RuntimeException(context.getClass().getSimpleName() + " must be an instance of " + AbsMusicServiceActivity.class.getSimpleName()); + } + } + + @Override + public void onDetach() { + super.onDetach(); + activity = null; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + activity.addMusicServiceEventListener(this); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + activity.removeMusicServiceEventListener(this); + } + + @Override + public void onPlayingMetaChanged() { + + } + + @Override + public void onServiceConnected() { + + } + + @Override + public void onServiceDisconnected() { + + } + + @Override + public void onQueueChanged() { + + } + + @Override + public void onPlayStateChanged() { + + } + + @Override + public void onRepeatModeChanged() { + + } + + @Override + public void onShuffleModeChanged() { + + } + + @Override + public void onMediaStoreChanged() { + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerControlsFragment.java new file mode 100644 index 00000000..d5a8d090 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerControlsFragment.java @@ -0,0 +1,23 @@ +package code.name.monkey.retromusic.ui.fragments.base; + +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; + +/** + * Created by hemanths on 24/09/17. + */ + +public abstract class AbsPlayerControlsFragment extends AbsMusicServiceFragment + implements MusicProgressViewUpdateHelper.Callback { + + protected abstract void show(); + + protected abstract void hide(); + + protected abstract void updateShuffleState(); + + protected abstract void updateRepeatState(); + + protected abstract void setUpProgressSlider(); + + public abstract void setDark(int color); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerFragment.java new file mode 100644 index 00000000..cd694d76 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerFragment.java @@ -0,0 +1,282 @@ +package code.name.monkey.retromusic.ui.fragments.base; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog; +import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog; +import code.name.monkey.retromusic.dialogs.DeleteSongsDialog; +import code.name.monkey.retromusic.dialogs.SleepTimerDialog; +import code.name.monkey.retromusic.dialogs.SongDetailDialog; +import code.name.monkey.retromusic.dialogs.SongShareDialog; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.interfaces.PaletteColorHolder; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.activities.tageditor.AbsTagEditorActivity; +import code.name.monkey.retromusic.ui.activities.tageditor.SongTagEditorActivity; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroUtil; + +public abstract class AbsPlayerFragment extends AbsMusicServiceFragment implements + Toolbar.OnMenuItemClickListener, PaletteColorHolder { + + public static final String TAG = AbsPlayerFragment.class.getSimpleName(); + private boolean isToolbarShown = true; + private Callbacks callbacks; + private AsyncTask updateIsFavoriteTask; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + try { + callbacks = (Callbacks) context; + } catch (ClassCastException e) { + throw new RuntimeException( + context.getClass().getSimpleName() + " must implement " + Callbacks.class + .getSimpleName()); + } + } + + @Override + public void onDetach() { + super.onDetach(); + callbacks = null; + } + + @SuppressWarnings("ConstantConditions") + @Override + public boolean onMenuItemClick(MenuItem item) { + final Song song = MusicPlayerRemote.getCurrentSong(); + switch (item.getItemId()) { + case R.id.action_toggle_favorite: + toggleFavorite(song); + return true; + case R.id.action_share: + if (getFragmentManager() != null) { + SongShareDialog.create(song).show(getFragmentManager(), "SHARE_SONG"); + } + return true; + case R.id.action_delete_from_device: + DeleteSongsDialog.create(song) + .show(getActivity().getSupportFragmentManager(), "DELETE_SONGS"); + return true; + case R.id.action_add_to_playlist: + if (getFragmentManager() != null) { + AddToPlaylistDialog.create(song).show(getFragmentManager(), "ADD_PLAYLIST"); + } + return true; + case R.id.action_clear_playing_queue: + MusicPlayerRemote.clearQueue(); + return true; + case R.id.action_save_playing_queue: + CreatePlaylistDialog.create(MusicPlayerRemote.getPlayingQueue()) + .show(getActivity().getSupportFragmentManager(), "ADD_TO_PLAYLIST"); + return true; + case R.id.action_tag_editor: + Intent intent = new Intent(getActivity(), SongTagEditorActivity.class); + intent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id); + startActivity(intent); + return true; + case R.id.action_details: + if (getFragmentManager() != null) { + SongDetailDialog.create(song).show(getFragmentManager(), "SONG_DETAIL"); + } + return true; + case R.id.action_go_to_album: + NavigationUtil.goToAlbum(getActivity(), song.albumId); + return true; + case R.id.action_go_to_artist: + NavigationUtil.goToArtist(getActivity(), song.artistId); + return true; + case R.id.now_playing: + NavigationUtil.goToPlayingQueue(getActivity()); + return true; + case R.id.action_show_lyrics: + NavigationUtil.goToLyrics(getActivity()); + return true; + case R.id.action_equalizer: + NavigationUtil.openEqualizer(getActivity()); + return true; + case R.id.action_sleep_timer: + new SleepTimerDialog().show(getFragmentManager(), TAG); + return true; + case R.id.action_set_as_ringtone: + MusicUtil.setRingtone(getActivity(), song.id); + return true; + case R.id.action_go_to_genre: + /*MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + Uri trackUri = ContentUris + .withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, song.id); + retriever.setDataSource(getActivity(), trackUri); + String genre = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE); + if (genre == null) { + genre = "Not Specified"; + }*/ + Toast.makeText(getContext(), "Soon", Toast.LENGTH_SHORT).show(); + return true; + } + return false; + } + + protected void toggleFavorite(Song song) { + MusicUtil.toggleFavorite(getActivity(), song); + } + + protected boolean isToolbarShown() { + return isToolbarShown; + } + + protected void setToolbarShown(boolean toolbarShown) { + isToolbarShown = toolbarShown; + } + + protected void showToolbar(@Nullable final View toolbar) { + if (toolbar == null) { + return; + } + setToolbarShown(true); + toolbar.setVisibility(View.VISIBLE); + toolbar.animate().alpha(1f).setDuration(PlayerAlbumCoverFragment.VISIBILITY_ANIM_DURATION); + } + + protected void hideToolbar(@Nullable final View toolbar) { + if (toolbar == null) { + return; + } + + setToolbarShown(false); + + toolbar.animate().alpha(0f).setDuration(PlayerAlbumCoverFragment.VISIBILITY_ANIM_DURATION) + .withEndAction(new Runnable() { + @Override + public void run() { + toolbar.setVisibility(View.GONE); + } + }); + } + + protected void toggleToolbar(@Nullable final View toolbar) { + if (isToolbarShown()) { + hideToolbar(toolbar); + } else { + showToolbar(toolbar); + } + } + + protected void checkToggleToolbar(@Nullable final View toolbar) { + if (toolbar != null && !isToolbarShown() && toolbar.getVisibility() != View.GONE) { + hideToolbar(toolbar); + } else if (toolbar != null && isToolbarShown() && toolbar.getVisibility() != View.VISIBLE) { + showToolbar(toolbar); + } + } + + public abstract void onShow(); + + public abstract void onHide(); + + public abstract boolean onBackPressed(); + + public abstract Toolbar getToolbar(); + + public abstract int toolbarIconColor(); + + @Override + public void onServiceConnected() { + updateIsFavorite(); + //updateLyrics(); + } + + @Override + public void onPlayingMetaChanged() { + updateIsFavorite(); + //updateLyrics(); + } + + @Override + public void onDestroyView() { + + if (updateIsFavoriteTask != null && !updateIsFavoriteTask.isCancelled()) { + updateIsFavoriteTask.cancel(true); + } + super.onDestroyView(); + + } + + @SuppressLint("StaticFieldLeak") + public void updateIsFavorite() { + if (updateIsFavoriteTask != null) { + updateIsFavoriteTask.cancel(false); + } + updateIsFavoriteTask = new AsyncTask() { + @Override + protected Boolean doInBackground(Song... params) { + Activity activity = getActivity(); + if (activity != null) { + return MusicUtil.isFavorite(getActivity(), params[0]); + } else { + cancel(false); + return null; + } + } + + @Override + protected void onPostExecute(Boolean isFavorite) { + Activity activity = getActivity(); + if (activity != null) { + int res = isFavorite ? R.drawable.ic_favorite_white_24dp + : R.drawable.ic_favorite_border_white_24dp; + Drawable drawable = RetroUtil.getTintedVectorDrawable(activity, res, toolbarIconColor()); + getToolbar().getMenu().findItem(R.id.action_toggle_favorite) + .setIcon(drawable) + .setTitle(isFavorite ? getString(R.string.action_remove_from_favorites) + : getString(R.string.action_add_to_favorites)); + } + } + }.execute(MusicPlayerRemote.getCurrentSong()); + } + + public Callbacks getCallbacks() { + return callbacks; + } + + protected void toggleStatusBar(ViewGroup viewGroup) { + if (!PreferenceUtil.getInstance(getContext()).getFullScreenMode()) { + RetroUtil.statusBarHeight(viewGroup); + } + } + + protected void toggleStatusBar(View viewGroup) { + if (!PreferenceUtil.getInstance(getContext()).getFullScreenMode()) { + RetroUtil.statusBarHeight(viewGroup); + } + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + view.setBackgroundColor(ThemeStore.primaryColor(getActivity())); + } + + public interface Callbacks { + + void onPaletteColorChanged(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/intro/NameFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/intro/NameFragment.java new file mode 100644 index 00000000..e29e1e25 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/intro/NameFragment.java @@ -0,0 +1,275 @@ +package code.name.monkey.retromusic.ui.fragments.intro; + +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.provider.MediaStore.Images.Media; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.Toast; + +import com.afollestad.materialdialogs.MaterialDialog.Builder; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.util.Compressor; +import code.name.monkey.retromusic.util.ImageUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.CircularImageView; +import code.name.monkey.retromusic.views.IconImageView; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +import static android.app.Activity.RESULT_OK; +import static code.name.monkey.retromusic.Constants.USER_BANNER; +import static code.name.monkey.retromusic.Constants.USER_PROFILE; + +public class NameFragment extends Fragment { + + private static final int PICK_IMAGE_REQUEST = 9002; + private static final int PICK_BANNER_REQUEST = 9003; + private static final int PROFILE_ICON_SIZE = 400; + @BindView(R.id.name) + EditText name; + @BindView(R.id.user_image) + CircularImageView userImage; + @BindView(R.id.image) + ImageView image; + @BindView(R.id.banner_select) + IconImageView imageView; + private Unbinder unbinder; + private CompositeDisposable disposable; + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + Bundle savedInstanceState) { + View view = LayoutInflater.from(getActivity()) + .inflate(R.layout.fragment_name, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + //noinspection ConstantConditions + name.setText(PreferenceUtil.getInstance(getActivity()).getUserName()); + if (!PreferenceUtil.getInstance(getActivity()).getProfileImage().isEmpty()) { + loadImageFromStorage(PreferenceUtil.getInstance(getActivity()).getProfileImage()); + } + if (!PreferenceUtil.getInstance(getActivity()).getBannerImage().isEmpty()) { + loadBannerFromStorage(PreferenceUtil.getInstance(getActivity()).getBannerImage()); + imageView.setImageResource(R.drawable.ic_close_white_24dp); + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + disposable = new CompositeDisposable(); + } + + @OnClick({R.id.next, R.id.banner_select}) + void next(View view) { + switch (view.getId()) { + case R.id.banner_select: + showBannerOptions(); + break; + case R.id.next: + String nameString = name.getText().toString().trim(); + if (TextUtils.isEmpty(nameString)) { + Toast.makeText(getActivity(), "Umm name is empty", Toast.LENGTH_SHORT).show(); + return; + } + //noinspection ConstantConditions + PreferenceUtil.getInstance(getActivity()).setUserName(nameString); + getActivity().setResult(RESULT_OK); + //((UserInfoActivity) getActivity()).setFragment(new ChooseThemeFragment(), true); + getActivity().finish(); + break; + } + } + + private void showBannerOptions() { + //noinspection ConstantConditions + new Builder(getContext()) + .title(R.string.select_banner_photo) + .items(Arrays.asList(getString(R.string.new_banner_photo), + getString(R.string.remove_banner_photo))) + .itemsCallback((dialog, itemView, position, text) -> { + switch (position) { + case 0: + selectBannerImage(); + break; + case 1: + PreferenceUtil.getInstance(getContext()).setBannerImagePath(""); + break; + } + }).show(); + } + + private void selectBannerImage() { + //noinspection ConstantConditions + if (PreferenceUtil.getInstance(getActivity()).getBannerImage().isEmpty()) { + Intent pickImageIntent = new Intent(Intent.ACTION_PICK, + Media.EXTERNAL_CONTENT_URI); + pickImageIntent.setType("image/*"); + pickImageIntent.putExtra("crop", "true"); + pickImageIntent.putExtra("outputX", 1290); + pickImageIntent.putExtra("outputY", 720); + pickImageIntent.putExtra("aspectX", 16); + pickImageIntent.putExtra("aspectY", 9); + pickImageIntent.putExtra("scale", true); + //intent.setAction(Intent.ACTION_GET_CONTENT); + startActivityForResult(Intent.createChooser(pickImageIntent, + "Select Picture"), PICK_BANNER_REQUEST); + } else { + PreferenceUtil.getInstance(getContext()).setBannerImagePath(""); + image.setImageResource(android.R.color.transparent); + imageView.setImageResource(R.drawable.ic_edit_white_24dp); + } + } + + @OnClick(R.id.image) + public void onViewClicked() { + //noinspection ConstantConditions + new Builder(getContext()) + .title("Set a profile photo") + .items(Arrays.asList(getString(R.string.new_profile_photo), + getString(R.string.remove_profile_photo))) + .itemsCallback((dialog, itemView, position, text) -> { + switch (position) { + case 0: + pickNewPhoto(); + break; + case 1: + PreferenceUtil.getInstance(getContext()).saveProfileImage(""); + break; + } + }).show(); + } + + private void pickNewPhoto() { + Intent pickImageIntent = new Intent(Intent.ACTION_PICK, + android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + pickImageIntent.setType("image/*"); + pickImageIntent.putExtra("crop", "true"); + pickImageIntent.putExtra("outputX", 512); + pickImageIntent.putExtra("outputY", 512); + pickImageIntent.putExtra("aspectX", 1); + pickImageIntent.putExtra("aspectY", 1); + pickImageIntent.putExtra("scale", true); + startActivityForResult(Intent.createChooser(pickImageIntent, "Select Picture"), + PICK_IMAGE_REQUEST); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && + data.getData() != null) { + Uri uri = data.getData(); + try { + Bitmap bitmap = ImageUtil.getResizedBitmap(Media.getBitmap(getActivity() + .getContentResolver(), uri), PROFILE_ICON_SIZE); + String profileImagePath = saveToInternalStorage(bitmap, USER_PROFILE); + PreferenceUtil.getInstance(getActivity()).saveProfileImage(profileImagePath); + loadImageFromStorage(profileImagePath); + + } catch (IOException e) { + e.printStackTrace(); + } + } + if (requestCode == PICK_BANNER_REQUEST && resultCode == RESULT_OK && data != null && + data.getData() != null) { + Uri uri = data.getData(); + try { + Bitmap bitmap = Media.getBitmap(getActivity().getContentResolver(), uri); + String profileImagePath = saveToInternalStorage(bitmap, USER_BANNER); + PreferenceUtil.getInstance(getActivity()).setBannerImagePath(profileImagePath); + loadBannerFromStorage(profileImagePath); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private void loadBannerFromStorage(String profileImagePath) { + disposable.add(new Compressor(getActivity()) + .setQuality(100) + .setCompressFormat(Bitmap.CompressFormat.WEBP) + .compressToBitmapAsFlowable(new File(profileImagePath, USER_BANNER)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(bitmap -> { + image.setImageBitmap(bitmap); + })); + } + + private void loadImageFromStorage(String path) { + disposable.add(new Compressor(getActivity()) + .setMaxHeight(300) + .setMaxWidth(300) + .setQuality(75) + .setCompressFormat(Bitmap.CompressFormat.WEBP) + .compressToBitmapAsFlowable(new File(path, USER_PROFILE)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(bitmap -> { + userImage.setImageBitmap(bitmap); + })); + } + + private String saveToInternalStorage(Bitmap bitmapImage, String userBanner) { + ContextWrapper cw = new ContextWrapper(getActivity()); + // path to /data/data/yourapp/app_data/imageDir + File directory = cw.getDir("imageDir", Context.MODE_PRIVATE); + // Create imageDir + File mypath = new File(directory, userBanner); + + FileOutputStream fos = null; + try { + fos = new FileOutputStream(mypath); + // Use the compress method on the BitMap object to write image to the OutputStream + bitmapImage.compress(Bitmap.CompressFormat.WEBP, 100, fos); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (fos != null) { + fos.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return directory.getAbsolutePath(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/AlbumsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/AlbumsFragment.java new file mode 100644 index 00000000..ccdf51f4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/AlbumsFragment.java @@ -0,0 +1,168 @@ +package code.name.monkey.retromusic.ui.fragments.mainactivity; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.GridLayoutManager; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.mvp.contract.AlbumContract; +import code.name.monkey.retromusic.mvp.presenter.AlbumPresenter; +import code.name.monkey.retromusic.ui.adapter.album.AlbumAdapter; +import code.name.monkey.retromusic.ui.fragments.base.AbsLibraryPagerRecyclerViewCustomGridSizeFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; + +public class AlbumsFragment extends + AbsLibraryPagerRecyclerViewCustomGridSizeFragment implements + AlbumContract.AlbumView { + + public static final String TAG = AlbumsFragment.class.getSimpleName(); + + private AlbumPresenter presenter; + + public static AlbumsFragment newInstance() { + Bundle args = new Bundle(); + AlbumsFragment fragment = new AlbumsFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected GridLayoutManager createLayoutManager() { + return new GridLayoutManager(getActivity(), getGridSize()); + } + + @NonNull + @Override + protected AlbumAdapter createAdapter() { + int itemLayoutRes = getItemLayoutRes(); + notifyLayoutResChanged(itemLayoutRes); + if (itemLayoutRes != R.layout.item_list) { + itemLayoutRes = PreferenceUtil.getInstance(getContext()).getAlbumGridStyle(getContext()); + } + ArrayList dataSet = + getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet(); + return new AlbumAdapter(getLibraryFragment().getMainActivity(), dataSet, itemLayoutRes, + loadUsePalette(), getLibraryFragment()); + } + + @Override + protected int getEmptyMessage() { + return R.string.no_albums; + } + + @Override + public boolean loadUsePalette() { + return PreferenceUtil.getInstance(getActivity()).albumColoredFooters(); + } + + @Override + protected void setUsePalette(boolean usePalette) { + getAdapter().usePalette(usePalette); + } + + @Override + protected void setGridSize(int gridSize) { + getLayoutManager().setSpanCount(gridSize); + getAdapter().notifyDataSetChanged(); + } + + @Override + protected void setSortOrder(String sortOrder) { + presenter.loadAlbums(); + } + + @Override + protected String loadSortOrder() { + return PreferenceUtil.getInstance(getActivity()).getAlbumSortOrder(); + } + + @Override + protected void saveSortOrder(String sortOrder) { + PreferenceUtil.getInstance(getActivity()).setAlbumSortOrder(sortOrder); + } + + @Override + protected int loadGridSize() { + return PreferenceUtil.getInstance(getActivity()).getAlbumGridSize(getActivity()); + } + + @Override + protected void saveGridSize(int gridSize) { + PreferenceUtil.getInstance(getActivity()).setAlbumGridSize(gridSize); + } + + @Override + protected int loadGridSizeLand() { + return PreferenceUtil.getInstance(getActivity()).getAlbumGridSizeLand(getActivity()); + } + + @Override + protected void saveGridSizeLand(int gridSize) { + PreferenceUtil.getInstance(getActivity()).setAlbumGridSizeLand(gridSize); + } + + @Override + protected void saveUsePalette(boolean usePalette) { + PreferenceUtil.getInstance(getActivity()).setAlbumColoredFooters(usePalette); + } + + @Override + public void onMediaStoreChanged() { + presenter.loadAlbums(); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + presenter = new AlbumPresenter(this); + } + + @Override + public void setMenuVisibility(boolean menuVisible) { + super.setMenuVisibility(menuVisible); + if (menuVisible) { + getLibraryFragment().getToolbar().setTitle( + PreferenceUtil.getInstance(getContext()).tabTitles() ? R.string.library + : R.string.albums); + } + } + + @Override + public void onResume() { + super.onResume(); + getLibraryFragment().getToolbar().setTitle( + PreferenceUtil.getInstance(getContext()).tabTitles() ? R.string.library : R.string.albums); + if (getAdapter().getDataSet().isEmpty()) { + presenter.subscribe(); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + presenter.unsubscribe(); + } + + @Override + public void loading() { + } + + @Override + public void showEmptyView() { + getAdapter().swapDataSet(new ArrayList<>()); + } + + @Override + public void completed() { + } + + @Override + public void showData(ArrayList albums) { + getAdapter().swapDataSet(albums); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/ArtistsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/ArtistsFragment.java new file mode 100644 index 00000000..82069802 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/ArtistsFragment.java @@ -0,0 +1,173 @@ +package code.name.monkey.retromusic.ui.fragments.mainactivity; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.GridLayoutManager; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.mvp.contract.ArtistContract; +import code.name.monkey.retromusic.mvp.presenter.ArtistPresenter; +import code.name.monkey.retromusic.ui.adapter.artist.ArtistAdapter; +import code.name.monkey.retromusic.ui.fragments.base.AbsLibraryPagerRecyclerViewCustomGridSizeFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; + +public class ArtistsFragment extends + AbsLibraryPagerRecyclerViewCustomGridSizeFragment implements + ArtistContract.ArtistView { + + public static final String TAG = ArtistsFragment.class.getSimpleName(); + private ArtistPresenter presenter; + + public static ArtistsFragment newInstance() { + + Bundle args = new Bundle(); + + ArtistsFragment fragment = new ArtistsFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + presenter = new ArtistPresenter(this); + } + + @NonNull + @Override + protected GridLayoutManager createLayoutManager() { + return new GridLayoutManager(getActivity(), getGridSize()); + } + + @NonNull + @Override + protected ArtistAdapter createAdapter() { + int itemLayoutRes = getItemLayoutRes(); + notifyLayoutResChanged(itemLayoutRes); + if (itemLayoutRes != R.layout.item_list) { + itemLayoutRes = PreferenceUtil.getInstance(getContext()).getArtistGridStyle(getContext()); + } + ArrayList dataSet = + getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet(); + return new ArtistAdapter(getLibraryFragment().getMainActivity(), dataSet, itemLayoutRes, + loadUsePalette(), getLibraryFragment()); + } + + @Override + protected int getEmptyMessage() { + return R.string.no_artists; + } + + @Override + public void onMediaStoreChanged() { + presenter.loadArtists(); + } + + @Override + protected int loadGridSize() { + return PreferenceUtil.getInstance(getActivity()).getArtistGridSize(getActivity()); + } + + @Override + protected void saveGridSize(int gridSize) { + PreferenceUtil.getInstance(getActivity()).setArtistGridSize(gridSize); + } + + @Override + protected int loadGridSizeLand() { + return PreferenceUtil.getInstance(getActivity()).getArtistGridSizeLand(getActivity()); + } + + @Override + protected void saveGridSizeLand(int gridSize) { + PreferenceUtil.getInstance(getActivity()).setArtistGridSizeLand(gridSize); + } + + @Override + protected void saveUsePalette(boolean usePalette) { + PreferenceUtil.getInstance(getActivity()).setArtistColoredFooters(usePalette); + } + + @Override + public boolean loadUsePalette() { + return PreferenceUtil.getInstance(getActivity()).artistColoredFooters(); + } + + @Override + protected void setUsePalette(boolean usePalette) { + getAdapter().usePalette(usePalette); + } + + @Override + protected void setGridSize(int gridSize) { + getLayoutManager().setSpanCount(gridSize); + getAdapter().notifyDataSetChanged(); + } + + + @Override + protected String loadSortOrder() { + return PreferenceUtil.getInstance(getActivity()).getArtistSortOrder(); + } + + @Override + protected void saveSortOrder(String sortOrder) { + PreferenceUtil.getInstance(getActivity()).setArtistSortOrder(sortOrder); + } + + @Override + protected void setSortOrder(String sortOrder) { + presenter.loadArtists(); + } + + + @Override + public void setMenuVisibility(boolean menuVisible) { + super.setMenuVisibility(menuVisible); + if (menuVisible) { + getLibraryFragment().getToolbar().setTitle( + PreferenceUtil.getInstance(getContext()).tabTitles() ? R.string.library + : R.string.artists); + } + } + + @Override + public void onResume() { + super.onResume(); + getLibraryFragment().getToolbar().setTitle( + PreferenceUtil.getInstance(getContext()).tabTitles() ? R.string.library : R.string.artists); + if (getAdapter().getDataSet().isEmpty()) { + presenter.subscribe(); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + presenter.unsubscribe(); + } + + @Override + public void loading() { + } + + @Override + public void showEmptyView() { + getAdapter().swapDataSet(new ArrayList<>()); + } + + @Override + public void completed() { + + } + + @Override + public void showData(ArrayList artists) { + getAdapter().swapDataSet(artists); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/GenreFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/GenreFragment.java new file mode 100644 index 00000000..9925b60f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/GenreFragment.java @@ -0,0 +1,112 @@ +package code.name.monkey.retromusic.ui.fragments.mainactivity; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.view.Menu; +import android.view.MenuInflater; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.mvp.contract.GenreContract; +import code.name.monkey.retromusic.mvp.presenter.GenrePresenter; +import code.name.monkey.retromusic.ui.adapter.GenreAdapter; +import code.name.monkey.retromusic.ui.fragments.base.AbsLibraryPagerRecyclerViewFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; +import java.util.ArrayList; + +public class GenreFragment extends + AbsLibraryPagerRecyclerViewFragment implements + GenreContract.GenreView { + + private GenrePresenter mPresenter; + + public static GenreFragment newInstance() { + Bundle args = new Bundle(); + GenreFragment fragment = new GenreFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + mPresenter = new GenrePresenter(this); + } + + @Override + public void setMenuVisibility(boolean menuVisible) { + super.setMenuVisibility(menuVisible); + if (menuVisible) { + getLibraryFragment().getToolbar().setTitle( + PreferenceUtil.getInstance(getContext()).tabTitles() ? R.string.library + : R.string.genres); + } + } + + @Override + public void onResume() { + super.onResume(); + getLibraryFragment().getToolbar().setTitle( + PreferenceUtil.getInstance(getContext()).tabTitles() ? R.string.library : R.string.genres); + if (getAdapter().getDataSet().isEmpty()) { + mPresenter.subscribe(); + } + } + + + @Override + public void onDestroy() { + super.onDestroy(); + mPresenter.unsubscribe(); + } + + @NonNull + @Override + protected LinearLayoutManager createLayoutManager() { + return new LinearLayoutManager(getActivity()); + } + + @NonNull + @Override + protected GenreAdapter createAdapter() { + ArrayList dataSet = + getAdapter() == null ? new ArrayList() : getAdapter().getDataSet(); + return new GenreAdapter(getLibraryFragment().getMainActivity(), dataSet, R.layout.item_list); + } + + @Override + public void loading() { + + } + + @Override + public void showData(ArrayList songs) { + getAdapter().swapDataSet(songs); + } + + @Override + public void showEmptyView() { + getAdapter().swapDataSet(new ArrayList()); + } + + @Override + public void completed() { + + } + + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + menu.removeItem(R.id.action_sort_order); + menu.removeItem(R.id.action_grid_size); + menu.removeItem(R.id.action_new_playlist); + } + + @Override + protected int getEmptyMessage() { + return R.string.no_genres; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/LibraryFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/LibraryFragment.java new file mode 100644 index 00000000..77e94be9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/LibraryFragment.java @@ -0,0 +1,458 @@ +package code.name.monkey.retromusic.ui.fragments.mainactivity; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.AppBarLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.SubMenu; +import android.view.View; +import android.view.ViewGroup; + +import com.afollestad.materialcab.MaterialCab; + +import java.util.Objects; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.common.ATHToolbarActivity; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog; +import code.name.monkey.retromusic.dialogs.SleepTimerDialog; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.SortOrder; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks; +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.ui.activities.SearchActivity; +import code.name.monkey.retromusic.ui.activities.SettingsActivity; +import code.name.monkey.retromusic.ui.fragments.base.AbsLibraryPagerRecyclerViewCustomGridSizeFragment; +import code.name.monkey.retromusic.ui.fragments.base.AbsMainActivityFragment; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.util.RetroColorUtil; +import code.name.monkey.retromusic.util.RetroUtil; +import code.name.monkey.retromusic.views.SansFontCollapsingToolbarLayout; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +public class LibraryFragment extends AbsMainActivityFragment implements CabHolder, + MainActivityFragmentCallbacks { + + private static final String TAG = "LibraryFragment"; + private static final String CURRENT_TAB_ID = "current_tab_id"; + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.appbar) + AppBarLayout appbar; + @BindView(R.id.collapsing_toolbar) + SansFontCollapsingToolbarLayout collapsingToolbar; + + private Unbinder unBinder; + private MaterialCab cab; + private FragmentManager fragmentManager; + + public static Fragment newInstance(int tab) { + Bundle args = new Bundle(); + args.putInt(CURRENT_TAB_ID, tab); + LibraryFragment fragment = new LibraryFragment(); + fragment.setArguments(args); + return fragment; + } + + public SansFontCollapsingToolbarLayout getToolbar() { + return collapsingToolbar; + } + + public void addOnAppBarOffsetChangedListener( + AppBarLayout.OnOffsetChangedListener onOffsetChangedListener) { + appbar.addOnOffsetChangedListener(onOffsetChangedListener); + } + + public void removeOnAppBarOffsetChangedListener( + AppBarLayout.OnOffsetChangedListener onOffsetChangedListener) { + appbar.removeOnOffsetChangedListener(onOffsetChangedListener); + } + + public int getTotalAppBarScrollingRange() { + return appbar.getTotalScrollRange(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_library, container, false); + unBinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + setStatusbarColorAuto(view); + + getMainActivity().setBottomBarVisibility(View.VISIBLE); + setupToolbar(); + if (getArguments() == null) { + selectedFragment(SongsFragment.newInstance()); + return; + } + switch (getArguments().getInt(CURRENT_TAB_ID)) { + default: + case R.id.action_song: + selectedFragment(SongsFragment.newInstance()); + break; + case R.id.action_album: + selectedFragment(AlbumsFragment.newInstance()); + break; + case R.id.action_artist: + selectedFragment(ArtistsFragment.newInstance()); + break; + case R.id.action_playlist: + selectedFragment(PlaylistsFragment.newInstance()); + break; + } + } + + private void setupToolbar() { + //noinspection ConstantConditions + int primaryColor = ThemeStore.primaryColor(getContext()); + appbar.setBackgroundColor(primaryColor); + toolbar.setBackgroundColor(primaryColor); + toolbar.setTitle(R.string.library); + appbar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> + getMainActivity().setLightStatusbar(!ATHUtil.isWindowBackgroundDark(getContext()))); + Objects.requireNonNull(getActivity()).setTitle(R.string.app_name); + getMainActivity().setSupportActionBar(toolbar); + } + + public Fragment getCurrentFragment() { + if (fragmentManager == null) { + return SongsFragment.newInstance(); + } + return fragmentManager.findFragmentByTag(LibraryFragment.TAG); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unBinder.unbind(); + } + + @Override + public boolean handleBackPress() { + if (cab != null && cab.isActive()) { + cab.finish(); + return true; + } + return false; + } + + public void selectedFragment(Fragment fragment) { + fragmentManager = getChildFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + + fragmentTransaction + .replace(R.id.fragment_container, fragment, TAG) + .commit(); + } + + @NonNull + @Override + public MaterialCab openCab(int menuRes, MaterialCab.Callback callback) { + if (cab != null && cab.isActive()) { + cab.finish(); + } + //noinspection ConstantConditions + cab = new MaterialCab(getMainActivity(), R.id.cab_stub) + .setMenu(menuRes) + .setCloseDrawableRes(R.drawable.ic_close_white_24dp) + .setBackgroundColor( + RetroColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(getActivity()))) + .start(callback); + return cab; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.menu_main, menu); + + Fragment currentFragment = getCurrentFragment(); + if (currentFragment instanceof AbsLibraryPagerRecyclerViewCustomGridSizeFragment + && currentFragment.isAdded()) { + AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment = (AbsLibraryPagerRecyclerViewCustomGridSizeFragment) currentFragment; + + MenuItem gridSizeItem = menu.findItem(R.id.action_grid_size); + if (RetroUtil.isLandscape(getResources())) { + gridSizeItem.setTitle(R.string.action_grid_size_land); + } + setUpGridSizeMenu(fragment, gridSizeItem.getSubMenu()); + + setUpSortOrderMenu(fragment, menu.findItem(R.id.action_sort_order).getSubMenu()); + + } else { + menu.add(0, R.id.action_new_playlist, 0, R.string.new_playlist_title); + menu.removeItem(R.id.action_grid_size); + } + Activity activity = getActivity(); + if (activity == null) { + return; + } + ToolbarContentTintHelper.handleOnCreateOptionsMenu(getActivity(), toolbar, menu, + ATHToolbarActivity.getToolbarBackgroundColor(toolbar)); + } + + private void setUpSortOrderMenu( + @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, + @NonNull SubMenu sortOrderMenu) { + String currentSortOrder = fragment.getSortOrder(); + sortOrderMenu.clear(); + + if (fragment instanceof AlbumsFragment) { + sortOrderMenu.add(0, R.id.action_album_sort_order_asc, 0, R.string.sort_order_a_z) + .setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_A_Z)); + sortOrderMenu.add(0, R.id.action_album_sort_order_desc, 1, R.string.sort_order_z_a) + .setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_Z_A)); + sortOrderMenu.add(0, R.id.action_album_sort_order_artist, 2, R.string.sort_order_artist) + .setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_ARTIST)); + sortOrderMenu.add(0, R.id.action_album_sort_order_year, 3, R.string.sort_order_year) + .setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_YEAR)); + } else if (fragment instanceof ArtistsFragment) { + sortOrderMenu.add(0, R.id.action_artist_sort_order_asc, 0, R.string.sort_order_a_z) + .setChecked(currentSortOrder.equals(SortOrder.ArtistSortOrder.ARTIST_A_Z)); + sortOrderMenu.add(0, R.id.action_artist_sort_order_desc, 1, R.string.sort_order_z_a) + .setChecked(currentSortOrder.equals(SortOrder.ArtistSortOrder.ARTIST_Z_A)); + } else if (fragment instanceof SongsFragment) { + sortOrderMenu.add(0, R.id.action_song_sort_order_asc, 0, R.string.sort_order_a_z) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_A_Z)); + sortOrderMenu.add(0, R.id.action_song_sort_order_desc, 1, R.string.sort_order_z_a) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_Z_A)); + sortOrderMenu.add(0, R.id.action_song_sort_order_artist, 2, R.string.sort_order_artist) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_ARTIST)); + sortOrderMenu.add(0, R.id.action_song_sort_order_album, 3, R.string.sort_order_album) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_ALBUM)); + sortOrderMenu.add(0, R.id.action_song_sort_order_year, 4, R.string.sort_order_year) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_YEAR)); + sortOrderMenu.add(0, R.id.action_song_sort_order_date, 4, R.string.sort_order_date) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_DATE)); + } + + sortOrderMenu.setGroupCheckable(0, true, true); + } + + private boolean handleSortOrderMenuItem( + @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, @NonNull MenuItem item) { + String sortOrder = null; + if (fragment instanceof AlbumsFragment) { + switch (item.getItemId()) { + case R.id.action_album_sort_order_asc: + sortOrder = SortOrder.AlbumSortOrder.ALBUM_A_Z; + break; + case R.id.action_album_sort_order_desc: + sortOrder = SortOrder.AlbumSortOrder.ALBUM_Z_A; + break; + case R.id.action_album_sort_order_artist: + sortOrder = SortOrder.AlbumSortOrder.ALBUM_ARTIST; + break; + case R.id.action_album_sort_order_year: + sortOrder = SortOrder.AlbumSortOrder.ALBUM_YEAR; + break; + } + } else if (fragment instanceof ArtistsFragment) { + switch (item.getItemId()) { + case R.id.action_artist_sort_order_asc: + sortOrder = SortOrder.ArtistSortOrder.ARTIST_A_Z; + break; + case R.id.action_artist_sort_order_desc: + sortOrder = SortOrder.ArtistSortOrder.ARTIST_Z_A; + break; + } + } else if (fragment instanceof SongsFragment) { + switch (item.getItemId()) { + case R.id.action_song_sort_order_asc: + sortOrder = SortOrder.SongSortOrder.SONG_A_Z; + break; + case R.id.action_song_sort_order_desc: + sortOrder = SortOrder.SongSortOrder.SONG_Z_A; + break; + case R.id.action_song_sort_order_artist: + sortOrder = SortOrder.SongSortOrder.SONG_ARTIST; + break; + case R.id.action_song_sort_order_album: + sortOrder = SortOrder.SongSortOrder.SONG_ALBUM; + break; + case R.id.action_song_sort_order_year: + sortOrder = SortOrder.SongSortOrder.SONG_YEAR; + break; + case R.id.action_song_sort_order_date: + sortOrder = SortOrder.SongSortOrder.SONG_DATE; + break; + } + } + + if (sortOrder != null) { + item.setChecked(true); + fragment.setAndSaveSortOrder(sortOrder); + return true; + } + + return false; + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + Activity activity = getActivity(); + if (activity == null) { + return; + } + ToolbarContentTintHelper.handleOnPrepareOptionsMenu(activity, toolbar); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + //if (pager == null) return false; + Fragment currentFragment = getCurrentFragment(); + if (currentFragment instanceof AbsLibraryPagerRecyclerViewCustomGridSizeFragment) { + AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment = (AbsLibraryPagerRecyclerViewCustomGridSizeFragment) currentFragment; + if (handleGridSizeMenuItem(fragment, item)) { + return true; + } + if (handleSortOrderMenuItem(fragment, item)) { + return true; + } + } + int id = item.getItemId(); + switch (id) { + case R.id.action_new_playlist: + CreatePlaylistDialog.create().show(getChildFragmentManager(), "CREATE_PLAYLIST"); + return true; + case R.id.action_shuffle_all: + //noinspection ConstantConditions + SongLoader.getAllSongs(getContext()).subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(songs -> MusicPlayerRemote.openAndShuffleQueue(songs, true)); + return true; + case R.id.action_search: + startActivity(new Intent(getActivity(), SearchActivity.class)); + return true; + case R.id.action_equalizer: + //noinspection ConstantConditions + NavigationUtil.openEqualizer(getActivity()); + return true; + case R.id.action_sleep_timer: + if (getFragmentManager() != null) { + new SleepTimerDialog().show(getFragmentManager(), TAG); + } + return true; + case R.id.action_settings: + startActivity(new Intent(getContext(), SettingsActivity.class)); + break; + } + return super.onOptionsItemSelected(item); + } + + private void setUpGridSizeMenu( + @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, + @NonNull SubMenu gridSizeMenu) { + switch (fragment.getGridSize()) { + case 1: + gridSizeMenu.findItem(R.id.action_grid_size_1).setChecked(true); + break; + case 2: + gridSizeMenu.findItem(R.id.action_grid_size_2).setChecked(true); + break; + case 3: + gridSizeMenu.findItem(R.id.action_grid_size_3).setChecked(true); + break; + case 4: + gridSizeMenu.findItem(R.id.action_grid_size_4).setChecked(true); + break; + case 5: + gridSizeMenu.findItem(R.id.action_grid_size_5).setChecked(true); + break; + case 6: + gridSizeMenu.findItem(R.id.action_grid_size_6).setChecked(true); + break; + case 7: + gridSizeMenu.findItem(R.id.action_grid_size_7).setChecked(true); + break; + case 8: + gridSizeMenu.findItem(R.id.action_grid_size_8).setChecked(true); + break; + } + int maxGridSize = fragment.getMaxGridSize(); + if (maxGridSize < 8) { + gridSizeMenu.findItem(R.id.action_grid_size_8).setVisible(false); + } + if (maxGridSize < 7) { + gridSizeMenu.findItem(R.id.action_grid_size_7).setVisible(false); + } + if (maxGridSize < 6) { + gridSizeMenu.findItem(R.id.action_grid_size_6).setVisible(false); + } + if (maxGridSize < 5) { + gridSizeMenu.findItem(R.id.action_grid_size_5).setVisible(false); + } + if (maxGridSize < 4) { + gridSizeMenu.findItem(R.id.action_grid_size_4).setVisible(false); + } + if (maxGridSize < 3) { + gridSizeMenu.findItem(R.id.action_grid_size_3).setVisible(false); + } + } + + + private boolean handleGridSizeMenuItem( + @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, @NonNull MenuItem item) { + int gridSize = 0; + switch (item.getItemId()) { + case R.id.action_grid_size_1: + gridSize = 1; + break; + case R.id.action_grid_size_2: + gridSize = 2; + break; + case R.id.action_grid_size_3: + gridSize = 3; + break; + case R.id.action_grid_size_4: + gridSize = 4; + break; + case R.id.action_grid_size_5: + gridSize = 5; + break; + case R.id.action_grid_size_6: + gridSize = 6; + break; + case R.id.action_grid_size_7: + gridSize = 7; + break; + case R.id.action_grid_size_8: + gridSize = 8; + break; + } + + if (gridSize > 0) { + item.setChecked(true); + fragment.setAndSaveGridSize(gridSize); + return true; + } + return false; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/PlaylistsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/PlaylistsFragment.java new file mode 100644 index 00000000..2850ed94 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/PlaylistsFragment.java @@ -0,0 +1,120 @@ +package code.name.monkey.retromusic.ui.fragments.mainactivity; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.View; + +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.mvp.contract.PlaylistContract; +import code.name.monkey.retromusic.mvp.presenter.PlaylistPresenter; +import code.name.monkey.retromusic.ui.adapter.playlist.PlaylistAdapter; +import code.name.monkey.retromusic.ui.fragments.base.AbsLibraryPagerRecyclerViewFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; + + +public class PlaylistsFragment extends AbsLibraryPagerRecyclerViewFragment implements + PlaylistContract.PlaylistView { + + private PlaylistPresenter presenter; + + public static PlaylistsFragment newInstance() { + Bundle args = new Bundle(); + PlaylistsFragment fragment = new PlaylistsFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + presenter = new PlaylistPresenter(this); + } + + @Override + protected LinearLayoutManager createLayoutManager() { + return new LinearLayoutManager(getActivity()); + } + + @NonNull + @Override + protected PlaylistAdapter createAdapter() { + return new PlaylistAdapter(getLibraryFragment().getMainActivity(), new ArrayList<>(), + R.layout.item_list, getLibraryFragment()); + } + + @Override + public void setMenuVisibility(boolean menuVisible) { + super.setMenuVisibility(menuVisible); + if (menuVisible) { + getLibraryFragment().getToolbar().setTitle(PreferenceUtil.getInstance(getContext()).tabTitles() ? R.string.library : R.string.playlists); + } + } + + @Override + public void onResume() { + super.onResume(); + getLibraryFragment().getToolbar().setTitle(PreferenceUtil.getInstance(getContext()).tabTitles() ? R.string.library : R.string.playlists); + if (getAdapter().getDataSet().isEmpty()) { + presenter.subscribe(); + } + } + + @Override + public void onDestroy() { + presenter.unsubscribe(); + super.onDestroy(); + } + + @Override + public void onMediaStoreChanged() { + super.onMediaStoreChanged(); + presenter.loadPlaylists(); + } + + @Override + public void loading() { + + } + + @Override + public void showEmptyView() { + getAdapter().swapDataSet(new ArrayList<>()); + } + + @Override + public void completed() { + + } + + @Override + public void showData(ArrayList playlists) { + getAdapter().swapDataSet(playlists); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + menu.removeItem(R.id.action_shuffle_all); + menu.removeItem(R.id.action_sort_order); + menu.removeItem(R.id.action_grid_size); + } + + @Override + protected int getEmptyMessage() { + return R.string.no_playlists; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/SongsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/SongsFragment.java new file mode 100644 index 00000000..c2fac873 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/SongsFragment.java @@ -0,0 +1,178 @@ +package code.name.monkey.retromusic.ui.fragments.mainactivity; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.GridLayoutManager; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.mvp.contract.SongContract; +import code.name.monkey.retromusic.mvp.presenter.SongPresenter; +import code.name.monkey.retromusic.ui.adapter.song.ShuffleButtonSongAdapter; +import code.name.monkey.retromusic.ui.adapter.song.SongAdapter; +import code.name.monkey.retromusic.ui.fragments.base.AbsLibraryPagerRecyclerViewCustomGridSizeFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; + +import java.util.ArrayList; + +@SuppressWarnings("ConstantConditions") +public class SongsFragment extends + AbsLibraryPagerRecyclerViewCustomGridSizeFragment implements + SongContract.SongView { + + private static final String TAG = "Songs"; + private SongPresenter presenter; + + public SongsFragment() { + // Required empty public constructor + } + + public static SongsFragment newInstance() { + Bundle args = new Bundle(); + SongsFragment fragment = new SongsFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + presenter = new SongPresenter(this); + } + + @NonNull + @Override + protected GridLayoutManager createLayoutManager() { + return new GridLayoutManager(getActivity(), getGridSize()); + } + + @Override + protected int getEmptyMessage() { + return R.string.no_songs; + } + + @NonNull + @Override + protected SongAdapter createAdapter() { + int itemLayoutRes = getItemLayoutRes(); + notifyLayoutResChanged(itemLayoutRes); + boolean usePalette = loadUsePalette(); + ArrayList dataSet = + getAdapter() == null ? new ArrayList() : getAdapter().getDataSet(); + + if (getGridSize() <= getMaxGridSizeForList()) { + return new ShuffleButtonSongAdapter(getLibraryFragment().getMainActivity(), dataSet, + itemLayoutRes, usePalette, getLibraryFragment()); + } + return new SongAdapter(getLibraryFragment().getMainActivity(), dataSet, itemLayoutRes, + usePalette, getLibraryFragment()); + } + + @Override + public void onMediaStoreChanged() { + presenter.loadSongs(); + } + + @Override + protected int loadGridSize() { + return PreferenceUtil.getInstance(getActivity()).getSongGridSize(getActivity()); + } + + @Override + protected void saveGridSize(int gridSize) { + PreferenceUtil.getInstance(getActivity()).setSongGridSize(gridSize); + } + + @Override + protected int loadGridSizeLand() { + return PreferenceUtil.getInstance(getActivity()).getSongGridSizeLand(getActivity()); + } + + @Override + protected void saveGridSizeLand(int gridSize) { + PreferenceUtil.getInstance(getActivity()).setSongGridSizeLand(gridSize); + } + + @Override + public void saveUsePalette(boolean usePalette) { + PreferenceUtil.getInstance(getActivity()).setSongColoredFooters(usePalette); + } + + @Override + public boolean loadUsePalette() { + return PreferenceUtil.getInstance(getActivity()).songColoredFooters(); + } + + @Override + public void setUsePalette(boolean usePalette) { + getAdapter().usePalette(usePalette); + } + + @Override + protected void setGridSize(int gridSize) { + getLayoutManager().setSpanCount(gridSize); + getAdapter().notifyDataSetChanged(); + } + + @Override + public void onResume() { + super.onResume(); + getLibraryFragment().getToolbar().setTitle( + PreferenceUtil.getInstance(getContext()).tabTitles() ? R.string.library : R.string.songs); + if (getAdapter().getDataSet().isEmpty()) { + presenter.subscribe(); + } + } + + @Override + public void setMenuVisibility(boolean menuVisible) { + super.setMenuVisibility(menuVisible); + if (menuVisible) { + getLibraryFragment().getToolbar().setTitle( + PreferenceUtil.getInstance(getContext()).tabTitles() ? R.string.library + : R.string.songs); + } + } + + @Override + public void onDestroy() { + presenter.unsubscribe(); + super.onDestroy(); + } + + @Override + public void loading() { + + } + + @Override + public void showData(ArrayList songs) { + getAdapter().swapDataSet(songs); + } + + @Override + public void showEmptyView() { + getAdapter().swapDataSet(new ArrayList()); + } + + @Override + public void completed() { + + } + + @Override + protected String loadSortOrder() { + return PreferenceUtil.getInstance(getActivity()).getSongSortOrder(); + } + + @Override + protected void saveSortOrder(String sortOrder) { + PreferenceUtil.getInstance(getActivity()).setSongSortOrder(sortOrder); + } + + @Override + protected void setSortOrder(String sortOrder) { + presenter.loadSongs(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/folders/FoldersFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/folders/FoldersFragment.java new file mode 100644 index 00000000..b7a687a9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/folders/FoldersFragment.java @@ -0,0 +1,697 @@ +package code.name.monkey.retromusic.ui.fragments.mainactivity.folders; + +import android.app.Dialog; +import android.content.Context; +import android.media.MediaScannerConnection; +import android.os.Bundle; +import android.os.Environment; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.Snackbar; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.MimeTypeMap; +import android.widget.PopupMenu; +import android.widget.Toast; + +import com.afollestad.materialcab.MaterialCab; +import com.afollestad.materialdialogs.MaterialDialog; +import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.common.ATHToolbarActivity; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.menu.SongMenuHelper; +import code.name.monkey.retromusic.helper.menu.SongsMenuHelper; +import code.name.monkey.retromusic.interfaces.CabHolder; +import code.name.monkey.retromusic.interfaces.LoaderIds; +import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks; +import code.name.monkey.retromusic.misc.DialogAsyncTask; +import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener; +import code.name.monkey.retromusic.misc.WrappedAsyncTaskLoader; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.adapter.SongFileAdapter; +import code.name.monkey.retromusic.ui.fragments.base.AbsMainActivityFragment; +import code.name.monkey.retromusic.util.FileUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroColorUtil; +import code.name.monkey.retromusic.util.ViewUtil; +import code.name.monkey.retromusic.views.BreadCrumbLayout; + +public class FoldersFragment extends AbsMainActivityFragment implements + MainActivityFragmentCallbacks, + CabHolder, BreadCrumbLayout.SelectionCallback, SongFileAdapter.Callbacks, + AppBarLayout.OnOffsetChangedListener, LoaderManager.LoaderCallbacks> { + + public static final String TAG = FoldersFragment.class.getSimpleName(); + public static final FileFilter AUDIO_FILE_FILTER = file -> !file.isHidden() && (file.isDirectory() || + FileUtil.fileIsMimeType(file, "audio/*", MimeTypeMap.getSingleton()) || + FileUtil.fileIsMimeType(file, "application/opus", MimeTypeMap.getSingleton()) || + FileUtil.fileIsMimeType(file, "application/ogg", MimeTypeMap.getSingleton())); + + protected static final String PATH = "path"; + protected static final String CRUMBS = "crumbs"; + private static final int LOADER_ID = LoaderIds.FOLDERS_FRAGMENT; + @BindView(R.id.coordinator_layout) + CoordinatorLayout coordinatorLayout; + @BindView(R.id.container) + View container; + @BindView(android.R.id.empty) + View empty; + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.bread_crumbs) + BreadCrumbLayout breadCrumbs; + @BindView(R.id.appbar) + AppBarLayout appbar; + @BindView(R.id.status_bar) + View statusBar; + @BindView(R.id.recycler_view) + FastScrollRecyclerView recyclerView; + Comparator fileComparator = (lhs, rhs) -> { + if (lhs.isDirectory() && !rhs.isDirectory()) { + return -1; + } else if (!lhs.isDirectory() && rhs.isDirectory()) { + return 1; + } else { + return lhs.getName().compareToIgnoreCase + (rhs.getName()); + } + }; + + private Unbinder unbinder; + private SongFileAdapter adapter; + private MaterialCab cab; + + public FoldersFragment() { + } + + public static FoldersFragment newInstance(Context context) { + return newInstance(PreferenceUtil.getInstance(context).getStartDirectory()); + } + + public static FoldersFragment newInstance(File directory) { + FoldersFragment frag = new FoldersFragment(); + Bundle b = new Bundle(); + b.putSerializable(PATH, directory); + frag.setArguments(b); + return frag; + } + + + public static File getDefaultStartDirectory() { + File musicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC); + File startFolder; + if (musicDir.exists() && musicDir.isDirectory()) { + startFolder = musicDir; + } else { + File externalStorage = Environment.getExternalStorageDirectory(); + if (externalStorage.exists() && externalStorage.isDirectory()) { + startFolder = externalStorage; + } else { + startFolder = new File("/"); // root + } + } + return startFolder; + } + + private static File tryGetCanonicalFile(File file) { + try { + return file.getCanonicalFile(); + } catch (IOException e) { + e.printStackTrace(); + return file; + } + } + + public void setCrumb(BreadCrumbLayout.Crumb crumb, boolean addToHistory) { + if (crumb == null) { + return; + } + saveScrollPosition(); + breadCrumbs.setActiveOrAdd(crumb, false); + if (addToHistory) { + breadCrumbs.addHistory(crumb); + } + getLoaderManager().restartLoader(LOADER_ID, null, this); + } + + private void saveScrollPosition() { + BreadCrumbLayout.Crumb crumb = getActiveCrumb(); + if (crumb != null) { + crumb.setScrollPosition( + ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition()); + } + } + + @Nullable + private BreadCrumbLayout.Crumb getActiveCrumb() { + return breadCrumbs != null && breadCrumbs.size() > 0 ? breadCrumbs + .getCrumb(breadCrumbs.getActiveIndex()) : null; + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelable(CRUMBS, breadCrumbs.getStateWrapper()); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + if (savedInstanceState == null) { + //noinspection ConstantConditions + setCrumb(new BreadCrumbLayout.Crumb( + FileUtil.safeGetCanonicalFile((File) getArguments().getSerializable(PATH))), true); + } else { + breadCrumbs.restoreFromStateWrapper(savedInstanceState.getParcelable(CRUMBS)); + getLoaderManager().initLoader(LOADER_ID, null, this); + } + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_folder, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + setStatusbarColorAuto(view); + getMainActivity().getSlidingUpPanelLayout().setShadowHeight(0); + + getMainActivity().setBottomBarVisibility(View.GONE); + + setUpAppbarColor(); + setUpToolbar(); + setUpBreadCrumbs(); + setUpRecyclerView(); + setUpAdapter(); + ViewUtil.setStatusBarHeight(getContext(), statusBar); + } + + private void setUpAppbarColor() { + //noinspection ConstantConditions + int primaryColor = ThemeStore.primaryColor(getActivity()); + appbar.setBackgroundColor(primaryColor); + toolbar.setBackgroundColor(primaryColor); + //breadCrumbs.setBackgroundColor(primaryColor); + breadCrumbs.setActivatedContentColor(ToolbarContentTintHelper.toolbarTitleColor(getActivity(), primaryColor)); + breadCrumbs.setDeactivatedContentColor(ToolbarContentTintHelper.toolbarSubtitleColor(getActivity(), primaryColor)); + appbar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> getMainActivity().setLightStatusbar(!ATHUtil.isWindowBackgroundDark(getContext()))); + } + + private void setUpToolbar() { + toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); + //noinspection ConstantConditions + getActivity().setTitle(R.string.folders); + getMainActivity().setSupportActionBar(toolbar); + } + + private void setUpBreadCrumbs() { + breadCrumbs.setCallback(this); + } + + private void setUpRecyclerView() { + //noinspection ConstantConditions + ViewUtil.setUpFastScrollRecyclerViewColor(getActivity(), recyclerView, ThemeStore.accentColor(getActivity())); + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + appbar.addOnOffsetChangedListener(this); + } + + private void setUpAdapter() { + adapter = new SongFileAdapter(getMainActivity(), new LinkedList(), R.layout.item_list, this, this); + adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { + @Override + public void onChanged() { + super.onChanged(); + checkIsEmpty(); + } + }); + recyclerView.setAdapter(adapter); + checkIsEmpty(); + } + + @Override + public void onPause() { + super.onPause(); + saveScrollPosition(); + } + + @Override + public void onDestroyView() { + appbar.removeOnOffsetChangedListener(this); + unbinder.unbind(); + super.onDestroyView(); + } + + @Override + public boolean handleBackPress() { + if (cab != null && cab.isActive()) { + cab.finish(); + return true; + } + if (breadCrumbs != null && breadCrumbs.popHistory()) { + setCrumb(breadCrumbs.lastHistory(), false); + return true; + } + return false; + } + + @NonNull + @Override + public MaterialCab openCab(int menuRes, MaterialCab.Callback callback) { + if (cab != null && cab.isActive()) cab.finish(); + cab = new MaterialCab(getMainActivity(), R.id.cab_stub) + .setMenu(menuRes) + .setCloseDrawableRes(R.drawable.ic_close_white_24dp) + .setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor + (getActivity()))) + .start(callback); + return cab; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.menu_folders, menu); + ToolbarContentTintHelper.handleOnCreateOptionsMenu(getActivity(), toolbar, menu, ATHToolbarActivity.getToolbarBackgroundColor(toolbar)); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + ToolbarContentTintHelper.handleOnPrepareOptionsMenu(getActivity(), toolbar); + } + + @Override + public void onCrumbSelection(BreadCrumbLayout.Crumb crumb, int index) { + setCrumb(crumb, true); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + //noinspection ConstantConditions + getActivity().onBackPressed(); + break; + case R.id.action_go_to_start_directory: + setCrumb(new BreadCrumbLayout.Crumb(tryGetCanonicalFile(PreferenceUtil.getInstance(getActivity()).getStartDirectory())), true); + return true; + case R.id.action_scan: + BreadCrumbLayout.Crumb crumb = getActiveCrumb(); + if (crumb != null) { + //noinspection Convert2MethodRef + new ListPathsAsyncTask(getActivity(), paths -> scanPaths(paths)).execute(new ListPathsAsyncTask.LoadingInfo(crumb.getFile(), AUDIO_FILE_FILTER)); + } + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onFileSelected(File file) { + file = tryGetCanonicalFile(file); // important as we compare the path value later + if (file.isDirectory()) { + setCrumb(new BreadCrumbLayout.Crumb(file), true); + } else { + FileFilter fileFilter = pathname -> !pathname.isDirectory() && AUDIO_FILE_FILTER.accept(pathname); + new ListSongsAsyncTask(getActivity(), file, (songs, extra) -> { + File file1 = (File) extra; + int startIndex = -1; + for (int i = 0; i < songs.size(); i++) { + if (file1.getPath().equals(songs.get(i).data)) { // path is already canonical here + startIndex = i; + break; + } + } + if (startIndex > -1) { + MusicPlayerRemote.openQueue(songs, startIndex, true); + } else { + final File finalFile = file1; + Snackbar.make(coordinatorLayout, Html.fromHtml(String.format(getString(R.string.not_listed_in_media_store), file1.getName())), Snackbar.LENGTH_LONG) + .setAction(R.string.action_scan, v -> new ListPathsAsyncTask(getActivity(), paths -> scanPaths(paths)).execute(new ListPathsAsyncTask.LoadingInfo(finalFile, AUDIO_FILE_FILTER))) + .setActionTextColor(ThemeStore.accentColor(getActivity())) + .show(); + } + }).execute(new ListSongsAsyncTask.LoadingInfo(toList(file.getParentFile()), fileFilter, getFileComparator())); + } + } + + @Override + public void onMultipleItemAction(MenuItem item, ArrayList files) { + final int itemId = item.getItemId(); + new ListSongsAsyncTask(getActivity(), null, (songs, extra) -> SongsMenuHelper.handleMenuClick(getActivity(), songs, itemId)).execute(new ListSongsAsyncTask.LoadingInfo(files, AUDIO_FILE_FILTER, getFileComparator())); + } + + private ArrayList toList(File file) { + ArrayList files = new ArrayList<>(1); + files.add(file); + return files; + } + + private Comparator getFileComparator() { + return fileComparator; + } + + @Override + public void onFileMenuClicked(final File file, View view) { + PopupMenu popupMenu = new PopupMenu(getActivity(), view); + if (file.isDirectory()) { + popupMenu.inflate(R.menu.menu_item_directory); + popupMenu.setOnMenuItemClickListener(item -> { + final int itemId = item.getItemId(); + switch (itemId) { + case R.id.action_play_next: + case R.id.action_add_to_current_playing: + case R.id.action_add_to_playlist: + case R.id.action_delete_from_device: + new ListSongsAsyncTask(getActivity(), null, (songs, extra) -> SongsMenuHelper.handleMenuClick(getActivity(), songs, itemId)).execute(new ListSongsAsyncTask.LoadingInfo(toList(file), AUDIO_FILE_FILTER, getFileComparator())); + return true; + case R.id.action_set_as_start_directory: + PreferenceUtil.getInstance(getActivity()).setStartDirectory(file); + Toast.makeText(getActivity(), String.format(getString(R.string.new_start_directory), file.getPath()), Toast.LENGTH_SHORT).show(); + return true; + case R.id.action_scan: + new ListPathsAsyncTask(getActivity(), paths -> scanPaths(paths)).execute(new ListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER)); + return true; + } + return false; + }); + } else { + popupMenu.inflate(R.menu.menu_item_file); + popupMenu.setOnMenuItemClickListener(item -> { + final int itemId = item.getItemId(); + switch (itemId) { + case R.id.action_play_next: + case R.id.action_add_to_current_playing: + case R.id.action_add_to_playlist: + case R.id.action_go_to_album: + case R.id.action_go_to_artist: + case R.id.action_share: + case R.id.action_tag_editor: + case R.id.action_details: + case R.id.action_set_as_ringtone: + case R.id.action_delete_from_device: + new ListSongsAsyncTask(getActivity(), null, (songs, extra) -> SongMenuHelper.handleMenuClick(getActivity(), songs.get(0), itemId)).execute(new ListSongsAsyncTask.LoadingInfo(toList(file), AUDIO_FILE_FILTER, getFileComparator())); + return true; + case R.id.action_scan: + new ListPathsAsyncTask(getActivity(), paths -> scanPaths(paths)).execute(new ListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER)); + return true; + } + return false; + }); + } + popupMenu.show(); + } + + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + container.setPadding(container.getPaddingLeft(), container.getPaddingTop(), container.getPaddingRight(), appbar.getTotalScrollRange() + verticalOffset); + } + + private void checkIsEmpty() { + if (empty != null) { + empty.setVisibility(adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); + } + } + + private void scanPaths(@Nullable String[] toBeScanned) { + if (getActivity() == null) return; + if (toBeScanned == null || toBeScanned.length < 1) { + Toast.makeText(getActivity(), R.string.nothing_to_scan, Toast.LENGTH_SHORT).show(); + } else { + MediaScannerConnection.scanFile(getActivity().getApplicationContext(), toBeScanned, null, new UpdateToastMediaScannerCompletionListener(getActivity(), toBeScanned)); + } + } + + private void updateAdapter(@NonNull List files) { + adapter.swapDataSet(files); + BreadCrumbLayout.Crumb crumb = getActiveCrumb(); + if (crumb != null && recyclerView != null) { + ((LinearLayoutManager) recyclerView.getLayoutManager()) + .scrollToPositionWithOffset(crumb.getScrollPosition(), 0); + } + } + + @NonNull + @Override + public Loader> onCreateLoader(int id, Bundle args) { + return new AsyncFileLoader(this); + } + + @Override + public void onLoadFinished(@NonNull Loader> loader, List data) { + updateAdapter(data); + } + + @Override + public void onLoaderReset(@NonNull Loader> loader) { + updateAdapter(new LinkedList()); + } + + private static class AsyncFileLoader extends WrappedAsyncTaskLoader> { + private WeakReference fragmentWeakReference; + + public AsyncFileLoader(FoldersFragment foldersFragment) { + super(foldersFragment.getActivity()); + fragmentWeakReference = new WeakReference<>(foldersFragment); + } + + @Override + public List loadInBackground() { + FoldersFragment foldersFragment = fragmentWeakReference.get(); + File directory = null; + if (foldersFragment != null) { + BreadCrumbLayout.Crumb crumb = foldersFragment.getActiveCrumb(); + if (crumb != null) { + directory = crumb.getFile(); + } + } + if (directory != null) { + List files = FileUtil.listFiles(directory, AUDIO_FILE_FILTER); + Collections.sort(files, foldersFragment.getFileComparator()); + return files; + } else { + return new LinkedList<>(); + } + } + } + + private static class ListSongsAsyncTask extends ListingFilesDialogAsyncTask> { + private final Object extra; + private WeakReference contextWeakReference; + private WeakReference callbackWeakReference; + + public ListSongsAsyncTask(Context context, Object extra, OnSongsListedCallback callback) { + super(context); + this.extra = extra; + contextWeakReference = new WeakReference<>(context); + callbackWeakReference = new WeakReference<>(callback); + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + checkCallbackReference(); + checkContextReference(); + } + + @Override + protected ArrayList doInBackground(LoadingInfo... params) { + try { + LoadingInfo info = params[0]; + List files = FileUtil.listFilesDeep(info.files, info.fileFilter); + + if (isCancelled() || checkContextReference() == null || checkCallbackReference() == null) + return null; + + Collections.sort(files, info.fileComparator); + + Context context = checkContextReference(); + if (isCancelled() || context == null || checkCallbackReference() == null) + return null; + + return FileUtil.matchFilesWithMediaStore(context, files).blockingFirst(); + } catch (Exception e) { + e.printStackTrace(); + cancel(false); + return null; + } + } + + @Override + protected void onPostExecute(ArrayList songs) { + super.onPostExecute(songs); + OnSongsListedCallback callback = checkCallbackReference(); + if (songs != null && callback != null) + callback.onSongsListed(songs, extra); + } + + private Context checkContextReference() { + Context context = contextWeakReference.get(); + if (context == null) { + cancel(false); + } + return context; + } + + private OnSongsListedCallback checkCallbackReference() { + OnSongsListedCallback callback = callbackWeakReference.get(); + if (callback == null) { + cancel(false); + } + return callback; + } + + public interface OnSongsListedCallback { + void onSongsListed(@NonNull ArrayList songs, Object extra); + } + + public static class LoadingInfo { + public final Comparator fileComparator; + public final FileFilter fileFilter; + public final List files; + + public LoadingInfo(@NonNull List files, @NonNull FileFilter fileFilter, @NonNull Comparator fileComparator) { + this.fileComparator = fileComparator; + this.fileFilter = fileFilter; + this.files = files; + } + } + } + + public static class ListPathsAsyncTask extends ListingFilesDialogAsyncTask { + private WeakReference onPathsListedCallbackWeakReference; + + public ListPathsAsyncTask(Context context, OnPathsListedCallback callback) { + super(context); + onPathsListedCallbackWeakReference = new WeakReference<>(callback); + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + checkCallbackReference(); + } + + @Override + protected String[] doInBackground(LoadingInfo... params) { + try { + if (isCancelled() || checkCallbackReference() == null) return null; + + LoadingInfo info = params[0]; + + final String[] paths; + + if (info.file.isDirectory()) { + List files = FileUtil.listFilesDeep(info.file, info.fileFilter); + + if (isCancelled() || checkCallbackReference() == null) return null; + + paths = new String[files.size()]; + for (int i = 0; i < files.size(); i++) { + File f = files.get(i); + paths[i] = FileUtil.safeGetCanonicalPath(f); + + if (isCancelled() || checkCallbackReference() == null) return null; + } + } else { + paths = new String[1]; + paths[0] = info.file.getPath(); + } + + return paths; + } catch (Exception e) { + e.printStackTrace(); + cancel(false); + return null; + } + } + + @Override + protected void onPostExecute(String[] paths) { + super.onPostExecute(paths); + OnPathsListedCallback callback = checkCallbackReference(); + if (callback != null && paths != null) { + callback.onPathsListed(paths); + } + } + + private OnPathsListedCallback checkCallbackReference() { + OnPathsListedCallback callback = onPathsListedCallbackWeakReference.get(); + if (callback == null) { + cancel(false); + } + return callback; + } + + public interface OnPathsListedCallback { + void onPathsListed(@NonNull String[] paths); + } + + public static class LoadingInfo { + public final File file; + public final FileFilter fileFilter; + + public LoadingInfo(File file, FileFilter fileFilter) { + this.file = file; + this.fileFilter = fileFilter; + } + } + } + + private static abstract class ListingFilesDialogAsyncTask extends DialogAsyncTask { + public ListingFilesDialogAsyncTask(Context context) { + super(context); + } + + public ListingFilesDialogAsyncTask(Context context, int showDelay) { + super(context, showDelay); + } + + @Override + protected Dialog createDialog(@NonNull Context context) { + return new MaterialDialog.Builder(context) + .title(R.string.listing_files) + .progress(true, 0) + .progressIndeterminateStyle(true) + .cancelListener(dialog -> cancel(false)) + .dismissListener(dialog -> cancel(false)) + .negativeText(android.R.string.cancel) + .onNegative((dialog, which) -> cancel(false)) + .show(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/home/HomeFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/home/HomeFragment.java new file mode 100644 index 00000000..f9085a3e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/home/HomeFragment.java @@ -0,0 +1,413 @@ +package code.name.monkey.retromusic.ui.fragments.mainactivity.home; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CollapsingToolbarLayout; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.DiskCacheStrategy; + +import java.io.File; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Random; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.dialogs.HomeOptionDialog; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks; +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.misc.AppBarStateChangeListener; +import code.name.monkey.retromusic.model.Album; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.smartplaylist.HistoryPlaylist; +import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist; +import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist; +import code.name.monkey.retromusic.mvp.contract.HomeContract; +import code.name.monkey.retromusic.mvp.presenter.HomePresenter; +import code.name.monkey.retromusic.ui.adapter.GenreAdapter; +import code.name.monkey.retromusic.ui.adapter.album.AlbumFullWithAdapter; +import code.name.monkey.retromusic.ui.adapter.artist.ArtistAdapter; +import code.name.monkey.retromusic.ui.fragments.base.AbsMainActivityFragment; +import code.name.monkey.retromusic.util.Compressor; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroUtil; +import code.name.monkey.retromusic.views.CircularImageView; +import code.name.monkey.retromusic.views.MetalRecyclerViewPager; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +import static code.name.monkey.retromusic.Constants.USER_BANNER; +import static code.name.monkey.retromusic.Constants.USER_PROFILE; + +public class HomeFragment extends AbsMainActivityFragment implements MainActivityFragmentCallbacks, + HomeContract.HomeView { + private static final String TAG = "HomeFragment"; + Unbinder unbinder; + @BindView(R.id.home_toolbar) + Toolbar toolbar; + @BindView(R.id.appbar) + AppBarLayout appbar; + @BindView(R.id.image) + ImageView imageView; + @BindView(R.id.user_image) + CircularImageView userImage; + @BindView(R.id.collapsing_toolbar) + CollapsingToolbarLayout toolbarLayout; + @BindView(R.id.recycler_view) + RecyclerView recentArtistRV; + @BindView(R.id.recent_album) + RecyclerView recentAlbumRV; + @BindView(R.id.top_artist) + RecyclerView topArtistRV; + @BindView(R.id.top_album) + MetalRecyclerViewPager topAlbumRV; + @BindView(R.id.recent_artist_container) + View recentArtistContainer; + @BindView(R.id.recent_albums_container) + View recentAlbumsContainer; + @BindView(R.id.top_artist_container) + View topArtistContainer; + @BindView(R.id.top_albums_container) + View topAlbumContainer; + @BindView(R.id.genres) + RecyclerView genresRecyclerView; + @BindView(R.id.genre_container) + LinearLayout genreContainer; + @BindView(R.id.container) + View container; + @BindView(R.id.title) + TextView title; + @BindView(R.id.search) + ImageView search; + + + private HomePresenter homePresenter; + private CompositeDisposable disposable; + + public static HomeFragment newInstance() { + Bundle args = new Bundle(); + HomeFragment fragment = new HomeFragment(); + fragment.setArguments(args); + return fragment; + } + + private void getTimeOfTheDay() { + Calendar c = Calendar.getInstance(); + int timeOfDay = c.get(Calendar.HOUR_OF_DAY); + + String[] images = new String[]{}; + if (timeOfDay >= 0 && timeOfDay < 6) { + images = getResources().getStringArray(R.array.night); + } else if (timeOfDay >= 6 && timeOfDay < 12) { + images = getResources().getStringArray(R.array.morning); + } else if (timeOfDay >= 12 && timeOfDay < 16) { + images = getResources().getStringArray(R.array.after_noon); + } else if (timeOfDay >= 16 && timeOfDay < 20) { + images = getResources().getStringArray(R.array.evening); + } else if (timeOfDay >= 20 && timeOfDay < 24) { + images = getResources().getStringArray(R.array.night); + } + String day = images[new Random().nextInt(images.length)]; + loadTimeImage(day); + } + + private void loadTimeImage(String day) { + //noinspection ConstantConditions + if (PreferenceUtil.getInstance(getActivity()).getBannerImage().isEmpty()) { + if (imageView != null) { + Glide.with(getActivity()).load(day) + .asBitmap() + .placeholder(R.drawable.material_design_default) + .diskCacheStrategy(DiskCacheStrategy.SOURCE) + .into(imageView); + } + } else { + loadBannerFromStorage(); + } + } + + private void loadBannerFromStorage() { + //noinspection ConstantConditions + disposable.add(new Compressor(getContext()) + .setQuality(100) + .setCompressFormat(Bitmap.CompressFormat.WEBP) + .compressToBitmapAsFlowable( + new File(PreferenceUtil.getInstance(getContext()).getBannerImage(), USER_BANNER)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(imageView::setImageBitmap)); + } + + private void loadImageFromStorage(ImageView imageView) { + //noinspection ConstantConditions + disposable.add(new Compressor(getContext()) + .setMaxHeight(300) + .setMaxWidth(300) + .setQuality(75) + .setCompressFormat(Bitmap.CompressFormat.WEBP) + .compressToBitmapAsFlowable( + new File(PreferenceUtil.getInstance(getContext()).getProfileImage(), USER_PROFILE)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(imageView::setImageBitmap, + throwable -> imageView.setImageDrawable(ContextCompat + .getDrawable(getContext(), R.drawable.ic_person_flat)))); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + disposable = new CompositeDisposable(); + //noinspection ConstantConditions + homePresenter = new HomePresenter(this); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_home, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + getMainActivity().getSlidingUpPanelLayout().setShadowHeight(8); + getMainActivity().setBottomBarVisibility(View.VISIBLE); + + setupToolbar(); + loadImageFromStorage(userImage); + + homePresenter.subscribe(); + checkPadding(); + getTimeOfTheDay(); + } + + @SuppressWarnings("ConstantConditions") + private void setupToolbar() { + if (!PreferenceUtil.getInstance(getContext()).getFullScreenMode()) { + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar + .getLayoutParams(); + params.topMargin = RetroUtil.getStatusBarHeight(getContext()); + toolbar.setLayoutParams(params); + } + + appbar.addOnOffsetChangedListener(new AppBarStateChangeListener() { + @Override + public void onStateChanged(AppBarLayout appBarLayout, State state) { + int color; + switch (state) { + case COLLAPSED: + getMainActivity().setLightStatusbar(!ATHUtil.isWindowBackgroundDark(getContext())); + color = ThemeStore.textColorPrimary(getContext()); + break; + default: + case EXPANDED: + case IDLE: + getMainActivity().setLightStatusbar(false); + color = ContextCompat.getColor(getContext(), R.color.md_white_1000); + break; + } + TintHelper.setTintAuto(search, color, false); + title.setTextColor(color); + } + }); + + int primaryColor = ThemeStore.primaryColor(getContext()); + + TintHelper.setTintAuto(container, primaryColor, true); + toolbarLayout.setStatusBarScrimColor(primaryColor); + toolbarLayout.setContentScrimColor(primaryColor); + + toolbar.setTitle(R.string.home); + getMainActivity().setSupportActionBar(toolbar); + + } + + @Override + public boolean handleBackPress() { + return false; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + disposable.clear(); + homePresenter.unsubscribe(); + } + + @Override + public void loading() { + + } + + @Override + public void showEmptyView() { + + } + + @Override + public void completed() { + + } + + @Override + public void showData(ArrayList homes) { + //homeAdapter.swapDataSet(homes); + } + + @Override + public void onMediaStoreChanged() { + super.onMediaStoreChanged(); + homePresenter.subscribe(); + } + + @Override + public void onServiceConnected() { + super.onServiceConnected(); + checkPadding(); + } + + @Override + public void onQueueChanged() { + super.onQueueChanged(); + checkPadding(); + } + + private void checkPadding() { + int height = getResources().getDimensionPixelSize(R.dimen.mini_player_height); + container.setPadding(0, 0, 0, MusicPlayerRemote.getPlayingQueue().isEmpty() ? height * 2 : 0); + } + + @Override + public void recentArtist(ArrayList artists) { + recentArtistContainer.setVisibility(View.VISIBLE); + recentArtistRV.setLayoutManager(new GridLayoutManager(getMainActivity(), + 1, GridLayoutManager.HORIZONTAL, false)); + ArtistAdapter artistAdapter = new ArtistAdapter(getMainActivity(), artists, + R.layout.item_artist, false, null); + recentArtistRV.setAdapter(artistAdapter); + } + + @Override + public void recentAlbum(ArrayList albums) { + recentAlbumsContainer.setVisibility(View.VISIBLE); + AlbumFullWithAdapter artistAdapter = new AlbumFullWithAdapter(getMainActivity(), + getDisplayMetrics()); + artistAdapter.swapData(albums); + recentAlbumRV.setAdapter(artistAdapter); + } + + @Override + public void topArtists(ArrayList artists) { + topArtistContainer.setVisibility(View.VISIBLE); + topArtistRV.setLayoutManager(new GridLayoutManager(getMainActivity(), + 1, GridLayoutManager.HORIZONTAL, false)); + ArtistAdapter artistAdapter = new ArtistAdapter(getMainActivity(), artists, + R.layout.item_artist, false, null); + topArtistRV.setAdapter(artistAdapter); + + } + + @Override + public void topAlbums(ArrayList albums) { + topAlbumContainer.setVisibility(View.VISIBLE); + AlbumFullWithAdapter artistAdapter = new AlbumFullWithAdapter(getMainActivity(), + getDisplayMetrics()); + artistAdapter.swapData(albums); + topAlbumRV.setAdapter(artistAdapter); + } + + private DisplayMetrics getDisplayMetrics() { + Display display = getMainActivity().getWindowManager().getDefaultDisplay(); + DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + + return metrics; + } + + @Override + public void suggestions(ArrayList playlists) { + + } + + + @Override + public void geners(ArrayList genres) { + genreContainer.setVisibility(View.VISIBLE); + genresRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + //noinspection ConstantConditions + GenreAdapter genreAdapter = new GenreAdapter(getActivity(), genres, R.layout.item_list); + genresRecyclerView.setAdapter(genreAdapter); + } + + + @OnClick({R.id.last_added, R.id.top_played, R.id.action_shuffle, R.id.history, + R.id.user_image, R.id.search}) + void startUserInfo(View view) { + Activity activity = getActivity(); + if (activity != null) { + switch (view.getId()) { + case R.id.action_shuffle: + MusicPlayerRemote + .openAndShuffleQueue(SongLoader.getAllSongs(activity).blockingFirst(), true); + break; + case R.id.last_added: + NavigationUtil.goToPlaylistNew(activity, new LastAddedPlaylist(activity)); + break; + case R.id.top_played: + NavigationUtil.goToPlaylistNew(activity, new MyTopTracksPlaylist(activity)); + break; + case R.id.history: + NavigationUtil.goToPlaylistNew(activity, new HistoryPlaylist(activity)); + break; + case R.id.search: + NavigationUtil.goToSearch(activity); + break; + case R.id.user_image: + new HomeOptionDialog().show(getFragmentManager(), TAG); + break; + } + } + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + homePresenter.loadRecentArtists(); + homePresenter.loadRecentAlbums(); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/PlayerAlbumCoverFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/PlayerAlbumCoverFragment.java new file mode 100644 index 00000000..e5ff394f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/PlayerAlbumCoverFragment.java @@ -0,0 +1,154 @@ +package code.name.monkey.retromusic.ui.fragments.player; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.transform.CustPagerTransformer; +import code.name.monkey.retromusic.transform.NormalPageTransformer; +import code.name.monkey.retromusic.transform.ParallaxPagerTransformer; +import code.name.monkey.retromusic.ui.adapter.album.AlbumCoverPagerAdapter; +import code.name.monkey.retromusic.ui.fragments.NowPlayingScreen; +import code.name.monkey.retromusic.ui.fragments.base.AbsMusicServiceFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; + + +public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements + ViewPager.OnPageChangeListener { + + public static final String TAG = PlayerAlbumCoverFragment.class.getSimpleName(); + public static final long VISIBILITY_ANIM_DURATION = 300; + @BindView(R.id.player_album_cover_viewpager) + ViewPager viewPager; + private Unbinder unbinder; + private Callbacks callbacks; + private int currentPosition; + private AlbumCoverPagerAdapter.AlbumCoverFragment.ColorReceiver colorReceiver = + new AlbumCoverPagerAdapter.AlbumCoverFragment.ColorReceiver() { + @Override + public void onColorReady(int color, int requestCode) { + if (currentPosition == requestCode) { + notifyColorChange(color); + } + } + }; + + public void removeSlideEffect() { + ParallaxPagerTransformer transformer = new ParallaxPagerTransformer(R.id.player_image); + transformer.setSpeed(0.3f); + viewPager.setPageTransformer(true, transformer); + + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_player_album_cover, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + viewPager.addOnPageChangeListener(this); + + //noinspection ConstantConditions + if (PreferenceUtil.getInstance(getContext()).carouselEffect() && !( + (PreferenceUtil.getInstance(getContext()).getNowPlayingScreen() == NowPlayingScreen.FULL) || + (PreferenceUtil.getInstance(getContext()).getNowPlayingScreen() + == NowPlayingScreen.FLAT))) { + viewPager.setClipToPadding(false); + viewPager.setPadding(96, 0, 96, 0); + viewPager.setPageMargin(18); + + viewPager.setPageTransformer(false, new CustPagerTransformer(getContext())); + } else { + viewPager.setPageTransformer(true, new NormalPageTransformer()); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + viewPager.removeOnPageChangeListener(this); + unbinder.unbind(); + } + + @Override + public void onServiceConnected() { + updatePlayingQueue(); + } + + @Override + public void onPlayingMetaChanged() { + viewPager.setCurrentItem(MusicPlayerRemote.getPosition()); + } + + @Override + public void onQueueChanged() { + updatePlayingQueue(); + } + + private void updatePlayingQueue() { + viewPager.setAdapter( + new AlbumCoverPagerAdapter(getFragmentManager(), MusicPlayerRemote.getPlayingQueue())); + //noinspection ConstantConditions + viewPager.getAdapter().notifyDataSetChanged(); + viewPager.setCurrentItem(MusicPlayerRemote.getPosition()); + onPageSelected(MusicPlayerRemote.getPosition()); + + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + currentPosition = position; + if (viewPager.getAdapter() != null) { + ((AlbumCoverPagerAdapter) viewPager.getAdapter()).receiveColor(colorReceiver, position); + } + if (position != MusicPlayerRemote.getPosition()) { + MusicPlayerRemote.playSongAt(position); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + + + private void notifyColorChange(int color) { + if (callbacks != null) { + callbacks.onColorChanged(color); + } + } + + public void setCallbacks(Callbacks listener) { + callbacks = listener; + } + + public void removeEffect() { + viewPager.setPageTransformer(false, null); + } + + + public interface Callbacks { + + void onColorChanged(int color); + + void onFavoriteToggled(); + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptiveFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptiveFragment.java new file mode 100644 index 00000000..482a93e5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptiveFragment.java @@ -0,0 +1,165 @@ +package code.name.monkey.retromusic.ui.fragments.player.adaptive; + +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment.Callbacks; +import code.name.monkey.retromusic.ui.fragments.player.normal.PlayerFragment; + +public class AdaptiveFragment extends AbsPlayerFragment implements Callbacks { + + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.status_bar) + View statusBar; + + private int lastColor; + private AdaptivePlaybackControlsFragment playbackControlsFragment; + private Unbinder unbinder; + + public static PlayerFragment newInstance() { + Bundle args = new Bundle(); + PlayerFragment fragment = new PlayerFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + @ColorInt + public int getPaletteColor() { + return lastColor; + } + + @Override + public void onShow() { + playbackControlsFragment.show(); + } + + @Override + public void onHide() { + playbackControlsFragment.hide(); + onBackPressed(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return ATHUtil.resolveColor(getContext(), R.attr.iconColor); + } + + @Override + public void onColorChanged(int color) { + playbackControlsFragment.setDark(color); + lastColor = color; + getCallbacks().onPaletteColorChanged(); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, + ATHUtil.resolveColor(getContext(), R.attr.iconColor), getActivity()); + + } + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_adaptive_player, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + + setUpSubFragments(); + setUpPlayerToolbar(); + } + + private void setUpSubFragments() { + playbackControlsFragment = + (AdaptivePlaybackControlsFragment) getChildFragmentManager() + .findFragmentById(R.id.playback_controls_fragment); + + PlayerAlbumCoverFragment playerAlbumCoverFragment = + (PlayerAlbumCoverFragment) getChildFragmentManager() + .findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + playerAlbumCoverFragment.removeSlideEffect(); + } + + private void setUpPlayerToolbar() { + int primaryColor = ATHUtil.resolveColor(getContext(), R.attr.iconColor); + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, primaryColor, getActivity()); + toolbar.setTitleTextColor(primaryColor); + toolbar.setSubtitleTextColor(ThemeStore.textColorSecondary(getContext())); + } + + @Override + public void onServiceConnected() { + updateIsFavorite(); + updateSong(); + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + toolbar.setTitle(song.title); + toolbar.setSubtitle(song.artistName); + } + + @Override + public void onPlayingMetaChanged() { + updateIsFavorite(); + updateSong(); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptivePlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptivePlaybackControlsFragment.java new file mode 100644 index 00000000..4db21270 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptivePlaybackControlsFragment.java @@ -0,0 +1,313 @@ +package code.name.monkey.retromusic.ui.fragments.player.adaptive; + +import android.animation.ObjectAnimator; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatSeekBar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.PlayPauseDrawable; + +public class AdaptivePlaybackControlsFragment extends AbsPlayerControlsFragment { + + @BindView(R.id.player_play_pause_button) + ImageButton playPauseButton; + @BindView(R.id.player_prev_button) + ImageButton prevButton; + @BindView(R.id.player_next_button) + ImageButton nextButton; + @BindView(R.id.player_repeat_button) + ImageButton repeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton shuffleButton; + @BindView(R.id.player_progress_slider) + AppCompatSeekBar progressSlider; + @BindView(R.id.player_song_total_time) + TextView songTotalTime; + @BindView(R.id.player_song_current_progress) + TextView songCurrentProgress; + @BindView(R.id.volume_fragment_container) + View volumeContainer; + + + private Unbinder unbinder; + private PlayPauseDrawable playPauseDrawable; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater + .inflate(R.layout.fragment_adaptive_player_playback_controls, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + unbinder = ButterKnife.bind(this, view); + setUpMusicControllers(); + + hideVolumeIfAvailable(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateShuffleState(); + + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Override + public void setDark(int dark) { + + if (ColorUtil.isColorLight(ATHUtil.resolveColor(getContext(), android.R.attr.windowBackground))) { + lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(getActivity(), true); + lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(getActivity(), true); + } else { + lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(getActivity(), false); + lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(getActivity(), false); + } + + updateRepeatState(); + updateShuffleState(); + updatePrevNextColor(); + updatePlayPauseColor(); + + TintHelper.setTintAuto(playPauseButton, MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(dark)), false); + TintHelper.setTintAuto(playPauseButton, dark, true); + TintHelper.setTintAuto(progressSlider, dark, false); + } + + private void updatePlayPauseColor() { + //playPauseButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpPlayPauseButton() { + playPauseDrawable = new PlayPauseDrawable(getActivity()); + playPauseButton.setImageDrawable(playPauseDrawable); + updatePlayPauseColor(); + playPauseButton.setOnClickListener(new PlayPauseButtonOnClickHandler()); + playPauseButton.post(() -> { + if (playPauseButton != null) { + playPauseButton.setPivotX(playPauseButton.getWidth() / 2); + playPauseButton.setPivotY(playPauseButton.getHeight() / 2); + } + }); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + playPauseDrawable.setPause(animate); + } else { + playPauseDrawable.setPlay(animate); + } + } + + private void setUpMusicControllers() { + setUpPlayPauseButton(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + nextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + prevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + prevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpShuffleButton() { + shuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + protected void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpRepeatButton() { + repeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + + @Override + protected void show() { + //Ignore + } + + @Override + protected void hide() { + //Ignore + } + + @Override + protected void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + + + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), + MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + } + + public void showBouceAnimation() { + playPauseButton.clearAnimation(); + + playPauseButton.setScaleX(0.9f); + playPauseButton.setScaleY(0.9f); + playPauseButton.setVisibility(View.VISIBLE); + playPauseButton.setPivotX(playPauseButton.getWidth() / 2); + playPauseButton.setPivotY(playPauseButton.getHeight() / 2); + + playPauseButton.animate() + .setDuration(200) + .setInterpolator(new DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(() -> playPauseButton.animate() + .setDuration(200) + .setInterpolator(new AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .start()) + .start(); + } + + @OnClick(R.id.player_play_pause_button) + void showAnimation() { + if (MusicPlayerRemote.isPlaying()) { + MusicPlayerRemote.pauseSong(); + } else { + MusicPlayerRemote.resumePlaying(); + } + showBouceAnimation(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + songTotalTime.setText(MusicUtil.getReadableDurationString(total)); + songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + } + + public void hideVolumeIfAvailable() { + volumeContainer.setVisibility( + PreferenceUtil.getInstance(getContext()).getVolumeToggle() ? View.VISIBLE : View.GONE); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlaybackControlsFragment.java new file mode 100644 index 00000000..f8a337ae --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlaybackControlsFragment.java @@ -0,0 +1,301 @@ +package code.name.monkey.retromusic.ui.fragments.player.blur; + +import android.animation.ObjectAnimator; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.AppCompatSeekBar; +import android.support.v7.widget.AppCompatTextView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.VolumeFragment; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.PlayPauseDrawable; + + +public class BlurPlaybackControlsFragment extends AbsPlayerControlsFragment { + + @BindView(R.id.player_play_pause_button) + ImageButton playPauseFab; + @BindView(R.id.player_prev_button) + ImageButton prevButton; + @BindView(R.id.player_next_button) + ImageButton nextButton; + @BindView(R.id.player_repeat_button) + ImageButton repeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton shuffleButton; + @BindView(R.id.player_progress_slider) + AppCompatSeekBar progressSlider; + @BindView(R.id.player_song_total_time) + TextView songTotalTime; + @BindView(R.id.player_song_current_progress) + TextView songCurrentProgress; + @BindView(R.id.title) + AppCompatTextView title; + @BindView(R.id.text) + TextView text; + @BindView(R.id.volume_fragment_container) + View mVolumeContainer; + private Unbinder unbinder; + private PlayPauseDrawable playerFabPlayPauseDrawable; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_blur_playback_controls, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + unbinder = ButterKnife.bind(this, view); + setUpMusicControllers(); + + mVolumeContainer.setVisibility(PreferenceUtil.getInstance(getContext()).getVolumeToggle() ? View.VISIBLE : View.GONE); + + VolumeFragment mVolumeFragment = (VolumeFragment) getChildFragmentManager().findFragmentById(R.id.volume_fragment); + mVolumeFragment.tintWhiteColor(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + title.setText(song.title); + text.setText(song.artistName); + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateShuffleState(); + updateSong(); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Override + public void setDark(int dark) { + lastPlaybackControlsColor = Color.WHITE; + lastDisabledPlaybackControlsColor = ContextCompat.getColor(getContext(), R.color.md_grey_500); + + setProgressBarColor(Color.WHITE); + + songCurrentProgress.setTextColor(lastPlaybackControlsColor); + songTotalTime.setTextColor(lastPlaybackControlsColor); + + updateRepeatState(); + updateShuffleState(); + updatePrevNextColor(); + } + + public void setProgressBarColor(int newColor) { + TintHelper.setTintAuto(progressSlider, newColor, false); + } + + private void setUpPlayPauseFab() { + final int fabColor = Color.WHITE; + TintHelper.setTintAuto(playPauseFab, fabColor, true); + + playerFabPlayPauseDrawable = new PlayPauseDrawable(getActivity()); + + playPauseFab.setImageDrawable(playerFabPlayPauseDrawable); // Note: set the drawable AFTER TintHelper.setTintAuto() was called + playPauseFab.setColorFilter(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(fabColor)), PorterDuff.Mode.SRC_IN); + playPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); + playPauseFab.post(() -> { + if (playPauseFab != null) { + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + } + }); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + playerFabPlayPauseDrawable.setPause(animate); + } else { + playerFabPlayPauseDrawable.setPlay(animate); + } + } + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + nextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + prevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + prevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpShuffleButton() { + shuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + protected void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpRepeatButton() { + repeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + + @Override + protected void show() { + playPauseFab.animate() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(new DecelerateInterpolator()) + .start(); + } + + @Override + protected void hide() { + if (playPauseFab != null) { + playPauseFab.setScaleX(0f); + playPauseFab.setScaleY(0f); + playPauseFab.setRotation(0f); + } + } + + @Override + protected void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + songTotalTime.setText(MusicUtil.getReadableDurationString(total)); + songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + } + + public void hideVolumeIfAvailable() { + mVolumeContainer.setVisibility(View.GONE); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlayerFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlayerFragment.java new file mode 100644 index 00000000..ddd9ed35 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlayerFragment.java @@ -0,0 +1,315 @@ +package code.name.monkey.retromusic.ui.fragments.player.blur; + +import android.app.Activity; +import android.graphics.Color; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator; +import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator; +import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager; +import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.adapter.song.PlayingQueueAdapter; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; +import code.name.monkey.retromusic.ui.fragments.player.normal.PlayerFragment; +import jp.wasabeef.glide.transformations.BlurTransformation; + +/** + * @author Hemanth S (h4h13). + */ + +public class BlurPlayerFragment extends AbsPlayerFragment implements PlayerAlbumCoverFragment.Callbacks { + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.toolbar_container) + View toolbarContainer; + @BindView(R.id.gradient_background) + ImageView colorBackground; + @BindView(R.id.status_bar) + View statusBar; + @Nullable + @BindView(R.id.recycler_view) + RecyclerView recyclerView; + @Nullable + @BindView(R.id.title) + TextView title; + + private int lastColor; + private BlurPlaybackControlsFragment playbackControlsFragment; + private Unbinder unbinder; + + private RecyclerView.Adapter wrappedAdapter; + private RecyclerViewDragDropManager recyclerViewDragDropManager; + private PlayingQueueAdapter playingQueueAdapter; + private LinearLayoutManager layoutManager; + + public static PlayerFragment newInstance() { + Bundle args = new Bundle(); + PlayerFragment fragment = new PlayerFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + @ColorInt + public int getPaletteColor() { + return lastColor; + } + + @Override + public void onShow() { + playbackControlsFragment.show(); + } + + @Override + public void onHide() { + playbackControlsFragment.hide(); + onBackPressed(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return Color.WHITE; + } + + @Override + public void onColorChanged(int color) { + playbackControlsFragment.setDark(color); + lastColor = color; + getCallbacks().onPaletteColorChanged(); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, Color.WHITE, getActivity()); + + if (title != null && playingQueueAdapter != null) { + if (ColorUtil.isColorLight(color)) { + title.setTextColor(Color.BLACK); + playingQueueAdapter.usePalette(false); + } else { + title.setTextColor(Color.WHITE); + playingQueueAdapter.usePalette(true); + } + } + } + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (recyclerViewDragDropManager != null) { + recyclerViewDragDropManager.release(); + recyclerViewDragDropManager = null; + } + + if (recyclerView != null) { + recyclerView.setItemAnimator(null); + recyclerView.setAdapter(null); + recyclerView = null; + } + + if (wrappedAdapter != null) { + WrapperAdapterUtils.releaseAll(wrappedAdapter); + wrappedAdapter = null; + } + playingQueueAdapter = null; + layoutManager = null; + super.onDestroyView(); + unbinder.unbind(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_blur, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + + setUpSubFragments(); + setUpPlayerToolbar(); + } + + private void setUpSubFragments() { + playbackControlsFragment = (BlurPlaybackControlsFragment) getChildFragmentManager() + .findFragmentById(R.id.playback_controls_fragment); + + PlayerAlbumCoverFragment playerAlbumCoverFragment = + (PlayerAlbumCoverFragment) getChildFragmentManager() + .findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, Color.WHITE, getActivity()); + } + + private void updateBlur() { + Activity activity = getActivity(); + if (activity == null) { + return; + } + + int blurAmount = PreferenceManager.getDefaultSharedPreferences(getContext()).getInt("blur_amount", 25); + + colorBackground.clearColorFilter(); + + SongGlideRequest.Builder.from(Glide.with(activity), MusicPlayerRemote.getCurrentSong()) + .checkIgnoreMediaStore(activity) + .generatePalette(activity) + .build() + .override(320, 480) + .transform(new BlurTransformation(getActivity(), blurAmount)) + .into(new RetroMusicColoredTarget(colorBackground) { + @Override + public void onColorReady(int color) { + if (color == getDefaultFooterColor()) { + colorBackground.setColorFilter(color); + } + } + }); + } + + @Override + public void onServiceConnected() { + updateIsFavorite(); + updateBlur(); + setUpRecyclerView(); + } + + @Override + public void onPlayingMetaChanged() { + updateIsFavorite(); + updateBlur(); + updateQueuePosition(); + } + + private void setUpRecyclerView() { + if (recyclerView != null) { + recyclerViewDragDropManager = new RecyclerViewDragDropManager(); + final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator(); + + playingQueueAdapter = new PlayingQueueAdapter( + (AppCompatActivity) getActivity(), + MusicPlayerRemote.getPlayingQueue(), + MusicPlayerRemote.getPosition(), + R.layout.item_song, + false, + null); + wrappedAdapter = recyclerViewDragDropManager.createWrappedAdapter(playingQueueAdapter); + + layoutManager = new LinearLayoutManager(getContext()); + + + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(wrappedAdapter); + recyclerView.setItemAnimator(animator); + recyclerViewDragDropManager.attachRecyclerView(recyclerView); + layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0); + } + } + + @Override + public void onQueueChanged() { + updateQueue(); + updateCurrentSong(); + } + + @Override + public void onMediaStoreChanged() { + updateQueue(); + updateCurrentSong(); + } + + @SuppressWarnings("ConstantConditions") + private void updateCurrentSong() { + } + + private void updateQueuePosition() { + if (playingQueueAdapter != null) { + playingQueueAdapter.setCurrent(MusicPlayerRemote.getPosition()); + // if (slidingUpPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) { + resetToCurrentPosition(); + //} + } + } + + private void updateQueue() { + if (playingQueueAdapter != null) { + playingQueueAdapter.swapDataSet(MusicPlayerRemote.getPlayingQueue(), MusicPlayerRemote.getPosition()); + resetToCurrentPosition(); + } + } + + private void resetToCurrentPosition() { + if (recyclerView != null) { + recyclerView.stopScroll(); + layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0); + } + + } + + @Override + public void onPause() { + if (recyclerViewDragDropManager != null) { + recyclerViewDragDropManager.cancelDrag(); + } + super.onPause(); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/card/CardFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/card/CardFragment.java new file mode 100644 index 00000000..355e9310 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/card/CardFragment.java @@ -0,0 +1,283 @@ +package code.name.monkey.retromusic.ui.fragments.player.card; + +import android.graphics.Color; +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator; +import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator; +import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager; +import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.adapter.song.PlayingQueueAdapter; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; +import code.name.monkey.retromusic.ui.fragments.player.normal.PlayerFragment; + +public class CardFragment extends AbsPlayerFragment implements PlayerAlbumCoverFragment.Callbacks { + + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.status_bar) + View statusBar; + @Nullable + @BindView(R.id.recycler_view) + RecyclerView recyclerView; + @Nullable + @BindView(R.id.title) + TextView title; + private RecyclerView.Adapter wrappedAdapter; + private RecyclerViewDragDropManager recyclerViewDragDropManager; + private PlayingQueueAdapter playingQueueAdapter; + private LinearLayoutManager layoutManager; + private int lastColor; + private CardPlaybackControlsFragment playbackControlsFragment; + private Unbinder unbinder; + + public static PlayerFragment newInstance() { + Bundle args = new Bundle(); + PlayerFragment fragment = new PlayerFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + @ColorInt + public int getPaletteColor() { + return lastColor; + } + + @Override + public void onShow() { + playbackControlsFragment.show(); + } + + @Override + public void onHide() { + playbackControlsFragment.hide(); + onBackPressed(); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return Color.WHITE; + } + + @Override + public void onColorChanged(int color) { + playbackControlsFragment.setDark(color); + lastColor = color; + getCallbacks().onPaletteColorChanged(); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, Color.WHITE, getActivity()); + + if (title != null && playingQueueAdapter != null) { + if (ColorUtil.isColorLight(color)) { + title.setTextColor(Color.BLACK); + playingQueueAdapter.usePalette(false); + } else { + title.setTextColor(Color.WHITE); + playingQueueAdapter.usePalette(true); + } + } + } + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (recyclerViewDragDropManager != null) { + recyclerViewDragDropManager.release(); + recyclerViewDragDropManager = null; + } + + if (recyclerView != null) { + recyclerView.setItemAnimator(null); + recyclerView.setAdapter(null); + recyclerView = null; + } + + if (wrappedAdapter != null) { + WrapperAdapterUtils.releaseAll(wrappedAdapter); + wrappedAdapter = null; + } + playingQueueAdapter = null; + layoutManager = null; + super.onDestroyView(); + unbinder.unbind(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_card_player, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + + setUpSubFragments(); + setUpPlayerToolbar(); + setUpRecyclerView(); + } + + private void setUpSubFragments() { + playbackControlsFragment = + (CardPlaybackControlsFragment) getChildFragmentManager() + .findFragmentById(R.id.playback_controls_fragment); + + PlayerAlbumCoverFragment playerAlbumCoverFragment = (PlayerAlbumCoverFragment) getChildFragmentManager() + .findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + playerAlbumCoverFragment.removeSlideEffect(); + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, Color.WHITE, getActivity()); + + } + + @Override + public void onServiceConnected() { + updateIsFavorite(); + //updateLyrics(); + setUpRecyclerView(); + } + + @Override + public void onPlayingMetaChanged() { + updateIsFavorite(); + //updateLyrics(); + updateQueuePosition(); + } + + private void setUpRecyclerView() { + if (recyclerView != null) { + recyclerViewDragDropManager = new RecyclerViewDragDropManager(); + final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator(); + + playingQueueAdapter = new PlayingQueueAdapter( + (AppCompatActivity) getActivity(), + MusicPlayerRemote.getPlayingQueue(), + MusicPlayerRemote.getPosition(), + R.layout.item_song, + false, + null); + wrappedAdapter = recyclerViewDragDropManager.createWrappedAdapter(playingQueueAdapter); + + layoutManager = new LinearLayoutManager(getContext()); + + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(wrappedAdapter); + recyclerView.setItemAnimator(animator); + recyclerViewDragDropManager.attachRecyclerView(recyclerView); + layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0); + } + } + + @Override + public void onQueueChanged() { + updateQueue(); + updateCurrentSong(); + } + + @Override + public void onMediaStoreChanged() { + updateQueue(); + updateCurrentSong(); + } + + @SuppressWarnings("ConstantConditions") + private void updateCurrentSong() { + } + + private void updateQueuePosition() { + if (playingQueueAdapter != null) { + playingQueueAdapter.setCurrent(MusicPlayerRemote.getPosition()); + } + // if (slidingUpPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) { + resetToCurrentPosition(); + //} + } + + private void updateQueue() { + if (playingQueueAdapter != null) { + playingQueueAdapter.swapDataSet(MusicPlayerRemote.getPlayingQueue(), + MusicPlayerRemote.getPosition()); + resetToCurrentPosition(); + } + } + + private void resetToCurrentPosition() { + if (recyclerView != null) { + recyclerView.stopScroll(); + layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0); + } + + } + + @Override + public void onPause() { + if (recyclerViewDragDropManager != null) { + recyclerViewDragDropManager.cancelDrag(); + } + + super.onPause(); + } + + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/card/CardPlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/card/CardPlaybackControlsFragment.java new file mode 100644 index 00000000..e92c885b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/card/CardPlaybackControlsFragment.java @@ -0,0 +1,358 @@ +package code.name.monkey.retromusic.ui.fragments.player.card; + +import android.animation.ObjectAnimator; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatSeekBar; +import android.support.v7.widget.AppCompatTextView; +import android.support.v7.widget.CardView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +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 code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.PlayPauseDrawable; + +public class CardPlaybackControlsFragment extends AbsPlayerControlsFragment { + @BindView(R.id.player_play_pause_button) + ImageButton playPauseButton; + @BindView(R.id.player_prev_button) + ImageButton prevButton; + @BindView(R.id.player_next_button) + ImageButton nextButton; + @BindView(R.id.player_repeat_button) + ImageButton repeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton shuffleButton; + @BindView(R.id.player_progress_slider) + AppCompatSeekBar progressSlider; + @BindView(R.id.player_song_total_time) + TextView songTotalTime; + @BindView(R.id.player_song_current_progress) + TextView songCurrentProgress; + @BindView(R.id.title) + AppCompatTextView title; + @BindView(R.id.text) + TextView text; + @BindView(R.id.volume_fragment_container) + View volumeContainer; + @BindView(R.id.menu) + View menuView; + @BindView(R.id.image_text_container) + CardView colorContainer; + + @BindView(R.id.image) + ImageView playImageView; + @BindView(R.id.playback_controls) + View playbackControls; + + private Unbinder unbinder; + private PlayPauseDrawable playPauseDrawable; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_card_player_playback_controls, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + unbinder = ButterKnife.bind(this, view); + setUpMusicControllers(); + + hideVolumeIfAvailable(); + + setupControls(); + } + + private void setupControls() { + playImageView.setImageResource(R.drawable.ic_play_circle_filled_white_24dp); + //noinspection ConstantConditions + int iconPadding = getActivity().getResources().getDimensionPixelSize(R.dimen.list_item_image_icon_padding); + playImageView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding); + + menuView.setVisibility(View.GONE); + + int primaryColor = ThemeStore.primaryColor(getContext()); + playbackControls.setBackgroundColor(primaryColor); + colorContainer.setCardBackgroundColor(primaryColor); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + title.setText(song.title); + text.setText(song.artistName); + + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateShuffleState(); + updateSong(); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Override + public void setDark(int dark) { + playImageView.setColorFilter(dark, PorterDuff.Mode.SRC_IN); + if (ColorUtil.isColorLight(ATHUtil.resolveColor(getContext(), android.R.attr.windowBackground))) { + lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(getActivity(), true); + lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(getActivity(), true); + } else { + lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(getActivity(), false); + lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(getActivity(), false); + } + + updateRepeatState(); + updateShuffleState(); + updatePrevNextColor(); + updatePlayPauseColor(); + updateProgressTextColor(); + + TintHelper.setTintAuto(playPauseButton, MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(dark)), false); + TintHelper.setTintAuto(playPauseButton, dark, true); + } + + private void updatePlayPauseColor() { + //playPauseButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpPlayPauseButton() { + playPauseDrawable = new PlayPauseDrawable(getActivity()); + playPauseButton.setImageDrawable(playPauseDrawable); + updatePlayPauseColor(); + playPauseButton.setOnClickListener(new PlayPauseButtonOnClickHandler()); + playPauseButton.post(() -> { + if (playPauseButton != null) { + playPauseButton.setPivotX(playPauseButton.getWidth() / 2); + playPauseButton.setPivotY(playPauseButton.getHeight() / 2); + } + }); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + playPauseDrawable.setPause(animate); + } else { + playPauseDrawable.setPlay(animate); + } + } + + private void setUpMusicControllers() { + setUpPlayPauseButton(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + nextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + prevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + prevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpShuffleButton() { + shuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + protected void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpRepeatButton() { + repeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void updateProgressTextColor() { + int color = MaterialValueHelper.getPrimaryTextColor(getContext(), false); + songTotalTime.setTextColor(color); + songCurrentProgress.setTextColor(color); + } + + @Override + protected void show() { + //Ignore + } + + @Override + protected void hide() { + //Ignore + } + + @Override + protected void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + } + + public void showBouceAnimation() { + playPauseButton.clearAnimation(); + + playPauseButton.setScaleX(0.9f); + playPauseButton.setScaleY(0.9f); + playPauseButton.setVisibility(View.VISIBLE); + playPauseButton.setPivotX(playPauseButton.getWidth() / 2); + playPauseButton.setPivotY(playPauseButton.getHeight() / 2); + + playPauseButton.animate() + .setDuration(200) + .setInterpolator(new DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(() -> playPauseButton.animate() + .setDuration(200) + .setInterpolator(new AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .start()) + .start(); + } + + @OnClick(R.id.player_play_pause_button) + void showAnimation() { + if (MusicPlayerRemote.isPlaying()) { + MusicPlayerRemote.pauseSong(); + } else { + MusicPlayerRemote.resumePlaying(); + } + showBouceAnimation(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + songTotalTime.setText(MusicUtil.getReadableDurationString(total)); + songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + } + + public void hideVolumeIfAvailable() { + volumeContainer.setVisibility(PreferenceUtil.getInstance(getContext()).getVolumeToggle() ? View.VISIBLE : View.GONE); + } + + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurFragment.java new file mode 100644 index 00000000..3d6e2436 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurFragment.java @@ -0,0 +1,192 @@ +package code.name.monkey.retromusic.ui.fragments.player.cardblur; + +import android.app.Activity; +import android.graphics.Color; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; +import code.name.monkey.retromusic.ui.fragments.player.normal.PlayerFragment; +import jp.wasabeef.glide.transformations.BlurTransformation; + +public class CardBlurFragment extends AbsPlayerFragment implements PlayerAlbumCoverFragment.Callbacks { + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.status_bar) + View statusBar; + @BindView(R.id.gradient_background) + ImageView colorBackground; + + private int lastColor; + private CardBlurPlaybackControlsFragment playbackControlsFragment; + private Unbinder unbinder; + + public static PlayerFragment newInstance() { + Bundle args = new Bundle(); + PlayerFragment fragment = new PlayerFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + @ColorInt + public int getPaletteColor() { + return lastColor; + } + + @Override + public void onShow() { + playbackControlsFragment.show(); + } + + @Override + public void onHide() { + playbackControlsFragment.hide(); + onBackPressed(); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return Color.WHITE; + } + + @Override + public void onColorChanged(int color) { + playbackControlsFragment.setDark(color); + lastColor = color; + getCallbacks().onPaletteColorChanged(); + ToolbarContentTintHelper.colorizeToolbar(toolbar, Color.WHITE, getActivity()); + } + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_card_blur_player, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + + setUpSubFragments(); + setUpPlayerToolbar(); + } + + private void setUpSubFragments() { + playbackControlsFragment = (CardBlurPlaybackControlsFragment) getChildFragmentManager() + .findFragmentById(R.id.playback_controls_fragment); + + PlayerAlbumCoverFragment playerAlbumCoverFragment = + (PlayerAlbumCoverFragment) getChildFragmentManager() + .findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + playerAlbumCoverFragment.removeEffect(); + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + + /* for (int i = 0; i < toolbar.getMenu().size(); i++) { + MenuItem menuItem = toolbar.getMenu().getItem(i); + menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + }*/ + ToolbarContentTintHelper.colorizeToolbar(toolbar, Color.WHITE, getActivity()); + } + + @Override + public void onServiceConnected() { + updateIsFavorite(); + updateBlur(); + } + + @Override + public void onPlayingMetaChanged() { + updateIsFavorite(); + updateBlur(); + } + + private void updateBlur() { + Activity activity = getActivity(); + if (activity == null) { + return; + } + int blurAmount = PreferenceManager.getDefaultSharedPreferences(getContext()).getInt("blur_amount", 25); + + colorBackground.clearColorFilter(); + SongGlideRequest.Builder.from(Glide.with(activity), MusicPlayerRemote.getCurrentSong()) + .checkIgnoreMediaStore(activity) + .generatePalette(activity) + .build() + .transform(new BlurTransformation(getActivity(), blurAmount)) + .into(new RetroMusicColoredTarget(colorBackground) { + @Override + public void onColorReady(int color) { + if (color == getDefaultFooterColor()) { + colorBackground.setColorFilter(color); + } + } + }); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurPlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurPlaybackControlsFragment.java new file mode 100644 index 00000000..a052d909 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurPlaybackControlsFragment.java @@ -0,0 +1,335 @@ +package code.name.monkey.retromusic.ui.fragments.player.cardblur; + +import android.animation.ObjectAnimator; +import android.content.res.ColorStateList; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatSeekBar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.VolumeFragment; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.PlayPauseDrawable; + +public class CardBlurPlaybackControlsFragment extends AbsPlayerControlsFragment { + @BindView(R.id.player_play_pause_button) + ImageButton playPauseFab; + @BindView(R.id.player_prev_button) + ImageButton prevButton; + @BindView(R.id.player_next_button) + ImageButton nextButton; + @BindView(R.id.player_repeat_button) + ImageButton repeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton shuffleButton; + @BindView(R.id.player_progress_slider) + AppCompatSeekBar progressSlider; + @BindView(R.id.player_song_total_time) + TextView songTotalTime; + @BindView(R.id.player_song_current_progress) + TextView songCurrentProgress; + @BindView(R.id.volume_fragment_container) + View volumeContainer; + @BindView(R.id.text) + TextView text; + @BindView(R.id.title) + TextView title; + private Unbinder unbinder; + private PlayPauseDrawable playerFabPlayPauseDrawable; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + title.setText(song.title); + text.setText(song.artistName); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_card_blur_player_playback_controls, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + unbinder = ButterKnife.bind(this, view); + setUpMusicControllers(); + hideVolumeIfAvailable(); + + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateSong(); + updateShuffleState(); + + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Override + public void setDark(int dark) { + + title.setTextColor(Color.WHITE); + text.setTextColor(Color.WHITE); + + lastPlaybackControlsColor = Color.WHITE; + lastDisabledPlaybackControlsColor = ColorUtil.withAlpha(Color.WHITE, 0.3f); + + updateRepeatState(); + updateShuffleState(); + updatePrevNextColor(); + updateProgressTextColor(); + } + + + private void setUpPlayPauseFab() { + final int fabColor = Color.WHITE; + TintHelper.setTintAuto(playPauseFab, fabColor, true); + + playerFabPlayPauseDrawable = new PlayPauseDrawable(getActivity()); + + playPauseFab.setImageDrawable(playerFabPlayPauseDrawable); // Note: set the drawable AFTER TintHelper.setTintAuto() was called + playPauseFab.setColorFilter(MaterialValueHelper.getPrimaryTextColor(getContext(), + ColorUtil.isColorLight(fabColor)), PorterDuff.Mode.SRC_IN); + playPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); + playPauseFab.post(() -> { + if (playPauseFab != null) { + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + } + }); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + playerFabPlayPauseDrawable.setPause(animate); + } else { + playerFabPlayPauseDrawable.setPlay(animate); + } + } + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + setupVolumeControls(); + } + + private void setupVolumeControls() { + VolumeFragment volumeFragment = (VolumeFragment) getChildFragmentManager() + .findFragmentById(R.id.volume_fragment); + volumeFragment.tintWhiteColor(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + nextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + prevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + prevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpShuffleButton() { + shuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + protected void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpRepeatButton() { + repeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void updateProgressTextColor() { + int color = MaterialValueHelper.getPrimaryTextColor(getContext(), false); + songTotalTime.setTextColor(color); + songCurrentProgress.setTextColor(color); + } + + @Override + protected void show() { + //Ignore + } + + @Override + protected void hide() { + //Ignore + } + + @Override + protected void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + progressSlider.setBackgroundTintList(ColorStateList.valueOf(Color.WHITE)); + } + + public void showBouceAnimation() { + playPauseFab.clearAnimation(); + + playPauseFab.setScaleX(0.9f); + playPauseFab.setScaleY(0.9f); + playPauseFab.setVisibility(View.VISIBLE); + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + + playPauseFab.animate() + .setDuration(200) + .setInterpolator(new DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(() -> playPauseFab.animate() + .setDuration(200) + .setInterpolator(new AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .start()) + .start(); + } + + @OnClick(R.id.player_play_pause_button) + void showAnimation() { + if (MusicPlayerRemote.isPlaying()) { + MusicPlayerRemote.pauseSong(); + } else { + MusicPlayerRemote.resumePlaying(); + } + showBouceAnimation(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + songTotalTime.setText(MusicUtil.getReadableDurationString(total)); + songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + } + + public void hideVolumeIfAvailable() { + volumeContainer.setVisibility(PreferenceUtil.getInstance(getContext()).getVolumeToggle() ? View.VISIBLE : View.GONE); + } + + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorFragment.java new file mode 100644 index 00000000..74d10fdf --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorFragment.java @@ -0,0 +1,305 @@ +package code.name.monkey.retromusic.ui.fragments.player.color; + +import android.animation.ArgbEvaluator; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.graphics.Palette; +import android.support.v7.widget.Toolbar; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +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.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.model.lyrics.Lyrics; +import code.name.monkey.retromusic.ui.activities.LyricsActivity; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.RetroColorUtil; +import code.name.monkey.retromusic.util.ViewUtil; + +public class ColorFragment extends AbsPlayerFragment { + + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.gradient_background) + View colorBackground; + @BindView(R.id.status_bar) + View statusBar; + @BindView(R.id.image) + ImageView imageView; + @BindView(R.id.lyrics) + TextView lyricsView; + @BindView(R.id.lyrics_container) + View lyricsViewContainer; + @BindView(R.id.album_cover_container) + View imageViewContainer; + + private int lastColor; + private int backgroundColor; + private ColorPlaybackControlsFragment playbackControlsFragment; + private Unbinder unbinder; + private ValueAnimator valueAnimator; + private AsyncTask updateLyricsAsyncTask; + private Lyrics lyrics; + + public static ColorFragment newInstance() { + Bundle args = new Bundle(); + ColorFragment fragment = new ColorFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onShow() { + playbackControlsFragment.show(); + } + + @Override + public void onHide() { + playbackControlsFragment.hide(); + onBackPressed(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + @ColorInt + public int getPaletteColor() { + return backgroundColor; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return lastColor; + } + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + if (valueAnimator != null) { + valueAnimator.cancel(); + valueAnimator = null; + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_color_player, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + + setUpSubFragments(); + setUpPlayerToolbar(); + } + + private void setUpSubFragments() { + playbackControlsFragment = (ColorPlaybackControlsFragment) + getChildFragmentManager().findFragmentById(R.id.playback_controls_fragment); + + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, + ATHUtil.resolveColor(getContext(), R.attr.iconColor), getActivity()); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + updateLyricsLocal(); + } + + @Override + public void onServiceConnected() { + super.onServiceConnected(); + updateSong(); + updateLyricsLocal(); + } + + private void updateSong() { + Activity activity = getActivity(); + + SongGlideRequest.Builder.from(Glide.with(activity), MusicPlayerRemote.getCurrentSong()) + .checkIgnoreMediaStore(activity) + .generatePalette(activity).build().dontAnimate() + .into(new RetroMusicColoredTarget(imageView) { + @Override + public void onColorReady(int color) { + //setColors(color); + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + + int backgroundColor = getDefaultFooterColor(); + int textColor = ColorUtil.isColorLight(getDefaultFooterColor()) ? + MaterialValueHelper.getPrimaryTextColor(getContext(), true) : + MaterialValueHelper.getPrimaryTextColor(getContext(), false); + + setColors(backgroundColor, textColor); + } + + @Override + public void onResourceReady(BitmapPaletteWrapper resource, + GlideAnimation glideAnimation) { + super.onResourceReady(resource, glideAnimation); + /* MediaNotificationProcessor processor = new MediaNotificationProcessor(getContext(), + getContext()); + Palette.Builder builder = MediaNotificationProcessor + .generatePalette(resource.getBitmap()); + + int backgroundColor = processor.getBackgroundColor(builder); + int textColor = processor.getTextColor(builder);*/ + + Palette palette = resource.getPalette(); + Palette.Swatch swatch = RetroColorUtil.getSwatch(palette); + + int textColor = RetroColorUtil.getTextColor(palette); + int backgroundColor = swatch.getRgb(); + + setColors(backgroundColor, textColor); + } + }); + } + + private void setColors(int backgroundColor, int textColor) { + playbackControlsFragment.setDark(textColor, backgroundColor); + + colorBackground.setBackgroundColor(backgroundColor); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, textColor, getActivity()); + + lastColor = textColor; + + this.backgroundColor = backgroundColor; + + getCallbacks().onPaletteColorChanged(); + } + + private void colorize(int i) { + if (valueAnimator != null) { + valueAnimator.cancel(); + } + + valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), Color.TRANSPARENT, i); + valueAnimator.addUpdateListener(animation -> { + if (colorBackground != null) { + colorBackground.setBackgroundColor((Integer) animation.getAnimatedValue()); + } + }); + valueAnimator.setDuration(ViewUtil.RETRO_MUSIC_ANIM_TIME).start(); + } + + @SuppressLint("StaticFieldLeak") + private void updateLyricsLocal() { + if (updateLyricsAsyncTask != null) { + updateLyricsAsyncTask.cancel(false); + } + final Song song = MusicPlayerRemote.getCurrentSong(); + updateLyricsAsyncTask = new AsyncTask() { + @Override + protected void onPreExecute() { + super.onPreExecute(); + lyrics = null; + toolbar.getMenu().removeItem(R.id.action_show_lyrics); + } + + @Override + protected Lyrics doInBackground(Void... params) { + String data = MusicUtil.getLyrics(song); + if (TextUtils.isEmpty(data)) { + return null; + } + return Lyrics.parse(song, data); + } + + @Override + protected void onPostExecute(Lyrics l) { + lyrics = l; + if (lyrics == null) { + lyricsView.setText(R.string.no_lyrics_found); + } else { + lyricsView.setText(lyrics.getText()); + } + } + + @Override + protected void onCancelled(Lyrics s) { + onPostExecute(null); + } + }.execute(); + } + + @OnClick(R.id.expand) + void expand() { + startActivity(new Intent(getContext(), LyricsActivity.class)); + } + + @OnClick({R.id.lyrics, R.id.image}) + void toggleLyrics(View view) { + if (lyricsViewContainer.getVisibility() == View.GONE) { + lyricsViewContainer.setVisibility(View.VISIBLE); + } else { + lyricsViewContainer.setVisibility(View.GONE); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorPlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorPlaybackControlsFragment.java new file mode 100644 index 00000000..7efff6ff --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorPlaybackControlsFragment.java @@ -0,0 +1,348 @@ +package code.name.monkey.retromusic.ui.fragments.player.color; + +import android.animation.ObjectAnimator; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatSeekBar; +import android.support.v7.widget.AppCompatTextView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.VolumeFragment; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.PlayPauseDrawable; + +public class ColorPlaybackControlsFragment extends AbsPlayerControlsFragment { + + @BindView(R.id.player_play_pause_button) + ImageButton playPauseFab; + @BindView(R.id.player_prev_button) + ImageButton prevButton; + @BindView(R.id.player_next_button) + ImageButton nextButton; + @BindView(R.id.player_repeat_button) + ImageButton repeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton shuffleButton; + @BindView(R.id.player_progress_slider) + AppCompatSeekBar progressSlider; + @BindView(R.id.player_song_total_time) + TextView songTotalTime; + @BindView(R.id.player_song_current_progress) + TextView songCurrentProgress; + @BindView(R.id.title) + AppCompatTextView title; + @BindView(R.id.text) + TextView text; + @BindView(R.id.volume_fragment_container) + View volumeContainer; + + private Unbinder unbinder; + private PlayPauseDrawable playerFabPlayPauseDrawable; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + private VolumeFragment volumeFragment; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_color_player_playback_controls, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + unbinder = ButterKnife.bind(this, view); + setUpMusicControllers(); + + if (PreferenceUtil.getInstance(getContext()).getVolumeToggle()) { + volumeContainer.setVisibility(View.VISIBLE); + } else { + volumeContainer.setVisibility(View.GONE); + } + + volumeFragment = (VolumeFragment) getChildFragmentManager().findFragmentById(R.id.volume_fragment); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + title.setText(song.title); + text.setText(song.artistName); + + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateShuffleState(); + updateSong(); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + + public void setDark(int textColor, int background) { + setDark(textColor); + TintHelper.setTintAuto(playPauseFab, background, false); + TintHelper.setTintAuto(playPauseFab, textColor, true); + } + + @Override + public void setDark(int color) { + lastPlaybackControlsColor = color; + lastDisabledPlaybackControlsColor = ColorUtil.withAlpha(color, 0.5f); + + title.setTextColor(lastPlaybackControlsColor); + text.setTextColor(lastDisabledPlaybackControlsColor); + + TintHelper.setTintAuto(progressSlider, lastPlaybackControlsColor, false); + + volumeFragment.setTintable(lastPlaybackControlsColor); + + songCurrentProgress.setTextColor(lastDisabledPlaybackControlsColor); + songTotalTime.setTextColor(lastDisabledPlaybackControlsColor); + + updateRepeatState(); + updateShuffleState(); + updatePrevNextColor(); + } + + + private void setUpPlayPauseFab() { + playerFabPlayPauseDrawable = new PlayPauseDrawable(getActivity()); + + playPauseFab.setImageDrawable(playerFabPlayPauseDrawable); // Note: set the drawable AFTER TintHelper.setTintAuto() was called + playPauseFab.setColorFilter(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(Color.BLACK)), PorterDuff.Mode.SRC_IN); + //playPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); + playPauseFab.post(() -> { + if (playPauseFab != null) { + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + } + }); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + playerFabPlayPauseDrawable.setPause(animate); + } else { + playerFabPlayPauseDrawable.setPlay(animate); + } + } + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + nextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + prevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + prevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpShuffleButton() { + shuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + protected void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpRepeatButton() { + repeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + + @Override + protected void show() { + playPauseFab.animate() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(new DecelerateInterpolator()) + .start(); + } + + @Override + protected void hide() { + if (playPauseFab != null) { + playPauseFab.setScaleX(0f); + playPauseFab.setScaleY(0f); + playPauseFab.setRotation(0f); + } + } + + @Override + protected void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + } + + public void showBouceAnimation() { + playPauseFab.clearAnimation(); + + playPauseFab.setScaleX(0.9f); + playPauseFab.setScaleY(0.9f); + playPauseFab.setVisibility(View.VISIBLE); + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + + playPauseFab.animate() + .setDuration(200) + .setInterpolator(new DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(() -> playPauseFab.animate() + .setDuration(200) + .setInterpolator(new AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .start()) + .start(); + } + + @OnClick(R.id.player_play_pause_button) + void showAnimation() { + if (MusicPlayerRemote.isPlaying()) { + MusicPlayerRemote.pauseSong(); + } else { + MusicPlayerRemote.resumePlaying(); + } + showBouceAnimation(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + songTotalTime.setText(MusicUtil.getReadableDurationString(total)); + songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + } + + public void hideVolumeIfAvailable() { + volumeContainer.setVisibility(PreferenceUtil.getInstance(getContext()).getVolumeToggle() ? View.VISIBLE : View.GONE); + } + + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlaybackControlsFragment.java new file mode 100644 index 00000000..4c7b20fb --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlaybackControlsFragment.java @@ -0,0 +1,300 @@ +package code.name.monkey.retromusic.ui.fragments.player.flat; + +import android.animation.ObjectAnimator; +import android.graphics.PorterDuff; +import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +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 code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback; +import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.base.AbsMusicServiceFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.PlayPauseDrawable; + +public class FlatPlaybackControlsFragment extends AbsMusicServiceFragment implements Callback { + + @BindView(R.id.text) + TextView mText; + @BindView(R.id.title) + TextView mTitle; + @BindView(R.id.playback_controls) + ViewGroup viewGroup; + @BindView(R.id.player_song_total_time) + TextView mSongTotalTime; + @BindView(R.id.player_song_current_progress) + TextView mPlayerSongCurrentProgress; + @BindView(R.id.player_repeat_button) + ImageButton mPlayerRepeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton mPlayerShuffleButton; + @BindView(R.id.player_play_pause_button) + ImageView mPlayerPlayPauseFab; + Unbinder unbinder; + @BindView(R.id.player_progress_slider) + SeekBar progressSlider; + @BindView(R.id.volume_fragment_container) + View mVolumeContainer; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + private PlayPauseDrawable playerFabPlayPauseDrawable; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_flat_player_playback_controls, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setUpMusicControllers(); + + mVolumeContainer.setVisibility(PreferenceUtil.getInstance(getContext()).getVolumeToggle() ? View.VISIBLE : View.GONE); + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + mPlayerSongCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + mSongTotalTime.setText(MusicUtil.getReadableDurationString(total)); + } + + + public void show() { + mPlayerPlayPauseFab.animate() + .scaleX(1f) + .scaleY(1f) + .setInterpolator(new DecelerateInterpolator()) + .start(); + } + + + public void hide() { + if (mPlayerPlayPauseFab != null) { + mPlayerPlayPauseFab.setScaleX(0f); + mPlayerPlayPauseFab.setScaleY(0f); + mPlayerPlayPauseFab.setRotation(0f); + } + } + + public void setDark(int dark) { + int color = ATHUtil.resolveColor(getActivity(), android.R.attr.colorBackground); + boolean isDark = ColorUtil.isColorLight(color); + if (isDark) { + lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(getActivity(), true); + lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(getActivity(), true); + } else { + lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(getActivity(), false); + lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(getActivity(), false); + } + int accentColor = ThemeStore.accentColor(getContext()); + boolean b = PreferenceUtil.getInstance(getContext()).getAdaptiveColor(); + updateTextColors(b ? dark : accentColor); + setProgressBarColor(b ? dark : accentColor); + + + updateRepeatState(); + updateShuffleState(); + } + + private void setProgressBarColor(int dark) { + TintHelper.setTintAuto(progressSlider, dark, false); + //LayerDrawable ld = (LayerDrawable) progressSlider.getProgressDrawable(); + //ClipDrawable clipDrawable = (ClipDrawable) ld.findDrawableByLayerId(android.R.id.progress); + //clipDrawable.setColorFilter(dark, PorterDuff.Mode.SRC_IN); + } + + private void updateTextColors(int color) { + boolean isDark = ColorUtil.isColorLight(color); + int darkColor = ColorUtil.darkenColor(color); + int colorPrimary = MaterialValueHelper.getPrimaryTextColor(getContext(), isDark); + int colorSecondary = MaterialValueHelper.getSecondaryTextColor(getContext(), ColorUtil.isColorLight(darkColor)); + + TintHelper.setTintAuto(mPlayerPlayPauseFab, colorPrimary, false); + TintHelper.setTintAuto(mPlayerPlayPauseFab, color, true); + + mTitle.setBackgroundColor(color); + mTitle.setTextColor(colorPrimary); + mText.setBackgroundColor(darkColor); + mText.setTextColor(colorSecondary); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateShuffleState(); + updateSong(); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + playerFabPlayPauseDrawable.setPause(animate); + } else { + playerFabPlayPauseDrawable.setPlay(animate); + } + } + + private void setUpPlayPauseFab() { + playerFabPlayPauseDrawable = new PlayPauseDrawable(getActivity()); + + mPlayerPlayPauseFab.setImageDrawable( + playerFabPlayPauseDrawable); // Note: set the drawable AFTER TintHelper.setTintAuto() was called + //playPauseFab.setColorFilter(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(fabColor)), PorterDuff.Mode.SRC_IN); + mPlayerPlayPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); + mPlayerPlayPauseFab.post(() -> { + if (mPlayerPlayPauseFab != null) { + mPlayerPlayPauseFab.setPivotX(mPlayerPlayPauseFab.getWidth() / 2); + mPlayerPlayPauseFab.setPivotY(mPlayerPlayPauseFab.getHeight() / 2); + } + }); + } + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + private void updateSong() { + //TransitionManager.beginDelayedTransition(viewGroup, new ChangeText().setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT_IN)); + Song song = MusicPlayerRemote.getCurrentSong(); + mTitle.setText(song.title); + mText.setText(song.artistName); + + } + + private void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), + MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + private void setUpRepeatButton() { + mPlayerRepeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + private void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + mPlayerRepeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + mPlayerRepeatButton + .setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + mPlayerRepeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + mPlayerRepeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + mPlayerRepeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + mPlayerRepeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpShuffleButton() { + mPlayerShuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + private void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + mPlayerShuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + mPlayerShuffleButton + .setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlayerFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlayerFragment.java new file mode 100644 index 00000000..256e3f38 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlayerFragment.java @@ -0,0 +1,174 @@ +package code.name.monkey.retromusic.ui.fragments.player.flat; + +import android.animation.ArgbEvaluator; +import android.animation.ValueAnimator; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +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.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.ViewUtil; +import code.name.monkey.retromusic.views.DrawableGradient; + +public class FlatPlayerFragment extends AbsPlayerFragment implements + PlayerAlbumCoverFragment.Callbacks { + + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.gradient_background) + View colorBackground; + @BindView(R.id.toolbar_container) + FrameLayout toolbarContainer; + @BindView(R.id.status_bar) + View statusBar; + + private Unbinder unbinder; + private ValueAnimator valueAnimator; + private FlatPlaybackControlsFragment flatPlaybackControlsFragment; + private int lastColor; + + private void setUpSubFragments() { + flatPlaybackControlsFragment = (FlatPlaybackControlsFragment) + getChildFragmentManager().findFragmentById(R.id.playback_controls_fragment); + + PlayerAlbumCoverFragment playerAlbumCoverFragment = (PlayerAlbumCoverFragment) + getChildFragmentManager().findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, ATHUtil.resolveColor(getContext(), + R.attr.iconColor), getActivity()); + } + + private void colorize(int i) { + if (valueAnimator != null) { + valueAnimator.cancel(); + } + + valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), android.R.color.transparent, i); + valueAnimator.addUpdateListener(animation -> { + GradientDrawable drawable = new DrawableGradient(GradientDrawable.Orientation.TOP_BOTTOM, + new int[]{(int) animation.getAnimatedValue(), android.R.color.transparent}, 0); + if (colorBackground != null) { + colorBackground.setBackground(drawable); + } + }); + valueAnimator.setDuration(ViewUtil.RETRO_MUSIC_ANIM_TIME).start(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_flat_player, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + + setUpPlayerToolbar(); + setUpSubFragments(); + + } + + @Override + public int getPaletteColor() { + return lastColor; + } + + @Override + public void onShow() { + flatPlaybackControlsFragment.show(); + } + + @Override + public void onHide() { + flatPlaybackControlsFragment.hide(); + onBackPressed(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + boolean isLight = ColorUtil.isColorLight(lastColor); + return PreferenceUtil.getInstance(getContext()).getAdaptiveColor() ? + MaterialValueHelper.getPrimaryTextColor(getContext(), isLight) : + ATHUtil.resolveColor(getContext(), R.attr.iconColor); + } + + @Override + public void onColorChanged(int color) { + lastColor = color; + flatPlaybackControlsFragment.setDark(color); + getCallbacks().onPaletteColorChanged(); + + boolean isLight = ColorUtil.isColorLight(color); + + //TransitionManager.beginDelayedTransition(mToolbar); + int iconColor = PreferenceUtil.getInstance(getContext()).getAdaptiveColor() ? + MaterialValueHelper.getPrimaryTextColor(getContext(), isLight) : + ATHUtil.resolveColor(getContext(), R.attr.iconColor); + ToolbarContentTintHelper.colorizeToolbar(toolbar, iconColor, getActivity()); + if (PreferenceUtil.getInstance(getContext()).getAdaptiveColor()) { + colorize(color); + } + } + + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/full/FullPlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/full/FullPlaybackControlsFragment.java new file mode 100644 index 00000000..6eb93e4a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/full/FullPlaybackControlsFragment.java @@ -0,0 +1,301 @@ +package code.name.monkey.retromusic.ui.fragments.player.full; + +import android.animation.ObjectAnimator; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.VolumeFragment; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * Created by hemanths on 20/09/17. + */ + +public class FullPlaybackControlsFragment extends AbsPlayerControlsFragment { + @BindView(R.id.player_song_current_progress) + TextView mPlayerSongCurrentProgress; + @BindView(R.id.player_song_total_time) + TextView songTotalTime; + @BindView(R.id.player_progress_slider) + SeekBar progressSlider; + @BindView(R.id.player_prev_button) + ImageButton playerPrevButton; + @BindView(R.id.player_next_button) + ImageButton playerNextButton; + @BindView(R.id.player_repeat_button) + ImageButton playerRepeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton playerShuffleButton; + @BindView(R.id.player_play_pause_button) + ImageButton playerPlayPauseFab; + Unbinder unbinder; + @BindView(R.id.title) + TextView mTitle; + @BindView(R.id.text) + TextView mText; + @BindView(R.id.volume_fragment_container) + View mVolumeContainer; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_full_player_controls, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + setUpMusicControllers(); + + mVolumeContainer.setVisibility(PreferenceUtil.getInstance(getContext()).getVolumeToggle() ? View.VISIBLE : View.GONE); + VolumeFragment volumeFragment = (VolumeFragment) getChildFragmentManager().findFragmentById(R.id.volume_fragment); + volumeFragment.tintWhiteColor(); + + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + mPlayerSongCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + songTotalTime.setText(MusicUtil.getReadableDurationString(total)); + } + + + public void show() { + playerPlayPauseFab.animate() + .scaleX(1f) + .scaleY(1f) + .setInterpolator(new DecelerateInterpolator()) + .start(); + } + + + public void hide() { + if (playerPlayPauseFab != null) { + playerPlayPauseFab.setScaleX(0f); + playerPlayPauseFab.setScaleY(0f); + playerPlayPauseFab.setRotation(0f); + } + } + + public void setDark(int dark) { + lastPlaybackControlsColor = Color.WHITE; + lastDisabledPlaybackControlsColor = ContextCompat.getColor(getContext(), R.color.md_grey_500); + + if (PreferenceUtil.getInstance(getContext()).getAdaptiveColor()) { + setProgressBarColor(dark); + } else { + int accentColor = ThemeStore.accentColor(getContext()); + setProgressBarColor(accentColor); + } + + updateRepeatState(); + updateShuffleState(); + updatePrevNextColor(); + updateProgressTextColor(); + } + + private void setProgressBarColor(int dark) { + LayerDrawable ld = (LayerDrawable) progressSlider.getProgressDrawable(); + ClipDrawable clipDrawable = (ClipDrawable) ld.findDrawableByLayerId(android.R.id.progress); + clipDrawable.setColorFilter(dark, PorterDuff.Mode.SRC_IN); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateShuffleState(); + updateSong(); + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + mTitle.setText(song.title); + mText.setText(song.artistName); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + + if (MusicPlayerRemote.isPlaying()) { + playerPlayPauseFab.setImageResource(R.drawable.ic_pause_white_24dp); + } else { + playerPlayPauseFab.setImageResource(R.drawable.ic_play_arrow_white_24dp); + } + } + + private void setUpPlayPauseFab() { + + playerPlayPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); + playerPlayPauseFab.post(() -> { + if (playerPlayPauseFab != null) { + playerPlayPauseFab.setPivotX(playerPlayPauseFab.getWidth() / 2); + playerPlayPauseFab.setPivotY(playerPlayPauseFab.getHeight() / 2); + } + }); + } + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + playerNextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + playerPrevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updateProgressTextColor() { + int color = MaterialValueHelper.getSecondaryTextColor(getContext(), false); + //songTotalTime.setTextColor(color); + //songCurrentProgress.setTextColor(color); + } + + private void updatePrevNextColor() { + playerNextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + playerPrevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + @Override + protected void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + } + + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + private void setUpRepeatButton() { + playerRepeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + playerRepeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + playerRepeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + playerRepeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + playerRepeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + playerRepeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + playerRepeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpShuffleButton() { + playerShuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + public void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + playerShuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + playerShuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/full/FullPlayerFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/full/FullPlayerFragment.java new file mode 100644 index 00000000..cb1e0d22 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/full/FullPlayerFragment.java @@ -0,0 +1,123 @@ +package code.name.monkey.retromusic.ui.fragments.player.full; + +import android.graphics.Color; +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; + +public class FullPlayerFragment extends AbsPlayerFragment implements PlayerAlbumCoverFragment.Callbacks { + @BindView(R.id.player_toolbar) + Toolbar toolbar; + + Unbinder unbinder; + + private int lastColor; + private FullPlaybackControlsFragment fullPlaybackControlsFragment; + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationIcon(R.drawable.ic_close_white_24dp); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_full, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + setUpSubFragments(); + setUpPlayerToolbar(); + } + + private void setUpSubFragments() { + fullPlaybackControlsFragment = (FullPlaybackControlsFragment) + getChildFragmentManager().findFragmentById(R.id.playback_controls_fragment); + + PlayerAlbumCoverFragment playerAlbumCoverFragment = (PlayerAlbumCoverFragment) + getChildFragmentManager().findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + playerAlbumCoverFragment.removeSlideEffect(); + } + + @Override + @ColorInt + public int getPaletteColor() { + return lastColor; + } + + @Override + public void onShow() { + + } + + @Override + public void onHide() { + + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return Color.WHITE; + } + + @Override + public void onColorChanged(int color) { + lastColor = color; + fullPlaybackControlsFragment.setDark(color); + getCallbacks().onPaletteColorChanged(); + ToolbarContentTintHelper.colorizeToolbar(toolbar, Color.WHITE, getActivity()); + } + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/hmm/HmmPlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/hmm/HmmPlaybackControlsFragment.java new file mode 100644 index 00000000..3bb3cff3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/hmm/HmmPlaybackControlsFragment.java @@ -0,0 +1,144 @@ +package code.name.monkey.retromusic.ui.fragments.player.hmm; + +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; + +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; + +/** + * @author Hemanth S (h4h13). + */ + +public class HmmPlaybackControlsFragment extends AbsPlayerControlsFragment { + @BindView(R.id.player_repeat_button) + ImageButton repeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton shuffleButton; + private Unbinder unbinder; + private int mLastPlaybackControlsColor; + private int mLastDisabledPlaybackControlsColor; + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_hmm_controls_fragment, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setUpMusicControllers(); + } + + private void setUpMusicControllers() { + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + @Override + protected void show() { + + } + + @Override + protected void hide() { + + } + + private void setUpShuffleButton() { + shuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + protected void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setColorFilter(mLastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + shuffleButton.setColorFilter(mLastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpRepeatButton() { + repeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(mLastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(mLastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + repeatButton.setColorFilter(mLastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + @Override + protected void setUpProgressSlider() { + + } + + @Override + public void setDark(int dark) { + if (ColorUtil.isColorLight(dark)) { + mLastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(getActivity(), true); + mLastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(getActivity(), true); + } else { + mLastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(getActivity(), false); + mLastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(getActivity(), false); + } + + updateRepeatState(); + updateShuffleState(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/hmm/HmmPlayerFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/hmm/HmmPlayerFragment.java new file mode 100644 index 00000000..bdd890ae --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/hmm/HmmPlayerFragment.java @@ -0,0 +1,220 @@ +package code.name.monkey.retromusic.ui.fragments.player.hmm; + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.LinearInterpolator; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.afollestad.materialdialogs.internal.MDTintHelper; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.fragments.MiniPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * @author Hemanth S (h4h13). + */ + +public class HmmPlayerFragment extends AbsPlayerFragment implements + MusicProgressViewUpdateHelper.Callback, PlayerAlbumCoverFragment.Callbacks { + + @BindView(R.id.title) + TextView title; + @BindView(R.id.text) + TextView text; + @BindView(R.id.player_song_total_time) + TextView totalTime; + @BindView(R.id.progress_bar) + ProgressBar progressBar; + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.status_bar) + View statusBar; + + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + private Unbinder unBinder; + private int lastColor; + private HmmPlaybackControlsFragment hmmPlaybackControlsFragment; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + title.setText(song.title); + text.setText(String.format("%s \nby -%s", song.albumName, song.artistName)); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unBinder.unbind(); + + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_hmm_player, container, false); + unBinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + + progressBar.setOnClickListener(new PlayPauseButtonOnClickHandler()); + progressBar.setOnTouchListener(new MiniPlayerFragment.FlingPlayBackController(getActivity())); + + setUpPlayerToolbar(); + setUpSubFragments(); + } + + private void setUpSubFragments() { + hmmPlaybackControlsFragment = (HmmPlaybackControlsFragment) getChildFragmentManager() + .findFragmentById(R.id.playback_controls_fragment); + PlayerAlbumCoverFragment playerAlbumCoverFragment = (PlayerAlbumCoverFragment) getChildFragmentManager() + .findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + + } + + @Override + public int getPaletteColor() { + return lastColor; + } + + @Override + public void onShow() { + hmmPlaybackControlsFragment.show(); + } + + @Override + public void onHide() { + hmmPlaybackControlsFragment.hide(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return MaterialValueHelper + .getSecondaryTextColor(getContext(), ColorUtil.isColorLight(lastColor)); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressBar.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressBar, "progress", progress); + + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playSequentially(animator); + + animatorSet.setDuration(1500); + animatorSet.setInterpolator(new LinearInterpolator()); + animatorSet.start(); + + totalTime.setText(String.format("%s/%s", MusicUtil.getReadableDurationString(total), + MusicUtil.getReadableDurationString(progress))); + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + } + + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + @Override + public void onServiceConnected() { + super.onServiceConnected(); + updateSong(); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + @Override + public void onColorChanged(int color) { + lastColor = PreferenceUtil.getInstance(getContext()).getAdaptiveColor() ? color : + ThemeStore.accentColor(getContext()); + getCallbacks().onPaletteColorChanged(); + hmmPlaybackControlsFragment.setDark(lastColor); + setProgressBarColor(lastColor); + + int iconColor = MaterialValueHelper + .getSecondaryTextColor(getContext(), ColorUtil.isColorLight(lastColor)); + ToolbarContentTintHelper.colorizeToolbar(toolbar, iconColor, getActivity()); + } + + private void setProgressBarColor(int color) { + MDTintHelper.setTint(progressBar, color); + } + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/lockscreen/LockScreenPlayerControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/lockscreen/LockScreenPlayerControlsFragment.java new file mode 100644 index 00000000..8acfdd47 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/lockscreen/LockScreenPlayerControlsFragment.java @@ -0,0 +1,294 @@ +package code.name.monkey.retromusic.ui.fragments.player.lockscreen; + +import android.animation.ObjectAnimator; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatImageButton; +import android.support.v7.widget.AppCompatSeekBar; +import android.support.v7.widget.AppCompatTextView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.fragments.VolumeFragment; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; + +/** + * @author Hemanth S (h4h13). + */ +public class LockScreenPlayerControlsFragment extends AbsPlayerControlsFragment { + @BindView(R.id.player_play_pause_button) + AppCompatImageButton playPauseFab; + @BindView(R.id.player_prev_button) + ImageButton prevButton; + @BindView(R.id.player_next_button) + ImageButton nextButton; + @BindView(R.id.player_progress_slider) + AppCompatSeekBar progressSlider; + @BindView(R.id.player_song_total_time) + TextView songTotalTime; + @BindView(R.id.player_song_current_progress) + TextView songCurrentProgress; + @BindView(R.id.title) + AppCompatTextView title; + @BindView(R.id.text) + AppCompatTextView text; + + private Unbinder unbinder; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + private int lastPlaybackControlsColor; + + public LockScreenPlayerControlsFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_lock_screen_playback_controls, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setUpMusicControllers(); + + VolumeFragment volumeFragment = (VolumeFragment) getChildFragmentManager().findFragmentById(R.id.volume_fragment); + + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + + title.setText(song.title); + text.setText(String.format("%s - %s", song.artistName, song.albumName)); + + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateShuffleState(); + updateSong(); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Override + public void setDark(int dark) { + setProgressBarColor(progressSlider, dark); + + if (ColorUtil.isColorLight(ATHUtil.resolveColor(getContext(), android.R.attr.windowBackground))) { + lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(getActivity(), true); + } else { + lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(getActivity(), false); + + } + + updatePrevNextColor(); + + boolean isDark = ColorUtil.isColorLight(dark); + text.setTextColor(dark); + TintHelper.setTintAuto(playPauseFab, MaterialValueHelper.getPrimaryTextColor(getContext(), isDark), false); + TintHelper.setTintAuto(playPauseFab, dark, true); + } + + public void setProgressBarColor(SeekBar progressBar, int newColor) { + TintHelper.setTintAuto(progressBar, newColor, false); + //LayerDrawable ld = (LayerDrawable) progressBar.getProgressDrawable(); + //ClipDrawable clipDrawable = (ClipDrawable) ld.findDrawableByLayerId(android.R.id.progress); + //clipDrawable.setColorFilter(newColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpPlayPauseFab() { + playPauseFab.post(() -> { + if (playPauseFab != null) { + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + } + }); + } + + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpPrevNext(); + setUpProgressSlider(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + nextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + prevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + prevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + @Override + protected void show() { + playPauseFab.animate() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(new DecelerateInterpolator()) + .start(); + } + + @Override + protected void hide() { + if (playPauseFab != null) { + playPauseFab.setScaleX(0f); + playPauseFab.setScaleY(0f); + playPauseFab.setRotation(0f); + } + } + + @Override + protected void updateShuffleState() { + //TODO(Nothing to Implement) + } + + @Override + protected void updateRepeatState() { + //TODO(Nothing to Implement) + } + + @Override + protected void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), + MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + } + + public void showBouceAnimation() { + playPauseFab.clearAnimation(); + + playPauseFab.setScaleX(0.9f); + playPauseFab.setScaleY(0.9f); + playPauseFab.setVisibility(View.VISIBLE); + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + + playPauseFab.animate() + .setDuration(200) + .setInterpolator(new DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(() -> playPauseFab.animate() + .setDuration(200) + .setInterpolator(new AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .start()) + .start(); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + playPauseFab.setImageResource(R.drawable.ic_pause_white_24dp); + } else { + playPauseFab.setImageResource(R.drawable.ic_play_arrow_white_24dp); + } + } + + @OnClick(R.id.player_play_pause_button) + void showAnimation() { + if (MusicPlayerRemote.isPlaying()) { + MusicPlayerRemote.pauseSong(); + } else { + MusicPlayerRemote.resumePlaying(); + } + showBouceAnimation(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + songTotalTime.setText(MusicUtil.getReadableDurationString(total)); + songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialControlsFragment.java new file mode 100644 index 00000000..a2425edb --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialControlsFragment.java @@ -0,0 +1,273 @@ +package code.name.monkey.retromusic.ui.fragments.player.material; + +import android.animation.ObjectAnimator; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatSeekBar; +import android.support.v7.widget.AppCompatTextView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +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.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * @author Hemanth S (h4h13). + */ +public class MaterialControlsFragment extends AbsPlayerControlsFragment { + + @BindView(R.id.player_play_pause_button) + ImageButton playPauseFab; + @BindView(R.id.player_prev_button) + ImageButton prevButton; + @BindView(R.id.player_next_button) + ImageButton nextButton; + @BindView(R.id.player_repeat_button) + ImageButton repeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton shuffleButton; + @BindView(R.id.player_progress_slider) + AppCompatSeekBar progressSlider; + @BindView(R.id.player_song_total_time) + TextView songTotalTime; + @BindView(R.id.player_song_current_progress) + TextView songCurrentProgress; + @BindView(R.id.title) + AppCompatTextView title; + @BindView(R.id.text) + TextView text; + @BindView(R.id.volume_fragment_container) + View mVolumeContainer; + private Unbinder unbinder; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_material_playback_controls, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + unbinder = ButterKnife.bind(this, view); + setUpMusicControllers(); + + if (PreferenceUtil.getInstance(getContext()).getVolumeToggle()) { + mVolumeContainer.setVisibility(View.VISIBLE); + } else { + mVolumeContainer.setVisibility(View.GONE); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + title.setText(song.title); + text.setText(song.artistName); + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(); + updateRepeatState(); + updateShuffleState(); + updateSong(); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Override + public void setDark(int dark) { + int color = ATHUtil.resolveColor(getActivity(), android.R.attr.colorBackground); + if (ColorUtil.isColorLight(color)) { + lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(getActivity(), true); + lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(getActivity(), true); + } else { + lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(getActivity(), false); + lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(getActivity(), false); + } + + updatePlayPauseColor(); + updateRepeatState(); + updateShuffleState(); + updatePrevNextColor(); + } + + private void setUpPlayPauseFab() { + playPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); + } + + protected void updatePlayPauseDrawableState() { + if (MusicPlayerRemote.isPlaying()) { + playPauseFab.setImageResource(R.drawable.ic_pause_white_big); + } else { + playPauseFab.setImageResource(R.drawable.ic_play_arrow_white_big); + } + } + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + nextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + prevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + prevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void updatePlayPauseColor() { + playPauseFab.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpShuffleButton() { + shuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + protected void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpRepeatButton() { + repeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + @Override + protected void show() { + + } + + @Override + protected void hide() { + + } + + @Override + protected void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), + MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + songTotalTime.setText(MusicUtil.getReadableDurationString(total)); + songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialFragment.java new file mode 100644 index 00000000..a78c799b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialFragment.java @@ -0,0 +1,153 @@ +package code.name.monkey.retromusic.ui.fragments.player.material; + +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; +import code.name.monkey.retromusic.ui.fragments.player.normal.PlayerFragment; + +/** + * @author Hemanth S (h4h13). + */ +public class MaterialFragment extends AbsPlayerFragment implements PlayerAlbumCoverFragment.Callbacks { + + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.status_bar) + View statusBar; + + private int lastColor; + private MaterialControlsFragment playbackControlsFragment; + private Unbinder unbinder; + + public static PlayerFragment newInstance() { + Bundle args = new Bundle(); + PlayerFragment fragment = new PlayerFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + @ColorInt + public int getPaletteColor() { + return lastColor; + } + + @Override + public void onShow() { + playbackControlsFragment.show(); + } + + @Override + public void onHide() { + playbackControlsFragment.hide(); + onBackPressed(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return ATHUtil.resolveColor(getContext(), R.attr.iconColor); + } + + @Override + public void onColorChanged(int color) { + playbackControlsFragment.setDark(color); + lastColor = color; + getCallbacks().onPaletteColorChanged(); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, + ATHUtil.resolveColor(getContext(), R.attr.iconColor), getActivity()); + } + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_material, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + + setUpSubFragments(); + setUpPlayerToolbar(); + } + + private void setUpSubFragments() { + playbackControlsFragment = (MaterialControlsFragment) getChildFragmentManager() + .findFragmentById(R.id.playback_controls_fragment); + + PlayerAlbumCoverFragment playerAlbumCoverFragment = + (PlayerAlbumCoverFragment) getChildFragmentManager() + .findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, + ATHUtil.resolveColor(getContext(), R.attr.iconColor), getActivity()); + } + + @Override + public void onServiceConnected() { + updateIsFavorite(); + } + + @Override + public void onPlayingMetaChanged() { + updateIsFavorite(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerFragment.java new file mode 100644 index 00000000..9914b72b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerFragment.java @@ -0,0 +1,181 @@ +package code.name.monkey.retromusic.ui.fragments.player.normal; + +import android.animation.ArgbEvaluator; +import android.animation.ValueAnimator; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.ViewUtil; +import code.name.monkey.retromusic.views.DrawableGradient; + + +public class PlayerFragment extends AbsPlayerFragment implements PlayerAlbumCoverFragment.Callbacks { + + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.gradient_background) + View colorBackground; + @BindView(R.id.status_bar) + View statusBar; + + private int lastColor; + private PlayerPlaybackControlsFragment playbackControlsFragment; + private Unbinder unbinder; + private ValueAnimator valueAnimator; + + public static PlayerFragment newInstance() { + Bundle args = new Bundle(); + PlayerFragment fragment = new PlayerFragment(); + fragment.setArguments(args); + return fragment; + } + + + private void colorize(int i) { + if (valueAnimator != null) { + valueAnimator.cancel(); + } + + valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), android.R.color.transparent, i); + valueAnimator.addUpdateListener(animation -> { + GradientDrawable drawable = new DrawableGradient(GradientDrawable.Orientation.TOP_BOTTOM, + new int[]{(int) animation.getAnimatedValue(), android.R.color.transparent}, 0); + if (colorBackground != null) { + colorBackground.setBackground(drawable); + } + }); + valueAnimator.setDuration(ViewUtil.RETRO_MUSIC_ANIM_TIME).start(); + } + + @Override + @ColorInt + public int getPaletteColor() { + return lastColor; + } + + @Override + public void onShow() { + playbackControlsFragment.show(); + } + + @Override + public void onHide() { + playbackControlsFragment.hide(); + onBackPressed(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return ATHUtil.resolveColor(getContext(), R.attr.iconColor); + } + + @Override + public void onColorChanged(int color) { + playbackControlsFragment.setDark(color); + lastColor = color; + getCallbacks().onPaletteColorChanged(); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, + ATHUtil.resolveColor(getContext(), R.attr.iconColor), getActivity()); + + if (PreferenceUtil.getInstance(getContext()).getAdaptiveColor()) { + colorize(color); + } + } + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_player, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + + setUpSubFragments(); + setUpPlayerToolbar(); + } + + private void setUpSubFragments() { + playbackControlsFragment = (PlayerPlaybackControlsFragment) getChildFragmentManager() + .findFragmentById(R.id.playback_controls_fragment); + + PlayerAlbumCoverFragment playerAlbumCoverFragment = + (PlayerAlbumCoverFragment) getChildFragmentManager() + .findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, + ATHUtil.resolveColor(getContext(), R.attr.iconColor), getActivity()); + } + + @Override + public void onServiceConnected() { + updateIsFavorite(); + + } + + @Override + public void onPlayingMetaChanged() { + updateIsFavorite(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerPlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerPlaybackControlsFragment.java new file mode 100644 index 00000000..4f0303e8 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerPlaybackControlsFragment.java @@ -0,0 +1,345 @@ +package code.name.monkey.retromusic.ui.fragments.player.normal; + +import android.animation.ObjectAnimator; +import android.graphics.PorterDuff; +import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatSeekBar; +import android.support.v7.widget.AppCompatTextView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +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 code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.PlayPauseDrawable; + +public class PlayerPlaybackControlsFragment extends AbsPlayerControlsFragment { + + @BindView(R.id.player_play_pause_button) + ImageButton playPauseFab; + @BindView(R.id.player_prev_button) + ImageButton prevButton; + @BindView(R.id.player_next_button) + ImageButton nextButton; + @BindView(R.id.player_repeat_button) + ImageButton repeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton shuffleButton; + @BindView(R.id.player_progress_slider) + AppCompatSeekBar progressSlider; + @BindView(R.id.player_song_total_time) + TextView songTotalTime; + @BindView(R.id.player_song_current_progress) + TextView songCurrentProgress; + @BindView(R.id.title) + AppCompatTextView title; + @BindView(R.id.text) + TextView text; + @BindView(R.id.volume_fragment_container) + View mVolumeContainer; + private Unbinder unbinder; + private PlayPauseDrawable playerFabPlayPauseDrawable; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_player_playback_controls, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + unbinder = ButterKnife.bind(this, view); + setUpMusicControllers(); + + if (PreferenceUtil.getInstance(getContext()).getVolumeToggle()) { + mVolumeContainer.setVisibility(View.VISIBLE); + } else { + mVolumeContainer.setVisibility(View.GONE); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + title.setText(song.title); + text.setText(song.artistName); + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateShuffleState(); + updateSong(); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Override + public void setDark(int dark) { + int color = ATHUtil.resolveColor(getActivity(), android.R.attr.colorBackground); + if (ColorUtil.isColorLight(color)) { + lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(getActivity(), true); + lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(getActivity(), true); + } else { + lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(getActivity(), false); + lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(getActivity(), false); + } + + if (PreferenceUtil.getInstance(getContext()).getAdaptiveColor()) { + setFabColor(dark); + } else { + setFabColor(ThemeStore.accentColor(getContext())); + } + + updateRepeatState(); + updateShuffleState(); + updatePrevNextColor(); + } + + private void setFabColor(int i) { + TintHelper.setTintAuto(playPauseFab, MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(i)), false); + TintHelper.setTintAuto(playPauseFab, i, true); + setProgressBarColor(i); + } + + public void setProgressBarColor(int newColor) { + LayerDrawable ld = (LayerDrawable) progressSlider.getProgressDrawable(); + ClipDrawable clipDrawable = (ClipDrawable) ld.findDrawableByLayerId(android.R.id.progress); + clipDrawable.setColorFilter(newColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpPlayPauseFab() { + playerFabPlayPauseDrawable = new PlayPauseDrawable(getActivity()); + + playPauseFab.setImageDrawable( + playerFabPlayPauseDrawable); // Note: set the drawable AFTER TintHelper.setTintAuto() was called + //playPauseFab.setColorFilter(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(fabColor)), PorterDuff.Mode.SRC_IN); + //playPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); + playPauseFab.post(() -> { + if (playPauseFab != null) { + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + } + }); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + playerFabPlayPauseDrawable.setPause(animate); + } else { + playerFabPlayPauseDrawable.setPlay(animate); + } + } + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + nextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + prevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + prevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpShuffleButton() { + shuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + protected void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpRepeatButton() { + repeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + @Override + protected void show() { + playPauseFab.animate() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(new DecelerateInterpolator()) + .start(); + } + + @Override + protected void hide() { + if (playPauseFab != null) { + playPauseFab.setScaleX(0f); + playPauseFab.setScaleY(0f); + playPauseFab.setRotation(0f); + } + } + + @Override + protected void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), + MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + } + + public void showBouceAnimation() { + playPauseFab.clearAnimation(); + + playPauseFab.setScaleX(0.9f); + playPauseFab.setScaleY(0.9f); + playPauseFab.setVisibility(View.VISIBLE); + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + + playPauseFab.animate() + .setDuration(200) + .setInterpolator(new DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(() -> playPauseFab.animate() + .setDuration(200) + .setInterpolator(new AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .start()) + .start(); + } + + @OnClick(R.id.player_play_pause_button) + void showAnimation() { + if (MusicPlayerRemote.isPlaying()) { + MusicPlayerRemote.pauseSong(); + } else { + MusicPlayerRemote.resumePlaying(); + } + showBouceAnimation(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + songTotalTime.setText(MusicUtil.getReadableDurationString(total)); + songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/plain/PlainPlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/plain/PlainPlaybackControlsFragment.java new file mode 100644 index 00000000..c32d8397 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/plain/PlainPlaybackControlsFragment.java @@ -0,0 +1,324 @@ +package code.name.monkey.retromusic.ui.fragments.player.plain; + +import android.animation.ObjectAnimator; +import android.graphics.PorterDuff; +import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.PlayPauseDrawable; + +/** + * @author Hemanth S (h4h13). + */ + +public class PlainPlaybackControlsFragment extends AbsPlayerControlsFragment { + @BindView(R.id.player_play_pause_button) + ImageButton playPauseFab; + @BindView(R.id.player_prev_button) + ImageButton prevButton; + @BindView(R.id.player_next_button) + ImageButton nextButton; + @BindView(R.id.player_repeat_button) + ImageButton repeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton shuffleButton; + @BindView(R.id.player_progress_slider) + SeekBar progressSlider; + @BindView(R.id.player_song_total_time) + TextView songTotalTime; + @BindView(R.id.player_song_current_progress) + TextView songCurrentProgress; + @BindView(R.id.volume_fragment_container) + View volumeContainer; + private Unbinder unbinder; + private PlayPauseDrawable playerFabPlayPauseDrawable; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateShuffleState(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_plain_controls_fragment, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setUpMusicControllers(); + if (PreferenceUtil.getInstance(getContext()).getVolumeToggle()) { + volumeContainer.setVisibility(View.VISIBLE); + } else { + volumeContainer.setVisibility(View.GONE); + } + } + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + nextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + prevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + prevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpShuffleButton() { + shuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + protected void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpRepeatButton() { + repeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + + @Override + protected void show() { + playPauseFab.animate() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(new DecelerateInterpolator()) + .start(); + } + + @Override + protected void hide() { + if (playPauseFab != null) { + playPauseFab.setScaleX(0f); + playPauseFab.setScaleY(0f); + playPauseFab.setRotation(0f); + } + } + + @Override + protected void setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress); + onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), MusicPlayerRemote.getSongDurationMillis()); + } + } + }); + } + + public void showBouceAnimation() { + playPauseFab.clearAnimation(); + + playPauseFab.setScaleX(0.9f); + playPauseFab.setScaleY(0.9f); + playPauseFab.setVisibility(View.VISIBLE); + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + + playPauseFab.animate() + .setDuration(200) + .setInterpolator(new DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(() -> playPauseFab.animate() + .setDuration(200) + .setInterpolator(new AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .start()) + .start(); + } + + @OnClick(R.id.player_play_pause_button) + void showAnimation() { + if (MusicPlayerRemote.isPlaying()) { + MusicPlayerRemote.pauseSong(); + } else { + MusicPlayerRemote.resumePlaying(); + } + showBouceAnimation(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + progressSlider.setMax(total); + + ObjectAnimator animator = ObjectAnimator.ofInt(progressSlider, "progress", progress); + animator.setDuration(1500); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + + songTotalTime.setText(MusicUtil.getReadableDurationString(total)); + songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); + } + + @Override + public void setDark(int dark) { + int color = ATHUtil.resolveColor(getActivity(), android.R.attr.colorBackground); + if (ColorUtil.isColorLight(color)) { + lastPlaybackControlsColor = + MaterialValueHelper.getSecondaryTextColor(getActivity(), true); + lastDisabledPlaybackControlsColor = + MaterialValueHelper.getSecondaryDisabledTextColor(getActivity(), true); + } else { + lastPlaybackControlsColor = + MaterialValueHelper.getPrimaryTextColor(getActivity(), false); + lastDisabledPlaybackControlsColor = + MaterialValueHelper.getPrimaryDisabledTextColor(getActivity(), false); + } + + if (PreferenceUtil.getInstance(getContext()).getAdaptiveColor()) { + TintHelper.setTintAuto(playPauseFab, MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(dark)), false); + TintHelper.setTintAuto(playPauseFab, dark, true); + setProgressBarColor(progressSlider, dark); + } + updateRepeatState(); + updateShuffleState(); + updatePrevNextColor(); + } + + public void setProgressBarColor(SeekBar progressBar, int newColor) { + LayerDrawable ld = (LayerDrawable) progressBar.getProgressDrawable(); + ClipDrawable clipDrawable = (ClipDrawable) ld.findDrawableByLayerId(android.R.id.progress); + clipDrawable.setColorFilter(newColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpPlayPauseFab() { + playerFabPlayPauseDrawable = new PlayPauseDrawable(getActivity()); + + playPauseFab.setImageDrawable(playerFabPlayPauseDrawable); // Note: set the drawable AFTER TintHelper.setTintAuto() was called + //playPauseFab.setColorFilter(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(fabColor)), PorterDuff.Mode.SRC_IN); + //playPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); + playPauseFab.post(() -> { + if (playPauseFab != null) { + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + } + }); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + playerFabPlayPauseDrawable.setPause(animate); + } else { + playerFabPlayPauseDrawable.setPlay(animate); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/plain/PlainPlayerFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/plain/PlainPlayerFragment.java new file mode 100644 index 00000000..f448fee5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/plain/PlainPlayerFragment.java @@ -0,0 +1,158 @@ +package code.name.monkey.retromusic.ui.fragments.player.plain; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; + +/** + * @author Hemanth S (h4h13). + */ + +public class PlainPlayerFragment extends AbsPlayerFragment implements + PlayerAlbumCoverFragment.Callbacks { + + @BindView(R.id.title) + TextView title; + @BindView(R.id.text) + TextView text; + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.toolbar_container) + FrameLayout toolbarContainer; + @BindView(R.id.status_bar) + View statusBar; + + private Unbinder unbinder; + private PlainPlaybackControlsFragment plainPlaybackControlsFragment; + private int mLastColor; + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + title.setText(song.title); + text.setText(song.artistName); + } + + @Override + public void onServiceConnected() { + super.onServiceConnected(); + updateSong(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_plain_player, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, + ATHUtil.resolveColor(getContext(), R.attr.iconColor), + getActivity()); + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + setUpSubFragments(); + setUpPlayerToolbar(); + title.setSelected(true); + } + + private void setUpSubFragments() { + plainPlaybackControlsFragment = (PlainPlaybackControlsFragment) getChildFragmentManager() + .findFragmentById(R.id.playback_controls_fragment); + PlayerAlbumCoverFragment playerAlbumCoverFragment = (PlayerAlbumCoverFragment) getChildFragmentManager() + .findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + } + + @Override + public int getPaletteColor() { + return mLastColor; + } + + @Override + public void onShow() { + plainPlaybackControlsFragment.show(); + } + + @Override + public void onHide() { + plainPlaybackControlsFragment.hide(); + onBackPressed(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return ATHUtil.resolveColor(getContext(), R.attr.iconColor); + } + + @Override + public void onColorChanged(int color) { + plainPlaybackControlsFragment.setDark(color); + mLastColor = color; + getCallbacks().onPaletteColorChanged(); + ToolbarContentTintHelper.colorizeToolbar(toolbar, + ATHUtil.resolveColor(getContext(), R.attr.iconColor), getActivity()); + } + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/simple/SimplePlaybackControlsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/simple/SimplePlaybackControlsFragment.java new file mode 100644 index 00000000..1631a757 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/simple/SimplePlaybackControlsFragment.java @@ -0,0 +1,319 @@ +package code.name.monkey.retromusic.ui.fragments.player.simple; + +import android.graphics.PorterDuff; +import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +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 code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.views.PlayPauseDrawable; + +/** + * @author Hemanth S (h4h13). + */ + +public class SimplePlaybackControlsFragment extends AbsPlayerControlsFragment { + @BindView(R.id.player_play_pause_button) + ImageButton playPauseFab; + @BindView(R.id.player_prev_button) + ImageButton prevButton; + @BindView(R.id.player_next_button) + ImageButton nextButton; + @BindView(R.id.player_repeat_button) + ImageButton repeatButton; + @BindView(R.id.player_shuffle_button) + ImageButton shuffleButton; + @BindView(R.id.player_song_current_progress) + TextView songCurrentProgress; + @BindView(R.id.volume_fragment_container) + View volumeContainer; + @BindView(R.id.title) + TextView title; + @BindView(R.id.text) + TextView text; + private Unbinder unbinder; + private PlayPauseDrawable playerFabPlayPauseDrawable; + private int lastPlaybackControlsColor; + private int lastDisabledPlaybackControlsColor; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Override + public void onServiceConnected() { + updatePlayPauseDrawableState(false); + updateRepeatState(); + updateShuffleState(); + updateSong(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_simple_controls_fragment, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onResume() { + super.onResume(); + progressViewUpdateHelper.start(); + } + + @Override + public void onPause() { + super.onPause(); + progressViewUpdateHelper.stop(); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setUpMusicControllers(); + volumeContainer.setVisibility(PreferenceUtil.getInstance(getContext()).getVolumeToggle() ? View.VISIBLE : View.GONE); + } + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + setUpProgressSlider(); + } + + private void setUpPrevNext() { + updatePrevNextColor(); + nextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong()); + prevButton.setOnClickListener(v -> MusicPlayerRemote.back()); + } + + private void updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + prevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpShuffleButton() { + shuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode()); + } + + @Override + protected void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + default: + shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void setUpRepeatButton() { + repeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode()); + } + + @Override + protected void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_NONE: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp); + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN); + break; + } + } + + private void updateSong() { + Song song = MusicPlayerRemote.getCurrentSong(); + title.setText(song.title); + text.setText(song.artistName); + } + + @Override + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateSong(); + + } + + @Override + protected void setUpProgressSlider() { + + } + + @Override + protected void show() { + playPauseFab.animate() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(new DecelerateInterpolator()) + .start(); + } + + @Override + protected void hide() { + if (playPauseFab != null) { + playPauseFab.setScaleX(0f); + playPauseFab.setScaleY(0f); + playPauseFab.setRotation(0f); + } + } + + + public void showBouceAnimation() { + playPauseFab.clearAnimation(); + + playPauseFab.setScaleX(0.9f); + playPauseFab.setScaleY(0.9f); + playPauseFab.setVisibility(View.VISIBLE); + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + + playPauseFab.animate() + .setDuration(200) + .setInterpolator(new DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(() -> playPauseFab.animate() + .setDuration(200) + .setInterpolator(new AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .start()) + .start(); + } + + @OnClick(R.id.player_play_pause_button) + void showAnimation() { + if (MusicPlayerRemote.isPlaying()) { + MusicPlayerRemote.pauseSong(); + } else { + MusicPlayerRemote.resumePlaying(); + } + showBouceAnimation(); + } + + @Override + public void onUpdateProgressViews(int progress, int total) { + songCurrentProgress.setText(String.format("%s / %s", MusicUtil.getReadableDurationString(progress), + MusicUtil.getReadableDurationString(total))); + } + + @Override + public void setDark(int dark) { + int color = ATHUtil.resolveColor(getActivity(), android.R.attr.colorBackground); + if (ColorUtil.isColorLight(color)) { + lastPlaybackControlsColor = MaterialValueHelper + .getSecondaryTextColor(getActivity(), true); + lastDisabledPlaybackControlsColor = MaterialValueHelper + .getSecondaryDisabledTextColor(getActivity(), true); + } else { + lastPlaybackControlsColor = MaterialValueHelper + .getPrimaryTextColor(getActivity(), false); + lastDisabledPlaybackControlsColor = MaterialValueHelper + .getPrimaryDisabledTextColor(getActivity(), false); + } + + if (PreferenceUtil.getInstance(getContext()).getAdaptiveColor()) { + TintHelper.setTintAuto(playPauseFab, MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(dark)), false); + TintHelper.setTintAuto(playPauseFab, dark, true); + text.setTextColor(dark); + } else { + text.setTextColor(ThemeStore.accentColor(getContext())); + } + + updateRepeatState(); + updateShuffleState(); + updatePrevNextColor(); + } + + public void setProgressBarColor(SeekBar progressBar, int newColor) { + LayerDrawable ld = (LayerDrawable) progressBar.getProgressDrawable(); + ClipDrawable clipDrawable = (ClipDrawable) ld.findDrawableByLayerId(android.R.id.progress); + clipDrawable.setColorFilter(newColor, PorterDuff.Mode.SRC_IN); + } + + private void setUpPlayPauseFab() { + playerFabPlayPauseDrawable = new PlayPauseDrawable(getActivity()); + + playPauseFab.setImageDrawable(playerFabPlayPauseDrawable); // Note: set the drawable AFTER TintHelper.setTintAuto() was called + //playPauseFab.setColorFilter(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(fabColor)), PorterDuff.Mode.SRC_IN); + //playPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); + playPauseFab.post(() -> { + if (playPauseFab != null) { + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + } + }); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (MusicPlayerRemote.isPlaying()) { + playerFabPlayPauseDrawable.setPause(animate); + } else { + playerFabPlayPauseDrawable.setPlay(animate); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/simple/SimplePlayerFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/simple/SimplePlayerFragment.java new file mode 100644 index 00000000..0ac6ecff --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/simple/SimplePlayerFragment.java @@ -0,0 +1,132 @@ +package code.name.monkey.retromusic.ui.fragments.player.simple; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.util.ATHUtil; +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment; +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment; + +/** + * @author Hemanth S (h4h13). + */ + +public class SimplePlayerFragment extends AbsPlayerFragment implements + PlayerAlbumCoverFragment.Callbacks { + + @BindView(R.id.player_toolbar) + Toolbar toolbar; + @BindView(R.id.status_bar) + View statusBar; + private Unbinder unbinder; + private SimplePlaybackControlsFragment simplePlaybackControlsFragment; + private int lastColor; + + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_simple_player, container, false); + unbinder = ButterKnife.bind(this, view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + toggleStatusBar(statusBar); + setUpSubFragments(); + setUpPlayerToolbar(); + } + + private void setUpSubFragments() { + PlayerAlbumCoverFragment playerAlbumCoverFragment = (PlayerAlbumCoverFragment) + getChildFragmentManager().findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setCallbacks(this); + simplePlaybackControlsFragment = (SimplePlaybackControlsFragment) + getChildFragmentManager().findFragmentById(R.id.playback_controls_fragment); + + } + + @Override + public int getPaletteColor() { + return lastColor; + } + + @Override + public void onShow() { + simplePlaybackControlsFragment.show(); + } + + @Override + public void onHide() { + simplePlaybackControlsFragment.hide(); + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public Toolbar getToolbar() { + return toolbar; + } + + @Override + public int toolbarIconColor() { + return ATHUtil.resolveColor(getContext(), R.attr.iconColor); + } + + @Override + public void onColorChanged(int color) { + lastColor = color; + getCallbacks().onPaletteColorChanged(); + simplePlaybackControlsFragment.setDark(color); + ToolbarContentTintHelper.colorizeToolbar(toolbar, + ATHUtil.resolveColor(getContext(), R.attr.iconColor), getActivity()); + + } + + @Override + public void onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.getCurrentSong()); + } + + @Override + protected void toggleFavorite(Song song) { + super.toggleFavorite(song); + if (song.id == MusicPlayerRemote.getCurrentSong().id) { + updateIsFavorite(); + } + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); + toolbar.setOnMenuItemClickListener(this); + + ToolbarContentTintHelper.colorizeToolbar(toolbar, + ATHUtil.resolveColor(getContext(), R.attr.iconColor), + getActivity()); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/AbsSettingsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/AbsSettingsFragment.java new file mode 100644 index 00000000..a42528a1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/AbsSettingsFragment.java @@ -0,0 +1,89 @@ +package code.name.monkey.retromusic.ui.fragments.settings; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.DialogFragment; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.Toast; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat; +import code.name.monkey.retromusic.preferences.BlacklistPreference; +import code.name.monkey.retromusic.preferences.BlacklistPreferenceDialog; +import code.name.monkey.retromusic.preferences.NowPlayingScreenPreference; +import code.name.monkey.retromusic.preferences.NowPlayingScreenPreferenceDialog; +import code.name.monkey.retromusic.ui.activities.SettingsActivity; +import code.name.monkey.retromusic.util.DensityUtil; +import code.name.monkey.retromusic.util.NavigationUtil; + +/** + * @author Hemanth S (h4h13). + */ + +public abstract class AbsSettingsFragment extends ATEPreferenceFragmentCompat { + protected void showProToastAndNavigate(String message) { + Toast.makeText(getContext(), message + " is Pro version feature.", Toast.LENGTH_SHORT).show(); + //noinspection ConstantConditions + NavigationUtil.goToProVersion(getActivity()); + } + + protected void setSummary(@NonNull Preference preference) { + setSummary(preference, PreferenceManager + .getDefaultSharedPreferences(preference.getContext()) + .getString(preference.getKey(), "")); + } + + protected void setSummary(Preference preference, @NonNull Object value) { + String stringValue = value.toString(); + if (preference instanceof ListPreference) { + ListPreference listPreference = (ListPreference) preference; + int index = listPreference.findIndexOfValue(stringValue); + preference.setSummary(index >= 0 ? listPreference.getEntries()[index] : null); + } else { + preference.setSummary(stringValue); + } + } + + public abstract void invalidateSettings(); + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setDividerHeight(0); + setDivider(new ColorDrawable(Color.TRANSPARENT)); + + getListView().setPadding(DensityUtil.dip2px(getContext(), 0), 0, 0, 0); + getListView().addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (getActivity() != null) { + ((SettingsActivity) getActivity()) + .addAppbarLayoutElevation(recyclerView.canScrollVertically(RecyclerView.NO_POSITION) ? 8f : 0f); + } + } + }); + //noinspection ConstantConditions + getListView().setBackgroundColor(ThemeStore.primaryColor(getContext())); + getListView().setOverScrollMode(View.OVER_SCROLL_NEVER); + invalidateSettings(); + } + + @Nullable + @Override + public DialogFragment onCreatePreferenceDialog(Preference preference) { + if (preference instanceof NowPlayingScreenPreference) { + return NowPlayingScreenPreferenceDialog.newInstance(); + } else if (preference instanceof BlacklistPreference) { + return BlacklistPreferenceDialog.newInstance(); + } + return super.onCreatePreferenceDialog(preference); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/AudioSettings.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/AudioSettings.java new file mode 100644 index 00000000..4135304f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/AudioSettings.java @@ -0,0 +1,49 @@ +package code.name.monkey.retromusic.ui.fragments.settings; + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.media.audiofx.AudioEffect; +import android.os.Bundle; +import android.support.v7.preference.Preference; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.util.NavigationUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * @author Hemanth S (h4h13). + */ + +public class AudioSettings extends AbsSettingsFragment { + @Override + public void invalidateSettings() { + Preference findPreference = findPreference("equalizer"); + if (!hasEqualizer() && !PreferenceUtil.getInstance(getContext()).getSelectedEqualizer().equals("retro")) { + findPreference.setEnabled(false); + findPreference.setSummary(getResources().getString(R.string.no_equalizer)); + } else { + findPreference.setEnabled(true); + } + findPreference.setOnPreferenceClickListener(preference -> { + //noinspection ConstantConditions + NavigationUtil.openEqualizer(getActivity()); + return true; + }); + + + } + + private boolean hasEqualizer() { + final Intent effects = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL); + //noinspection ConstantConditions + PackageManager pm = getActivity().getPackageManager(); + ResolveInfo ri = pm.resolveActivity(effects, 0); + return ri != null; + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.pref_audio); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ImageSettingFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ImageSettingFragment.java new file mode 100644 index 00000000..d34c0a32 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ImageSettingFragment.java @@ -0,0 +1,28 @@ +package code.name.monkey.retromusic.ui.fragments.settings; + +import android.os.Bundle; +import android.support.v7.preference.Preference; + +import code.name.monkey.retromusic.R; + +/** + * @author Hemanth S (h4h13). + */ + +public class ImageSettingFragment extends AbsSettingsFragment { + @Override + public void invalidateSettings() { + final Preference autoDownloadImagesPolicy = findPreference("auto_download_images_policy"); + setSummary(autoDownloadImagesPolicy); + autoDownloadImagesPolicy.setOnPreferenceChangeListener((preference, o) -> { + setSummary(autoDownloadImagesPolicy, o); + return true; + }); + + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.pref_images); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.java new file mode 100644 index 00000000..9c505166 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.java @@ -0,0 +1,85 @@ +package code.name.monkey.retromusic.ui.fragments.settings; + +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.util.List; + +import butterknife.BindView; +import butterknife.BindViews; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.ui.activities.SettingsActivity; +import code.name.monkey.retromusic.views.IconImageView; + +public class MainSettingsFragment extends Fragment { + + Unbinder unbinder; + @BindViews({R.id.general_settings_icon, R.id.audio_settings_icon, + R.id.now_playing_settings_icon, R.id.image_settings_icon, + R.id.notification_settings_icon, R.id.other_settings_icon}) + List icons; + ButterKnife.Action apply = (view, index) -> { + //noinspection ConstantConditions + ((IconImageView) view).setColorFilter(ThemeStore.accentColor(getContext()), PorterDuff.Mode.SRC_IN); + }; + @BindView(R.id.container) + ViewGroup container; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_main_settings, container, false); + unbinder = ButterKnife.bind(this, layout); + ButterKnife.apply(icons, apply); + return layout; + } + + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @OnClick({R.id.general_settings, R.id.audio_settings, R.id.now_playing_settings, + R.id.image_settings, R.id.notification_settings, R.id.other_settings}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.general_settings: + inflateFragment(new ThemeSettingsFragment()); + break; + case R.id.audio_settings: + inflateFragment(new AudioSettings()); + break; + case R.id.now_playing_settings: + inflateFragment(new NowPlayingSettingsFragment()); + break; + case R.id.image_settings: + inflateFragment(new ImageSettingFragment()); + break; + case R.id.notification_settings: + inflateFragment(new NotificationSettingsFragment()); + break; + case R.id.other_settings: + inflateFragment(new OtherSettingsFragment()); + break; + } + } + + private void inflateFragment(Fragment fragment) { + if (getActivity() != null) { + ((SettingsActivity) getActivity()).setupFragment(fragment); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NotificationSettingsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NotificationSettingsFragment.java new file mode 100644 index 00000000..e2d6f2b8 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NotificationSettingsFragment.java @@ -0,0 +1,43 @@ +package code.name.monkey.retromusic.ui.fragments.settings; + +import android.os.Build; +import android.os.Bundle; +import android.support.v7.preference.TwoStatePreference; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.service.MusicService; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * @author Hemanth S (h4h13). + */ + +public class NotificationSettingsFragment extends AbsSettingsFragment { + @Override + public void invalidateSettings() { + final TwoStatePreference classicNotification = (TwoStatePreference) findPreference("classic_notification"); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + classicNotification.setVisible(false); + } else { + classicNotification.setChecked(PreferenceUtil.getInstance(getActivity()).classicNotification()); + classicNotification.setOnPreferenceChangeListener((preference, newValue) -> { + // Save preference + PreferenceUtil.getInstance(getActivity()).setClassicNotification((Boolean) newValue); + + final MusicService service = MusicPlayerRemote.musicService; + if (service != null) { + service.initNotification(); + service.updateNotification(); + } + + return true; + }); + } + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.pref_notification); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NowPlayingSettingsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NowPlayingSettingsFragment.java new file mode 100644 index 00000000..eab599de --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NowPlayingSettingsFragment.java @@ -0,0 +1,92 @@ +package code.name.monkey.retromusic.ui.fragments.settings; + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v7.preference.TwoStatePreference; +import android.view.View; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * @author Hemanth S (h4h13). + */ + +public class NowPlayingSettingsFragment extends AbsSettingsFragment implements + SharedPreferences.OnSharedPreferenceChangeListener { + + @SuppressWarnings("ConstantConditions") + @Override + public void invalidateSettings() { + updateNowPlayingScreenSummary(); + + final TwoStatePreference cornerWindow = (TwoStatePreference) findPreference("corner_window"); + cornerWindow.setOnPreferenceChangeListener((preference, newValue) -> { + if ((Boolean) newValue && !RetroApplication.isProVersion()) { + showProToastAndNavigate(getActivity().getString(R.string.pref_title_round_corners)); + return false; + } + getActivity().recreate(); + return true; + }); + final TwoStatePreference carouselEffect = (TwoStatePreference) findPreference( + "carousel_effect"); + carouselEffect.setOnPreferenceChangeListener((preference, newValue) -> { + if ((Boolean) newValue && !RetroApplication.isProVersion()) { + showProToastAndNavigate( + getActivity().getString(R.string.pref_title_toggle_carousel_effect)); + return false; + } + return true; + }); + + final TwoStatePreference toggleFullScreen = (TwoStatePreference) findPreference( + "toggle_full_screen"); + toggleFullScreen.setOnPreferenceChangeListener((preference, newValue) -> { + getActivity().recreate(); + return true; + }); + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.pref_now_playing_screen); + addPreferencesFromResource(R.xml.pref_ui); + addPreferencesFromResource(R.xml.pref_window); + addPreferencesFromResource(R.xml.pref_lockscreen); + } + + private void updateNowPlayingScreenSummary() { + //noinspection ConstantConditions + findPreference("now_playing_screen_id") + .setSummary(PreferenceUtil.getInstance(getActivity()).getNowPlayingScreen().titleRes); + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + //noinspection ConstantConditions + PreferenceUtil.getInstance(getContext()).registerOnSharedPreferenceChangedListener(this); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + //noinspection ConstantConditions + PreferenceUtil.getInstance(getContext()).unregisterOnSharedPreferenceChangedListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + switch (key) { + case PreferenceUtil.NOW_PLAYING_SCREEN_ID: + updateNowPlayingScreenSummary(); + break; + case PreferenceUtil.CIRCULAR_ALBUM_ART: + case PreferenceUtil.CAROUSEL_EFFECT: + invalidateSettings(); + break; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/OtherSettingsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/OtherSettingsFragment.java new file mode 100644 index 00000000..4099daa1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/OtherSettingsFragment.java @@ -0,0 +1,23 @@ +package code.name.monkey.retromusic.ui.fragments.settings; + +import android.os.Bundle; + +import code.name.monkey.retromusic.R; + +/** + * @author Hemanth S (h4h13). + */ + +public class OtherSettingsFragment extends AbsSettingsFragment { + @Override + public void invalidateSettings() { + + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.pref_blacklist); + addPreferencesFromResource(R.xml.pref_playlists); + addPreferencesFromResource(R.xml.pref_advanced); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.java new file mode 100644 index 00000000..b33aaedd --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.java @@ -0,0 +1,143 @@ +package code.name.monkey.retromusic.ui.fragments.settings; + +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.support.v4.content.ContextCompat; +import android.support.v7.preference.Preference; +import android.support.v7.preference.TwoStatePreference; + +import com.afollestad.materialdialogs.color.ColorChooserDialog; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEColorPreference; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.VersionUtils; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager; +import code.name.monkey.retromusic.ui.activities.SettingsActivity; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * @author Hemanth S (h4h13). + */ + +public class ThemeSettingsFragment extends AbsSettingsFragment { + + @Override + public void invalidateSettings() { + + final ATEColorPreference primaryColorPref = (ATEColorPreference) findPreference( + "primary_color"); + //noinspection ConstantConditions + primaryColorPref.setVisible(PreferenceUtil.getInstance(getActivity()).getGeneralTheme() == R.style.Theme_RetroMusic_Color); + final int primaryColor = ThemeStore.primaryColor(getActivity()); + primaryColorPref.setColor(primaryColor, ColorUtil.darkenColor(primaryColor)); + primaryColorPref.setOnPreferenceClickListener(preference -> { + new ColorChooserDialog.Builder(getActivity(), R.string.primary_color) + .accentMode(false) + .allowUserColorInput(true) + .allowUserColorInputAlpha(false) + .preselect(primaryColor) + .show(getActivity()); + return true; + }); + + final Preference generalTheme = findPreference("general_theme"); + setSummary(generalTheme); + generalTheme.setOnPreferenceChangeListener((preference, newValue) -> { + String theme = (String) newValue; + + if (theme.equals("color") && !RetroApplication.isProVersion()) { + primaryColorPref.setVisible(false); + showProToastAndNavigate("Color theme"); + return false; + } else { + primaryColorPref.setVisible(true); + } + + setSummary(generalTheme, newValue); + + + switch (theme) { + case "light": + ThemeStore.editTheme(getContext()).primaryColor(Color.WHITE).commit(); + break; + case "black": + ThemeStore.editTheme(getContext()).primaryColor(Color.BLACK).commit(); + break; + case "dark": + ThemeStore.editTheme(getContext()).primaryColor(ContextCompat.getColor(getContext(), R.color.md_grey_900)).commit(); + break; + case "color": + ThemeStore.editTheme(getContext()).primaryColor(ContextCompat.getColor(getContext(), R.color.md_blue_grey_800)).commit(); + break; + } + + ThemeStore.editTheme(getActivity()) + .activityTheme(PreferenceUtil.getThemeResFromPrefValue(theme)) + .commit(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + getActivity().setTheme(PreferenceUtil.getThemeResFromPrefValue(theme)); + new DynamicShortcutManager(getActivity()).updateDynamicShortcuts(); + } + getActivity().recreate(); + //invalidateSettings(); + return true; + }); + + ATEColorPreference accentColorPref = (ATEColorPreference) findPreference("accent_color"); + final int accentColor = ThemeStore.accentColor(getActivity()); + accentColorPref.setColor(accentColor, ColorUtil.darkenColor(accentColor)); + + accentColorPref.setOnPreferenceClickListener(preference -> { + new ColorChooserDialog.Builder(((SettingsActivity) getActivity()), R.string.accent_color) + .accentMode(true) + .allowUserColorInput(true) + .allowUserColorInputAlpha(false) + .preselect(accentColor) + .show(getActivity()); + return true; + }); + + TwoStatePreference colorNavBar = (TwoStatePreference) findPreference( + "should_color_navigation_bar"); + if (!VersionUtils.hasLollipop()) { + colorNavBar.setEnabled(false); + colorNavBar.setSummary(R.string.pref_only_lollipop); + } else { + colorNavBar.setChecked(ThemeStore.coloredNavigationBar(getActivity())); + colorNavBar.setOnPreferenceChangeListener((preference, newValue) -> { + ThemeStore.editTheme(getActivity()) + .coloredNavigationBar((Boolean) newValue) + .commit(); + getActivity().recreate(); + return true; + }); + } + + TwoStatePreference colorAppShortcuts = (TwoStatePreference) findPreference( + "should_color_app_shortcuts"); + if (!VersionUtils.hasNougatMR()) { + colorAppShortcuts.setVisible(false); + } else { + colorAppShortcuts.setChecked(PreferenceUtil.getInstance(getActivity()).coloredAppShortcuts()); + colorAppShortcuts.setOnPreferenceChangeListener((preference, newValue) -> { + // Save preference + PreferenceUtil.getInstance(getActivity()).setColoredAppShortcuts((Boolean) newValue); + // Update app shortcuts + new DynamicShortcutManager(getActivity()).updateDynamicShortcuts(); + + return true; + }); + } + + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.pref_general); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/AnimationUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/AnimationUtil.java new file mode 100644 index 00000000..27a8caa8 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/AnimationUtil.java @@ -0,0 +1,23 @@ +package code.name.monkey.retromusic.util; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.animation.AnimationUtils; +import android.view.animation.LayoutAnimationController; +import code.name.monkey.retromusic.R; + +/** + * @author Hemanth S (h4h13). + */ +public class AnimationUtil { + + public static void runLayoutAnimation(final RecyclerView recyclerView) { + final Context context = recyclerView.getContext(); + final LayoutAnimationController controller = + AnimationUtils.loadLayoutAnimation(context, R.anim.layout_animation_slide_from_bottom); + + recyclerView.setLayoutAnimation(controller); + recyclerView.getAdapter().notifyDataSetChanged(); + recyclerView.scheduleLayoutAnimation(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/ArtistSignatureUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/ArtistSignatureUtil.java new file mode 100644 index 00000000..f747be56 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/ArtistSignatureUtil.java @@ -0,0 +1,41 @@ +package code.name.monkey.retromusic.util; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.support.annotation.NonNull; + +import com.bumptech.glide.signature.StringSignature; + + +public class ArtistSignatureUtil { + private static final String ARTIST_SIGNATURE_PREFS = "artist_signatures"; + + private static ArtistSignatureUtil sInstance; + + private final SharedPreferences mPreferences; + + private ArtistSignatureUtil(@NonNull final Context context) { + mPreferences = context.getSharedPreferences(ARTIST_SIGNATURE_PREFS, Context.MODE_PRIVATE); + } + + public static ArtistSignatureUtil getInstance(@NonNull final Context context) { + if (sInstance == null) { + sInstance = new ArtistSignatureUtil(context.getApplicationContext()); + } + return sInstance; + } + + @SuppressLint("CommitPrefEdits") + public void updateArtistSignature(String artistName) { + mPreferences.edit().putLong(artistName, System.currentTimeMillis()).apply(); + } + + public long getArtistSignatureRaw(String artistName) { + return mPreferences.getLong(artistName, 0); + } + + public StringSignature getArtistSignature(String artistName) { + return new StringSignature(String.valueOf(getArtistSignatureRaw(artistName))); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/CalendarUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/CalendarUtil.java new file mode 100644 index 00000000..cd32f330 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/CalendarUtil.java @@ -0,0 +1,117 @@ +package code.name.monkey.retromusic.util; + +import java.util.Calendar; +import java.util.GregorianCalendar; + +/** + * @author Eugene Cheung (arkon) + */ +public class CalendarUtil { + private static final long MS_PER_MINUTE = 60 * 1000; + private static final long MS_PER_DAY = 24 * 60 * MS_PER_MINUTE; + + private Calendar calendar; + + public CalendarUtil() { + this.calendar = Calendar.getInstance(); + } + + /** + * Returns the time elapsed so far today in milliseconds. + * + * @return Time elapsed today in milliseconds. + */ + public long getElapsedToday() { + // Time elapsed so far today + return (calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE)) * MS_PER_MINUTE + + calendar.get(Calendar.SECOND) * 1000 + + calendar.get(Calendar.MILLISECOND); + } + + /** + * Returns the time elapsed so far this week in milliseconds. + * + * @return Time elapsed this week in milliseconds. + */ + public long getElapsedWeek() { + // Today + days passed this week + long elapsed = getElapsedToday(); + + final int passedWeekdays = calendar.get(Calendar.DAY_OF_WEEK) - 1 - calendar.getFirstDayOfWeek(); + if (passedWeekdays > 0) { + elapsed += passedWeekdays * MS_PER_DAY; + } + + return elapsed; + } + + /** + * Returns the time elapsed so far this month in milliseconds. + * + * @return Time elapsed this month in milliseconds. + */ + public long getElapsedMonth() { + // Today + rest of this month + return getElapsedToday() + + ((calendar.get(Calendar.DAY_OF_MONTH) - 1) * MS_PER_DAY); + } + + /** + * Returns the time elapsed so far this month and the last numMonths months in milliseconds. + * + * @param numMonths Additional number of months prior to the current month to calculate. + * @return Time elapsed this month and the last numMonths months in milliseconds. + */ + public long getElapsedMonths(int numMonths) { + // Today + rest of this month + long elapsed = getElapsedMonth(); + + // Previous numMonths months + int month = calendar.get(Calendar.MONTH); + int year = calendar.get(Calendar.YEAR); + for (int i = 0; i < numMonths; i++) { + month--; + + if (month < Calendar.JANUARY) { + month = Calendar.DECEMBER; + year--; + } + + elapsed += getDaysInMonth(year, month) * MS_PER_DAY; + } + + return elapsed; + } + + /** + * Returns the time elapsed so far this year in milliseconds. + * + * @return Time elapsed this year in milliseconds. + */ + public long getElapsedYear() { + // Today + rest of this month + previous months until January + long elapsed = getElapsedMonth(); + + int month = calendar.get(Calendar.MONTH) - 1; + int year = calendar.get(Calendar.YEAR); + while (month > Calendar.JANUARY) { + elapsed += getDaysInMonth(year, month) * MS_PER_DAY; + + month--; + } + + return elapsed; + } + + /** + * Gets the number of days for the given month in the given year. + * + * @param year The year. + * @param month The month (1 - 12). + * @return The days in that month/year. + */ + private int getDaysInMonth(int year, int month) { + final Calendar monthCal = new GregorianCalendar(calendar.get(Calendar.YEAR), month, 1); + return monthCal.getActualMaximum(Calendar.DAY_OF_MONTH); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/ColorUtils.java b/app/src/main/java/code/name/monkey/retromusic/util/ColorUtils.java new file mode 100755 index 00000000..48854454 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/ColorUtils.java @@ -0,0 +1,64 @@ +package code.name.monkey.retromusic.util; + +import android.graphics.Color; +import android.support.annotation.ColorInt; + +public class ColorUtils { + + public static boolean isColorLight(@ColorInt int color) { + return getColorDarkness(color) < 0.5; + } + + private static double getColorDarkness(@ColorInt int color) { + if (color == Color.BLACK) + return 1.0; + else if (color == Color.WHITE || color == Color.TRANSPARENT) + return 0.0; + else + return (1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255); + } + + @ColorInt + public static int getInverseColor(@ColorInt int color) { + return (0xFFFFFF - color) | 0xFFFFFFFF; + } + + public static boolean isColorSaturated(@ColorInt int color) { + double max = Math.max(0.299 * Color.red(color), Math.max(0.587 * Color.green(color), 0.114 * Color.blue(color))); + double min = Math.min(0.299 * Color.red(color), Math.min(0.587 * Color.green(color), 0.114 * Color.blue(color))); + double diff = Math.abs(max - min); + return diff > 20; + } + + @ColorInt + public static int getMixedColor(@ColorInt int color1, @ColorInt int color2) { + return Color.rgb( + (Color.red(color1) + Color.red(color2)) / 2, + (Color.green(color1) + Color.green(color2)) / 2, + (Color.blue(color1) + Color.blue(color2)) / 2 + ); + } + + public static double getDifference(@ColorInt int color1, @ColorInt int color2) { + double diff = Math.abs(0.299 * (Color.red(color1) - Color.red(color2))); + diff += Math.abs(0.587 * (Color.green(color1) - Color.green(color2))); + diff += Math.abs(0.114 * (Color.blue(color1) - Color.blue(color2))); + return diff; + } + + @ColorInt + public static int getReadableText(@ColorInt int textColor, @ColorInt int backgroundColor) { + return getReadableText(textColor, backgroundColor, 100); + } + + @ColorInt + public static int getReadableText(@ColorInt int textColor, @ColorInt int backgroundColor, int difference) { + boolean isLight = isColorLight(backgroundColor); + for (int i = 0; getDifference(textColor, backgroundColor) < difference && i < 100; i++) { + textColor = getMixedColor(textColor, isLight ? Color.BLACK : Color.WHITE); + } + + return textColor; + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/Compressor.java b/app/src/main/java/code/name/monkey/retromusic/util/Compressor.java new file mode 100644 index 00000000..eb8d6c0f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/Compressor.java @@ -0,0 +1,90 @@ +package code.name.monkey.retromusic.util; + +import android.content.Context; +import android.graphics.Bitmap; + +import java.io.File; +import java.io.IOException; + +import io.reactivex.Flowable; + +/** + * Created on : June 18, 2016 + * Author : zetbaitsu + * Name : Zetra + * GitHub : https://github.com/zetbaitsu + */ +public class Compressor { + //max width and height values of the compressed image is taken as 612x816 + private int maxWidth = 612; + private int maxHeight = 816; + private Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.JPEG; + private int quality = 80; + private String destinationDirectoryPath; + + public Compressor(Context context) { + destinationDirectoryPath = context.getCacheDir().getPath() + File.separator + "images"; + } + + public Compressor setMaxWidth(int maxWidth) { + this.maxWidth = maxWidth; + return this; + } + + public Compressor setMaxHeight(int maxHeight) { + this.maxHeight = maxHeight; + return this; + } + + public Compressor setCompressFormat(Bitmap.CompressFormat compressFormat) { + this.compressFormat = compressFormat; + return this; + } + + public Compressor setQuality(int quality) { + this.quality = quality; + return this; + } + + public Compressor setDestinationDirectoryPath(String destinationDirectoryPath) { + this.destinationDirectoryPath = destinationDirectoryPath; + return this; + } + + public File compressToFile(File imageFile) throws IOException { + return compressToFile(imageFile, imageFile.getName()); + } + + public File compressToFile(File imageFile, String compressedFileName) throws IOException { + return ImageUtil.compressImage(imageFile, maxWidth, maxHeight, compressFormat, quality, + destinationDirectoryPath + File.separator + compressedFileName); + } + + public Bitmap compressToBitmap(File imageFile) throws IOException { + return ImageUtil.decodeSampledBitmapFromFile(imageFile, maxWidth, maxHeight); + } + + public Flowable compressToFileAsFlowable(final File imageFile) { + return compressToFileAsFlowable(imageFile, imageFile.getName()); + } + + public Flowable compressToFileAsFlowable(final File imageFile, final String compressedFileName) { + return Flowable.defer(() -> { + try { + return Flowable.just(compressToFile(imageFile, compressedFileName)); + } catch (IOException e) { + return Flowable.error(e); + } + }); + } + + public Flowable compressToBitmapAsFlowable(final File imageFile) { + return Flowable.defer(() -> { + try { + return Flowable.just(compressToBitmap(imageFile)); + } catch (IOException e) { + return Flowable.error(e); + } + }); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.java new file mode 100644 index 00000000..ca369a9d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.java @@ -0,0 +1,137 @@ +package code.name.monkey.retromusic.util; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.AsyncTask; +import android.support.annotation.NonNull; +import android.widget.Toast; + +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.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Locale; + +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.model.Artist; + + +public class CustomArtistImageUtil { + private static final String CUSTOM_ARTIST_IMAGE_PREFS = "custom_artist_image"; + private static final String FOLDER_NAME = "/custom_artist_images/"; + + private static CustomArtistImageUtil sInstance; + + private final SharedPreferences mPreferences; + + private CustomArtistImageUtil(@NonNull final Context context) { + mPreferences = context.getApplicationContext().getSharedPreferences(CUSTOM_ARTIST_IMAGE_PREFS, Context.MODE_PRIVATE); + } + + public static CustomArtistImageUtil getInstance(@NonNull final Context context) { + if (sInstance == null) { + sInstance = new CustomArtistImageUtil(context.getApplicationContext()); + } + return sInstance; + } + + private static String getFileName(Artist artist) { + String artistName = artist.getName(); + if (artistName == null) + artistName = ""; + // replace everything that is not a letter or a number with _ + artistName = artistName.replaceAll("[^a-zA-Z0-9]", "_"); + return String.format(Locale.US, "#%d#%s.jpeg", artist.getId(), artistName); + } + + public static File getFile(Artist artist) { + File dir = new File(RetroApplication.getInstance().getFilesDir(), FOLDER_NAME); + return new File(dir, getFileName(artist)); + } + + public void setCustomArtistImage(final Artist artist, Uri uri) { + Glide.with(RetroApplication.getInstance()) + .load(uri) + .asBitmap() + .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(true) + .into(new SimpleTarget() { + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + e.printStackTrace(); + Toast.makeText(RetroApplication.getInstance(), e.toString(), Toast.LENGTH_LONG).show(); + } + + @SuppressLint("StaticFieldLeak") + @Override + public void onResourceReady(final Bitmap resource, GlideAnimation glideAnimation) { + new AsyncTask() { + @SuppressLint("ApplySharedPref") + @Override + protected Void doInBackground(Void... params) { + File dir = new File(RetroApplication.getInstance().getFilesDir(), FOLDER_NAME); + if (!dir.exists()) { + if (!dir.mkdirs()) { // create the folder + return null; + } + } + File file = new File(dir, getFileName(artist)); + + boolean succesful = false; + try { + OutputStream os = new BufferedOutputStream(new FileOutputStream(file)); + succesful = ImageUtil.resizeBitmap(resource, 2048).compress(Bitmap.CompressFormat.JPEG, 100, os); + os.close(); + } catch (IOException e) { + Toast.makeText(RetroApplication.getInstance(), e.toString(), Toast.LENGTH_LONG).show(); + } + + if (succesful) { + mPreferences.edit().putBoolean(getFileName(artist), true).commit(); + ArtistSignatureUtil.getInstance(RetroApplication.getInstance()).updateArtistSignature(artist.getName()); + RetroApplication.getInstance().getContentResolver().notifyChange(Uri.parse("content://media"), null); // trigger media store changed to force artist image reload + } + return null; + } + }.execute(); + } + }); + } + + @SuppressLint("StaticFieldLeak") + public void resetCustomArtistImage(final Artist artist) { + new AsyncTask() { + @SuppressLint("ApplySharedPref") + @Override + protected Void doInBackground(Void... params) { + mPreferences.edit().putBoolean(getFileName(artist), false).commit(); + ArtistSignatureUtil.getInstance(RetroApplication.getInstance()).updateArtistSignature(artist.getName()); + RetroApplication.getInstance().getContentResolver().notifyChange(Uri.parse("content://media"), null); // trigger media store changed to force artist image reload + + File file = getFile(artist); + if (!file.exists()) { + return null; + } else { + file.delete(); + } + return null; + } + }.execute(); + } + + // shared prefs saves us many IO operations + public boolean hasCustomArtistImage(Artist artist) { + return mPreferences.getBoolean(getFileName(artist), false); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/DensityUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/DensityUtil.java new file mode 100644 index 00000000..78aedd21 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/DensityUtil.java @@ -0,0 +1,54 @@ +package code.name.monkey.retromusic.util; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.util.DisplayMetrics; +import android.util.TypedValue; + +/** + * Created by hefuyi on 16/7/30. + */ +public class DensityUtil { + + public static int getScreenHeight(Context context) { + DisplayMetrics displayMetrics = new DisplayMetrics(); + ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + return displayMetrics.heightPixels; + } + + public static int getScreenWidth(Context context) { + DisplayMetrics displayMetrics = new DisplayMetrics(); + ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + return displayMetrics.widthPixels; + } + + public static int dip2px(Context context, float dpVale) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpVale * scale + 0.5f); + } + + public static int getStatusBarHeight(Context context) { + Resources resources = context.getResources(); + int resourcesId = resources.getIdentifier("status_bar_height", "dimen", "android"); + int height = resources.getDimensionPixelSize(resourcesId); + return height; + } + + /** + * Converts sp to px + * + * @param context Context + * @param sp the value in sp + * @return int + */ + public static int dip2sp(Context context, float sp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics()); + } + + public static int px2dip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/FileUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/FileUtil.java new file mode 100644 index 00000000..4ac97d3c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/FileUtil.java @@ -0,0 +1,251 @@ +package code.name.monkey.retromusic.util; + +import android.content.Context; +import android.database.Cursor; +import android.os.Environment; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.webkit.MimeTypeMap; +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.loaders.SortedCursor; +import code.name.monkey.retromusic.model.Song; +import io.reactivex.Observable; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + + +public final class FileUtil { + + private FileUtil() { + } + + public static byte[] readBytes(InputStream stream) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int count; + while ((count = stream.read(buffer)) != -1) { + baos.write(buffer, 0, count); + } + stream.close(); + return baos.toByteArray(); + } + + @NonNull + public static Observable> matchFilesWithMediaStore(@NonNull Context context, + @Nullable List files) { + return SongLoader.getSongs(makeSongCursor(context, files)); + } + + public static String safeGetCanonicalPath(File file) { + try { + return file.getCanonicalPath(); + } catch (IOException e) { + e.printStackTrace(); + return file.getAbsolutePath(); + } + } + + @Nullable + public static SortedCursor makeSongCursor(@NonNull final Context context, + @Nullable final List files) { + String selection = null; + String[] paths = null; + + if (files != null) { + paths = toPathArray(files); + + if (files.size() > 0 + && files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle. + selection = + MediaStore.Audio.AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")"; + } + } + + Cursor songCursor = SongLoader + .makeSongCursor(context, selection, selection == null ? null : paths); + + return songCursor == null ? null + : new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA); + } + + private static String makePlaceholders(int len) { + StringBuilder sb = new StringBuilder(len * 2 - 1); + sb.append("?"); + for (int i = 1; i < len; i++) { + sb.append(",?"); + } + return sb.toString(); + } + + @Nullable + private static String[] toPathArray(@Nullable List files) { + if (files != null) { + String[] paths = new String[files.size()]; + for (int i = 0; i < files.size(); i++) { + /*try { + paths[i] = files.get(i).getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later + } catch (IOException e) { + e.printStackTrace(); + paths[i] = files.get(i).getPath(); + }*/ + paths[i] = safeGetCanonicalPath(files.get(i)); + } + return paths; + } + return null; + } + + @NonNull + public static List listFiles(@NonNull File directory, @Nullable FileFilter fileFilter) { + List fileList = new LinkedList<>(); + File[] found = directory.listFiles(fileFilter); + if (found != null) { + Collections.addAll(fileList, found); + } + return fileList; + } + + @NonNull + public static List listFilesDeep(@NonNull File directory, @Nullable FileFilter fileFilter) { + List files = new LinkedList<>(); + internalListFilesDeep(files, directory, fileFilter); + return files; + } + + @NonNull + public static List listFilesDeep(@NonNull Collection files, + @Nullable FileFilter fileFilter) { + List resFiles = new LinkedList<>(); + for (File file : files) { + if (file.isDirectory()) { + internalListFilesDeep(resFiles, file, fileFilter); + } else if (fileFilter == null || fileFilter.accept(file)) { + resFiles.add(file); + } + } + return resFiles; + } + + private static void internalListFilesDeep(@NonNull Collection files, + @NonNull File directory, @Nullable FileFilter fileFilter) { + File[] found = directory.listFiles(fileFilter); + + if (found != null) { + for (File file : found) { + if (file.isDirectory()) { + internalListFilesDeep(files, file, fileFilter); + } else { + files.add(file); + } + } + } + } + + public static boolean fileIsMimeType(File file, String mimeType, MimeTypeMap mimeTypeMap) { + if (mimeType == null || mimeType.equals("*/*")) { + return true; + } else { + // get the file mime type + String filename = file.toURI().toString(); + int dotPos = filename.lastIndexOf('.'); + if (dotPos == -1) { + return false; + } + String fileExtension = filename.substring(dotPos + 1).toLowerCase(); + String fileType = mimeTypeMap.getMimeTypeFromExtension(fileExtension); + if (fileType == null) { + return false; + } + // check the 'type/subtype' pattern + if (fileType.equals(mimeType)) { + return true; + } + // check the 'type/*' pattern + int mimeTypeDelimiter = mimeType.lastIndexOf('/'); + if (mimeTypeDelimiter == -1) { + return false; + } + String mimeTypeMainType = mimeType.substring(0, mimeTypeDelimiter); + String mimeTypeSubtype = mimeType.substring(mimeTypeDelimiter + 1); + if (!mimeTypeSubtype.equals("*")) { + return false; + } + int fileTypeDelimiter = fileType.lastIndexOf('/'); + if (fileTypeDelimiter == -1) { + return false; + } + String fileTypeMainType = fileType.substring(0, fileTypeDelimiter); + if (fileTypeMainType.equals(mimeTypeMainType)) { + return true; + } + return fileTypeMainType.equals(mimeTypeMainType); + } + } + + public static String stripExtension(String str) { + if (str == null) { + return null; + } + int pos = str.lastIndexOf('.'); + if (pos == -1) { + return str; + } + return str.substring(0, pos); + } + + public static String readFromStream(InputStream is) throws Exception { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + if (sb.length() > 0) { + sb.append("\n"); + } + sb.append(line); + } + reader.close(); + return sb.toString(); + } + + public static String read(File file) throws Exception { + FileInputStream fin = new FileInputStream(file); + String ret = readFromStream(fin); + fin.close(); + return ret; + } + + public static boolean isExternalMemoryAvailable() { + Boolean isSDPresent = Environment.getExternalStorageState() + .equals(android.os.Environment.MEDIA_MOUNTED); + Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable(); + + if (isSDSupportedDevice && isSDPresent) { + // yes SD-card is present + return true; + } else { + return false; + // Sorry + } + } + + public static File safeGetCanonicalFile(File file) { + try { + return file.getCanonicalFile(); + } catch (IOException e) { + e.printStackTrace(); + return file.getAbsoluteFile(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/ImageUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/ImageUtil.java new file mode 100644 index 00000000..bb0a8f04 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/ImageUtil.java @@ -0,0 +1,222 @@ +package code.name.monkey.retromusic.util; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.media.ExifInterface; +import android.support.annotation.NonNull; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * Created on : June 18, 2016 Author : zetbaitsu Name : Zetra GitHub : + * https://github.com/zetbaitsu + */ +public class ImageUtil { + + private static final int TOLERANCE = 20; + // Alpha amount for which values below are considered transparent. + private static final int ALPHA_TOLERANCE = 50; + private static int[] mTempBuffer; + + private ImageUtil() { + + } + + public static boolean isGrayscale(Bitmap bitmap) { + final int height = bitmap.getHeight(); + final int width = bitmap.getWidth(); + int size = height * width; + ensureBufferSize(size); + bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height); + for (int i = 0; i < size; i++) { + if (!isGrayscale(mTempBuffer[i])) { + return false; + } + } + return true; + } + + /** + * Makes sure that {@code mTempBuffer} has at least length {@code size}. + */ + private static void ensureBufferSize(int size) { + if (mTempBuffer == null || mTempBuffer.length < size) { + mTempBuffer = new int[size]; + } + } + + public static Bitmap setBitmapColor(Bitmap bitmap, int color) { + Bitmap result = Bitmap + .createBitmap(bitmap, 0, 0, bitmap.getWidth() - 1, bitmap.getHeight() - 1); + Paint paint = new Paint(); + paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)); + + Canvas canvas = new Canvas(result); + canvas.drawBitmap(result, 0, 0, paint); + + return result; + } + + public static boolean isGrayscale(int color) { + int alpha = 0xFF & (color >> 24); + if (alpha < ALPHA_TOLERANCE) { + return true; + } + int r = 0xFF & (color >> 16); + int g = 0xFF & (color >> 8); + int b = 0xFF & color; + return Math.abs(r - g) < TOLERANCE + && Math.abs(r - b) < TOLERANCE + && Math.abs(g - b) < TOLERANCE; + } // Amount (max is 255) that two channels can differ before the color is no longer "gray". + + public static Bitmap resizeBitmap(@NonNull Bitmap src, int maxForSmallerSize) { + int width = src.getWidth(); + int height = src.getHeight(); + + final int dstWidth; + final int dstHeight; + + if (width < height) { + if (maxForSmallerSize >= width) { + return src; + } + float ratio = (float) height / width; + dstWidth = maxForSmallerSize; + dstHeight = Math.round(maxForSmallerSize * ratio); + } else { + if (maxForSmallerSize >= height) { + return src; + } + float ratio = (float) width / height; + dstWidth = Math.round(maxForSmallerSize * ratio); + dstHeight = maxForSmallerSize; + } + + return Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false); + } + + public static int calculateInSampleSize(int width, int height, int reqWidth) { + // setting reqWidth matching to desired 1:1 ratio and screen-size + if (width < height) { + reqWidth = (height / width) * reqWidth; + } else { + reqWidth = (width / height) * reqWidth; + } + + int inSampleSize = 1; + + if (height > reqWidth || width > reqWidth) { + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + // Calculate the largest inSampleSize value that is a power of 2 and keeps both + // height and width larger than the requested height and width. + while ((halfHeight / inSampleSize) > reqWidth + && (halfWidth / inSampleSize) > reqWidth) { + inSampleSize *= 2; + } + } + + return inSampleSize; + } + + static File compressImage(File imageFile, int reqWidth, int reqHeight, + Bitmap.CompressFormat compressFormat, int quality, String destinationPath) + throws IOException { + FileOutputStream fileOutputStream = null; + File file = new File(destinationPath).getParentFile(); + if (!file.exists()) { + file.mkdirs(); + } + try { + fileOutputStream = new FileOutputStream(destinationPath); + // write the compressed bitmap at the destination specified by destinationPath. + decodeSampledBitmapFromFile(imageFile, reqWidth, reqHeight) + .compress(compressFormat, quality, fileOutputStream); + } finally { + if (fileOutputStream != null) { + fileOutputStream.flush(); + fileOutputStream.close(); + } + } + + return new File(destinationPath); + } + + static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight) + throws IOException { + // First decode with inJustDecodeBounds=true to check dimensions + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options); + + // Calculate inSampleSize + options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); + + // Decode bitmap with inSampleSize set + options.inJustDecodeBounds = false; + + Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options); + + //check the rotation of the image and display it properly + ExifInterface exif; + exif = new ExifInterface(imageFile.getAbsolutePath()); + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0); + Matrix matrix = new Matrix(); + if (orientation == 6) { + matrix.postRotate(90); + } else if (orientation == 3) { + matrix.postRotate(180); + } else if (orientation == 8) { + matrix.postRotate(270); + } + scaledBitmap = Bitmap + .createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, + true); + return scaledBitmap; + } + + private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, + int reqHeight) { + // Raw height and width of image + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + // Calculate the largest inSampleSize value that is a power of 2 and keeps both + // height and width larger than the requested height and width. + while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { + inSampleSize *= 2; + } + } + + return inSampleSize; + } + + public static Bitmap getResizedBitmap(Bitmap image, int maxSize) { + int width = image.getWidth(); + int height = image.getHeight(); + + float bitmapRatio = (float) width / (float) height; + if (bitmapRatio > 1) { + width = maxSize; + height = (int) (width / bitmapRatio); + } else { + height = maxSize; + width = (int) (height * bitmapRatio); + } + return Bitmap.createScaledBitmap(image, width, height, true); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/LastFMUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/LastFMUtil.java new file mode 100755 index 00000000..d7d6fe1a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/LastFMUtil.java @@ -0,0 +1,69 @@ +package code.name.monkey.retromusic.util; + +import code.name.monkey.retromusic.rest.model.LastFmAlbum.Album.Image; +import code.name.monkey.retromusic.rest.model.LastFmArtist; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class LastFMUtil { + + public static String getLargestAlbumImageUrl(List list) { + Map hashMap = new HashMap(); + for (Image image : list) { + Object obj = null; + String size = image.getSize(); + if (size == null) { + obj = ImageSize.UNKNOWN; + } else { + try { + obj = ImageSize.valueOf(size.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException ignored) { + } + } + if (obj != null) { + hashMap.put(obj, image.getText()); + } + } + return getLargestImageUrl(hashMap); + } + + public static String getLargestArtistImageUrl(List list) { + Map hashMap = new HashMap(); + for (LastFmArtist.Artist.Image image : list) { + Object obj = null; + String size = image.getSize(); + if (size == null) { + obj = ImageSize.UNKNOWN; + } else { + try { + obj = ImageSize.valueOf(size.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException ignored) { + } + } + if (obj != null) { + hashMap.put(obj, image.getText()); + } + } + return getLargestImageUrl(hashMap); + } + + private static String getLargestImageUrl(Map map) { + return map.containsKey(ImageSize.MEGA) ? map.get(ImageSize.MEGA) + : map.containsKey(ImageSize.EXTRALARGE) ? map.get(ImageSize.EXTRALARGE) + : map.containsKey(ImageSize.LARGE) ? map.get(ImageSize.LARGE) + : map.containsKey(ImageSize.MEDIUM) ? map.get(ImageSize.MEDIUM) + : map.containsKey(ImageSize.SMALL) ? map.get(ImageSize.SMALL) + : map.containsKey(ImageSize.UNKNOWN) ? map.get(ImageSize.UNKNOWN) : null; + } + + private enum ImageSize { + SMALL, + MEDIUM, + LARGE, + EXTRALARGE, + MEGA, + UNKNOWN + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.java new file mode 100644 index 00000000..1af45380 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.java @@ -0,0 +1,103 @@ +package code.name.monkey.retromusic.util; + +import android.util.Base64; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; + +/** + * Created by hefuyi on 2016/11/8. + */ + +public class LyricUtil { + + private static final String lrcRootPath = android.os.Environment + .getExternalStorageDirectory().toString() + "/RetroMusic/lyrics/"; + + public static File writeLrcToLoc(String title, String artist, String lrcContext) { + FileWriter writer = null; + try { + File file = new File(getLrcPath(title, artist)); + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + writer = new FileWriter(getLrcPath(title, artist)); + writer.write(lrcContext); + return file; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + try { + if (writer != null) + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static boolean deleteLrcFile(String title, String artist) { + File file = new File(getLrcPath(title, artist)); + return file.delete(); + } + + public static boolean isLrcFileExist(String title, String artist) { + File file = new File(getLrcPath(title, artist)); + return file.exists(); + } + + public static File getLocalLyricFile(String title, String artist) { + File file = new File(getLrcPath(title, artist)); + if (file.exists()) { + return file; + } else { + return new File("lyric file not exist"); + } + } + + private static String getLrcPath(String title, String artist) { + return lrcRootPath + title + " - " + artist + ".lrc"; + } + + public static String decryptBASE64(String str) { + if (str == null || str.length() == 0) { + return null; + } + try { + byte[] encode = str.getBytes("UTF-8"); + // base64 解密 + return new String(Base64.decode(encode, 0, encode.length, Base64.DEFAULT), "UTF-8"); + + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + return null; + } + + public static String getStringFromFile(String title, String artist) throws Exception { + File file = new File(getLrcPath(title, artist)); + FileInputStream fin = new FileInputStream(file); + String ret = convertStreamToString(fin); + fin.close(); + return ret; + } + + private static String convertStreamToString(InputStream is) throws Exception { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + String line = null; + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + reader.close(); + return sb.toString(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java new file mode 100644 index 00000000..49b1c0a7 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java @@ -0,0 +1,410 @@ +package code.name.monkey.retromusic.util; + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Environment; +import android.provider.BaseColumns; +import android.provider.MediaStore; +import android.provider.Settings; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.content.FileProvider; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; + +import org.jaudiotagger.audio.AudioFileIO; +import org.jaudiotagger.tag.FieldKey; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.loaders.PlaylistLoader; +import code.name.monkey.retromusic.loaders.SongLoader; +import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics; +import io.reactivex.Observable; + + +public class MusicUtil { + + public static final String TAG = MusicUtil.class.getSimpleName(); + private static Playlist playlist; + + public static Uri getMediaStoreAlbumCoverUri(int albumId) { + final Uri sArtworkUri = Uri + .parse("content://media/external/audio/albumart"); + + return ContentUris.withAppendedId(sArtworkUri, albumId); + } + + public static Uri getSongFileUri(int songId) { + return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId); + } + + @NonNull + public static Intent createShareSongFileIntent(@NonNull final Song song, Context context) { + try { + + return new Intent() + .setAction(Intent.ACTION_SEND) + .putExtra(Intent.EXTRA_STREAM, + FileProvider.getUriForFile(context, + context.getApplicationContext().getPackageName(), + new File(song.data))) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + .setType("audio/*"); + } catch (IllegalArgumentException e) { + // TODO the path is most likely not like /storage/emulated/0/... but something like /storage/28C7-75B0/... + e.printStackTrace(); + Toast.makeText(context, "Could not share this file, I'm aware of the issue.", + Toast.LENGTH_SHORT).show(); + return new Intent(); + } + } + + public static void setRingtone(@NonNull final Context context, final int id) { + final ContentResolver resolver = context.getContentResolver(); + final Uri uri = getSongFileUri(id); + try { + final ContentValues values = new ContentValues(2); + values.put(MediaStore.Audio.AudioColumns.IS_RINGTONE, "1"); + values.put(MediaStore.Audio.AudioColumns.IS_ALARM, "1"); + resolver.update(uri, values, null, null); + } catch (@NonNull final UnsupportedOperationException ignored) { + return; + } + + try { + Cursor cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + new String[]{MediaStore.MediaColumns.TITLE}, + BaseColumns._ID + "=?", + new String[]{String.valueOf(id)}, + null); + try { + if (cursor != null && cursor.getCount() == 1) { + cursor.moveToFirst(); + Settings.System.putString(resolver, Settings.System.RINGTONE, uri.toString()); + final String message = context + .getString(R.string.x_has_been_set_as_ringtone, cursor.getString(0)); + Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + } catch (SecurityException ignored) { + } + } + + @NonNull + public static String getArtistInfoString(@NonNull final Context context, + @NonNull final Artist artist) { + int albumCount = artist.getAlbumCount(); + int songCount = artist.getSongCount(); + String albumString = albumCount == 1 ? context.getResources().getString(R.string.album) + : context.getResources().getString(R.string.albums); + String songString = songCount == 1 ? context.getResources().getString(R.string.song) + : context.getResources().getString(R.string.songs); + return albumCount + " " + albumString + " • " + songCount + " " + songString; + } + + @NonNull + public static String getArtistInfoStringSmall(@NonNull final Context context, + @NonNull final Artist artist) { + int songCount = artist.getSongCount(); + String songString = songCount == 1 ? context.getResources().getString(R.string.song) + : context.getResources().getString(R.string.songs); + return songCount + " " + songString; + } + + @NonNull + public static String getPlaylistInfoString(@NonNull final Context context, + @NonNull List songs) { + final int songCount = songs.size(); + final String songString = songCount == 1 ? context.getResources().getString(R.string.song) + : context.getResources().getString(R.string.songs); + + long duration = 0; + for (int i = 0; i < songs.size(); i++) { + duration += songs.get(i).duration; + } + + return songCount + " " + songString + " • " + MusicUtil.getReadableDurationString(duration); + } + + public static String getReadableDurationString(long songDurationMillis) { + long minutes = (songDurationMillis / 1000) / 60; + long seconds = (songDurationMillis / 1000) % 60; + if (minutes < 60) { + return String.format(Locale.getDefault(), "%01d:%02d", minutes, seconds); + } else { + long hours = minutes / 60; + minutes = minutes % 60; + return String.format(Locale.getDefault(), "%d:%02d:%02d", hours, minutes, seconds); + } + } + + //iTunes uses for example 1002 for track 2 CD1 or 3011 for track 11 CD3. + //this method converts those values to normal tracknumbers + public static int getFixedTrackNumber(int trackNumberToFix) { + return trackNumberToFix % 1000; + } + + public static void insertAlbumArt(@NonNull Context context, int albumId, String path) { + ContentResolver contentResolver = context.getContentResolver(); + + Uri artworkUri = Uri.parse("content://media/external/audio/albumart"); + contentResolver.delete(ContentUris.withAppendedId(artworkUri, albumId), null, null); + + ContentValues values = new ContentValues(); + values.put("album_id", albumId); + values.put("_data", path); + + contentResolver.insert(artworkUri, values); + } + + @NonNull + public static File createAlbumArtFile() { + return new File(createAlbumArtDir(), String.valueOf(System.currentTimeMillis())); + } + + @NonNull + @SuppressWarnings("ResultOfMethodCallIgnored") + private static File createAlbumArtDir() { + File albumArtDir = new File(Environment.getExternalStorageDirectory(), "/albumthumbs/"); + if (!albumArtDir.exists()) { + albumArtDir.mkdirs(); + try { + new File(albumArtDir, ".nomedia").createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return albumArtDir; + } + + public static void deleteTracks(@NonNull final Activity activity, + @NonNull final List songs) { + final String[] projection = new String[]{ + BaseColumns._ID, MediaStore.MediaColumns.DATA + }; + final StringBuilder selection = new StringBuilder(); + selection.append(BaseColumns._ID + " IN ("); + for (int i = 0; i < songs.size(); i++) { + selection.append(songs.get(i).id); + if (i < songs.size() - 1) { + selection.append(","); + } + } + selection.append(")"); + + try { + final Cursor cursor = activity.getContentResolver().query( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection.toString(), + null, null); + if (cursor != null) { + // Step 1: Remove selected tracks from the current playlist, as well + // as from the album art cache + cursor.moveToFirst(); + while (!cursor.isAfterLast()) { + final int id = cursor.getInt(0); + SongLoader.getSong(activity, id).subscribe(song -> { + MusicPlayerRemote.removeFromQueue(song); + cursor.moveToNext(); + }); + } + + // Step 2: Remove selected tracks from the database + activity.getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + selection.toString(), null); + + // Step 3: Remove files from card + cursor.moveToFirst(); + while (!cursor.isAfterLast()) { + final String name = cursor.getString(1); + try { // File.delete can throw a security exception + final File f = new File(name); + if (!f.delete()) { + // I'm not sure if we'd ever get here (deletion would + // have to fail, but no exception thrown) + Log.e("MusicUtils", "Failed to delete file " + name); + } + cursor.moveToNext(); + } catch (@NonNull final SecurityException ex) { + cursor.moveToNext(); + } catch (NullPointerException e) { + Log.e("MusicUtils", "Failed to find file " + name); + } + } + cursor.close(); + } + activity.getContentResolver().notifyChange(Uri.parse("content://media"), null); + Toast.makeText(activity, activity.getString(R.string.deleted_x_songs, songs.size()), + Toast.LENGTH_SHORT).show(); + } catch (SecurityException ignored) { + } + } + + public static void deleteAlbumArt(@NonNull Context context, int albumId) { + ContentResolver contentResolver = context.getContentResolver(); + Uri localUri = Uri.parse("content://media/external/audio/albumart"); + contentResolver.delete(ContentUris.withAppendedId(localUri, albumId), null, null); + } + + + @Nullable + public static String getLyrics(Song song) { + String lyrics = null; + + File file = new File(song.data); + + try { + lyrics = AudioFileIO.read(file).getTagOrCreateDefault().getFirst(FieldKey.LYRICS); + } catch (Exception e) { + e.printStackTrace(); + } + + if (lyrics == null || lyrics.trim().isEmpty() || !AbsSynchronizedLyrics + .isSynchronized(lyrics)) { + File dir = file.getAbsoluteFile().getParentFile(); + + if (dir != null && dir.exists() && dir.isDirectory()) { + String format = ".*%s.*\\.(lrc|txt)"; + String filename = Pattern.quote(FileUtil.stripExtension(file.getName())); + String songtitle = Pattern.quote(song.title); + + final ArrayList patterns = new ArrayList<>(); + patterns.add(Pattern.compile(String.format(format, filename), + Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)); + patterns.add(Pattern.compile(String.format(format, songtitle), + Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)); + + File[] files = dir.listFiles(f -> { + for (Pattern pattern : patterns) { + if (pattern.matcher(f.getName()).matches()) { + return true; + } + } + return false; + }); + + if (files != null && files.length > 0) { + for (File f : files) { + try { + String newLyrics = FileUtil.read(f); + if (newLyrics != null && !newLyrics.trim().isEmpty()) { + if (AbsSynchronizedLyrics.isSynchronized(newLyrics)) { + return newLyrics; + } + lyrics = newLyrics; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + } + + return lyrics; + } + + public static void toggleFavorite(@NonNull final Context context, @NonNull final Song song) { + if (isFavorite(context, song)) { + PlaylistsUtil + .removeFromPlaylist(context, song, getFavoritesPlaylist(context).blockingFirst().id); + } else { + PlaylistsUtil + .addToPlaylist(context, song, getOrCreateFavoritesPlaylist(context).blockingFirst().id, + false); + } + } + + public static boolean isFavoritePlaylist(@NonNull final Context context, + @NonNull final Playlist playlist) { + return playlist.name != null && playlist.name.equals(context.getString(R.string.favorites)); + } + + private static Observable getFavoritesPlaylist(@NonNull final Context context) { + return PlaylistLoader.getPlaylist(context, context.getString(R.string.favorites)); + } + + private static Observable getOrCreateFavoritesPlaylist(@NonNull final Context context) { + return PlaylistLoader.getPlaylist(context, + PlaylistsUtil.createPlaylist(context, context.getString(R.string.favorites))); + } + + public static boolean isFavorite(@NonNull final Context context, @NonNull final Song song) { + /*return Observable.create(e -> getFavoritesPlaylist(context).subscribe(playlist1 -> { + boolean isBoolean = PlaylistsUtil.doPlaylistContains(context, playlist1.id, song.id); + e.onNext(isBoolean); + e.onComplete(); + }));*/ + + //getFavoritesPlaylist(context).blockingFirst().id.subscribe(MusicUtil::setPlaylist); + //return PlaylistsUtil.doPlaylistContains(context, getFavoritesPlaylist(context).blockingFirst().id, song.id); + return PlaylistsUtil + .doPlaylistContains(context, getFavoritesPlaylist(context).blockingFirst().id, song.id); + } + + public static boolean isArtistNameUnknown(@Nullable String artistName) { + if (TextUtils.isEmpty(artistName)) return false; + if (artistName.equals(Artist.UNKNOWN_ARTIST_DISPLAY_NAME)) return true; + artistName = artistName.trim().toLowerCase(); + return artistName.equals("unknown") || artistName.equals(""); + } + + @NonNull + public static String getSectionName(@Nullable String musicMediaTitle) { + if (TextUtils.isEmpty(musicMediaTitle)) { + return ""; + } + musicMediaTitle = musicMediaTitle.trim().toLowerCase(); + if (musicMediaTitle.startsWith("the ")) { + musicMediaTitle = musicMediaTitle.substring(4); + } else if (musicMediaTitle.startsWith("a ")) { + musicMediaTitle = musicMediaTitle.substring(2); + } + if (musicMediaTitle.isEmpty()) { + return ""; + } + return String.valueOf(musicMediaTitle.charAt(0)).toUpperCase(); + } + + public static Playlist getPlaylist() { + return playlist; + } + + public static void setPlaylist(Playlist playlist) { + MusicUtil.playlist = playlist; + } + + public static long getTotalDuration(@NonNull final Context context, @NonNull List songs) { + long duration = 0; + for (int i = 0; i < songs.size(); i++) { + duration += songs.get(i).duration; + } + return duration; + } + + @NonNull + public static String getYearString(int year) { + return year > 0 ? String.valueOf(year) : "-"; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.java new file mode 100755 index 00000000..e86c0305 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.java @@ -0,0 +1,120 @@ +package code.name.monkey.retromusic.util; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.media.audiofx.AudioEffect; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.util.Pair; +import android.widget.Toast; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.MusicPlayerRemote; +import code.name.monkey.retromusic.model.Genre; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.ui.activities.AboutActivity; +import code.name.monkey.retromusic.ui.activities.AlbumDetailsActivity; +import code.name.monkey.retromusic.ui.activities.ArtistDetailActivity; +import code.name.monkey.retromusic.ui.activities.EqualizerActivity; +import code.name.monkey.retromusic.ui.activities.GenreDetailsActivity; +import code.name.monkey.retromusic.ui.activities.LicenseActivity; +import code.name.monkey.retromusic.ui.activities.LyricsActivity; +import code.name.monkey.retromusic.ui.activities.MainActivity; +import code.name.monkey.retromusic.ui.activities.PlayingQueueActivity; +import code.name.monkey.retromusic.ui.activities.PlaylistDetailActivity; +import code.name.monkey.retromusic.ui.activities.ProVersionActivity; +import code.name.monkey.retromusic.ui.activities.SearchActivity; +import code.name.monkey.retromusic.ui.activities.SettingsActivity; +import code.name.monkey.retromusic.ui.activities.UserInfoActivity; + +import static code.name.monkey.retromusic.ui.activities.GenreDetailsActivity.EXTRA_GENRE_ID; + +public class NavigationUtil { + public static void goToAlbum(@NonNull Activity activity, int i, @Nullable Pair... sharedElements) { + Intent intent = new Intent(activity, AlbumDetailsActivity.class); + intent.putExtra(AlbumDetailsActivity.EXTRA_ALBUM_ID, i); + //noinspection unchecked + ActivityCompat.startActivity(activity, intent, + ActivityOptionsCompat.makeSceneTransitionAnimation(activity, sharedElements).toBundle()); + } + + public static void goToArtist(@NonNull Activity activity, int i, @Nullable Pair... sharedElements) { + Intent intent = new Intent(activity, ArtistDetailActivity.class); + intent.putExtra(ArtistDetailActivity.EXTRA_ARTIST_ID, i); + //noinspection unchecked + ActivityCompat.startActivity(activity, intent, null); + } + + public static void goToPlaylistNew(@NonNull Activity activity, Playlist playlist) { + Intent intent = new Intent(activity, PlaylistDetailActivity.class); + intent.putExtra(PlaylistDetailActivity.EXTRA_PLAYLIST, playlist); + ActivityCompat.startActivity(activity, intent, null); + } + + public static void openEqualizer(@NonNull final Activity activity) { + if (PreferenceUtil.getInstance(activity).getSelectedEqualizer().equals("system")) { + stockEqalizer(activity); + } else { + ActivityCompat.startActivity(activity, new Intent(activity, EqualizerActivity.class), null); + } + } + + private static void stockEqalizer(@NonNull Activity activity) { + final int sessionId = MusicPlayerRemote.getAudioSessionId(); + if (sessionId == AudioEffect.ERROR_BAD_VALUE) { + Toast.makeText(activity, activity.getResources().getString(R.string.no_audio_ID), Toast.LENGTH_LONG).show(); + } else { + try { + final Intent effects = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL); + effects.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, sessionId); + effects.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC); + activity.startActivityForResult(effects, 0); + } catch (@NonNull final ActivityNotFoundException notFound) { + Toast.makeText(activity, activity.getResources().getString(R.string.no_equalizer), Toast.LENGTH_SHORT).show(); + } + } + } + + public static void goToPlayingQueue(@NonNull Activity activity) { + Intent intent = new Intent(activity, PlayingQueueActivity.class); + ActivityCompat.startActivity(activity, intent, null); + } + + public static void goToLyrics(@NonNull Activity activity) { + Intent intent = new Intent(activity, LyricsActivity.class); + ActivityCompat.startActivity(activity, intent, null); + } + + public static void goToGenre(@NonNull Activity activity, @NonNull Genre genre) { + Intent intent = new Intent(activity, GenreDetailsActivity.class); + intent.putExtra(EXTRA_GENRE_ID, genre); + ActivityCompat.startActivity(activity, intent, null); + } + + public static void goToProVersion(@NonNull Activity activity) { + ActivityCompat.startActivity(activity, new Intent(activity, ProVersionActivity.class), null); + } + + public static void goToSettings(@NonNull Activity activity) { + ActivityCompat.startActivity(activity, new Intent(activity, SettingsActivity.class), null); + } + + public static void goToAbout(@NonNull Activity activity) { + ActivityCompat.startActivity(activity, new Intent(activity, AboutActivity.class), null); + } + + public static void goToUserInfo(@NonNull Activity activity) { + ActivityCompat.startActivity(activity, new Intent(activity, UserInfoActivity.class), null); + } + + public static void goToOpenSource(@NonNull Activity activity) { + ActivityCompat.startActivity(activity, new Intent(activity, LicenseActivity.class), null); + } + + public static void goToSearch(Activity activity) { + ActivityCompat.startActivity(activity, new Intent(activity, SearchActivity.class), null); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java new file mode 100644 index 00000000..cb82867e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java @@ -0,0 +1,250 @@ +package code.name.monkey.retromusic.util; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Environment; +import android.provider.BaseColumns; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.widget.Toast; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.helper.M3UWriter; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.PlaylistSong; +import code.name.monkey.retromusic.model.Song; +import io.reactivex.Observable; + +import static android.provider.MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI; + + +public class PlaylistsUtil { + public static boolean doesPlaylistExist(@NonNull final Context context, final int playlistId) { + if (playlistId == -1) { + return false; + } + + Cursor cursor = context.getContentResolver().query( + MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId), + new String[]{}, null, null, null); + + if (cursor == null || cursor.getCount() == 0) { + return false; + } + + cursor.close(); + return true; + } + + public static int createPlaylist(@NonNull final Context context, @Nullable final String name) { + int id = -1; + if (name != null && name.length() > 0) { + try { + Cursor cursor = context.getContentResolver().query(EXTERNAL_CONTENT_URI, + new String[]{MediaStore.Audio.Playlists._ID}, MediaStore.Audio.PlaylistsColumns.NAME + "=?", new String[]{name}, null); + if (cursor == null || cursor.getCount() < 1) { + final ContentValues values = new ContentValues(1); + values.put(MediaStore.Audio.PlaylistsColumns.NAME, name); + final Uri uri = context.getContentResolver().insert( + EXTERNAL_CONTENT_URI, + values); + if (uri != null) { + // necessary because somehow the MediaStoreObserver is not notified when adding a playlist + context.getContentResolver().notifyChange(Uri.parse("content://media"), null); + Toast.makeText(context, context.getResources().getString( + R.string.created_playlist_x, name), Toast.LENGTH_SHORT).show(); + id = Integer.parseInt(uri.getLastPathSegment()); + } + } else { + if (cursor.moveToFirst()) { + id = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Playlists._ID)); + } + } + if (cursor != null) { + cursor.close(); + } + } catch (SecurityException ignored) { + } + } + if (id == -1) { + Toast.makeText(context, context.getResources().getString( + R.string.could_not_create_playlist), Toast.LENGTH_SHORT).show(); + } + return id; + } + + public static void deletePlaylists(@NonNull final Context context, @NonNull final ArrayList playlists) { + final StringBuilder selection = new StringBuilder(); + selection.append(MediaStore.Audio.Playlists._ID + " IN ("); + for (int i = 0; i < playlists.size(); i++) { + selection.append(playlists.get(i).id); + if (i < playlists.size() - 1) { + selection.append(","); + } + } + selection.append(")"); + try { + context.getContentResolver().delete(EXTERNAL_CONTENT_URI, selection.toString(), null); + } catch (SecurityException ignored) { + } + } + + public static void addToPlaylist(@NonNull final Context context, final Song song, final int playlistId, final boolean showToastOnFinish) { + List helperList = new ArrayList<>(); + helperList.add(song); + addToPlaylist(context, helperList, playlistId, showToastOnFinish); + } + + public static void addToPlaylist(@NonNull final Context context, @NonNull final List songs, final int playlistId, final boolean showToastOnFinish) { + final int size = songs.size(); + final ContentResolver resolver = context.getContentResolver(); + final String[] projection = new String[]{ + "max(" + MediaStore.Audio.Playlists.Members.PLAY_ORDER + ")", + }; + final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId); + Cursor cursor = null; + int base = 0; + + try { + try { + cursor = resolver.query(uri, projection, null, null, null); + + if (cursor != null && cursor.moveToFirst()) { + base = cursor.getInt(0) + 1; + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + + int numInserted = 0; + for (int offSet = 0; offSet < size; offSet += 1000) + numInserted += resolver.bulkInsert(uri, makeInsertItems(songs, offSet, 1000, base)); + + if (showToastOnFinish) { + Toast.makeText(context, context.getResources().getString( + R.string.inserted_x_songs_into_playlist_x, numInserted, getNameForPlaylist(context, playlistId)), Toast.LENGTH_SHORT).show(); + } + } catch (SecurityException ignored) { + } + } + + @NonNull + public static ContentValues[] makeInsertItems(@NonNull final List songs, final int offset, int len, final int base) { + if (offset + len > songs.size()) { + len = songs.size() - offset; + } + + ContentValues[] contentValues = new ContentValues[len]; + + for (int i = 0; i < len; i++) { + contentValues[i] = new ContentValues(); + contentValues[i].put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, base + offset + i); + contentValues[i].put(MediaStore.Audio.Playlists.Members.AUDIO_ID, songs.get(offset + i).id); + } + return contentValues; + } + + public static void removeFromPlaylist(@NonNull final Context context, @NonNull final Song song, int playlistId) { + Uri uri = MediaStore.Audio.Playlists.Members.getContentUri( + "external", playlistId); + String selection = MediaStore.Audio.Playlists.Members.AUDIO_ID + " =?"; + String[] selectionArgs = new String[]{String.valueOf(song.id)}; + + try { + context.getContentResolver().delete(uri, selection, selectionArgs); + } catch (SecurityException ignored) { + } + } + + public static void removeFromPlaylist(@NonNull final Context context, @NonNull final List songs) { + final int playlistId = songs.get(0).playlistId; + Uri uri = MediaStore.Audio.Playlists.Members.getContentUri( + "external", playlistId); + String selectionArgs[] = new String[songs.size()]; + for (int i = 0; i < selectionArgs.length; i++) { + selectionArgs[i] = String.valueOf(songs.get(i).idInPlayList); + } + String selection = MediaStore.Audio.Playlists.Members._ID + " in ("; + //noinspection unused + for (String selectionArg : selectionArgs) selection += "?, "; + selection = selection.substring(0, selection.length() - 2) + ")"; + + try { + context.getContentResolver().delete(uri, selection, selectionArgs); + } catch (SecurityException ignored) { + } + } + + public static boolean doPlaylistContains(@NonNull final Context context, final long playlistId, final int songId) { + if (playlistId != -1) { + try { + Cursor c = context.getContentResolver().query( + MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId), + new String[]{MediaStore.Audio.Playlists.Members.AUDIO_ID}, MediaStore.Audio.Playlists.Members.AUDIO_ID + "=?", new String[]{String.valueOf(songId)}, null); + int count = 0; + if (c != null) { + count = c.getCount(); + c.close(); + } + return count > 0; + } catch (SecurityException ignored) { + } + } + return false; + } + + public static boolean moveItem(@NonNull final Context context, int playlistId, int from, int to) { + return MediaStore.Audio.Playlists.Members.moveItem(context.getContentResolver(), + playlistId, from, to); + } + + public static void renamePlaylist(@NonNull final Context context, final long id, final String newName) { + ContentValues contentValues = new ContentValues(); + contentValues.put(MediaStore.Audio.PlaylistsColumns.NAME, newName); + try { + context.getContentResolver().update(EXTERNAL_CONTENT_URI, + contentValues, + MediaStore.Audio.Playlists._ID + "=?", + new String[]{String.valueOf(id)}); + context.getContentResolver().notifyChange(Uri.parse("content://media"), null); + } catch (SecurityException ignored) { + } + } + + public static String getNameForPlaylist(@NonNull final Context context, final long id) { + try { + Cursor cursor = context.getContentResolver().query( + EXTERNAL_CONTENT_URI, + new String[]{MediaStore.Audio.PlaylistsColumns.NAME}, + BaseColumns._ID + "=?", + new String[]{String.valueOf(id)}, + null); + if (cursor != null) { + try { + if (cursor.moveToFirst()) { + return cursor.getString(0); + } + } finally { + cursor.close(); + } + } + } catch (SecurityException ignored) { + } + return ""; + } + + public static Observable savePlaylist(Context context, Playlist playlist) { + return M3UWriter.write(context, new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist); + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java new file mode 100644 index 00000000..3192aa36 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java @@ -0,0 +1,705 @@ +package code.name.monkey.retromusic.util; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.content.res.TypedArray; +import android.preference.PreferenceManager; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.StyleRes; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; + +import java.io.File; +import java.lang.reflect.Type; +import java.util.ArrayList; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.helper.SortOrder; +import code.name.monkey.retromusic.model.CategoryInfo; +import code.name.monkey.retromusic.ui.fragments.NowPlayingScreen; +import code.name.monkey.retromusic.ui.fragments.mainactivity.folders.FoldersFragment; + +public final class PreferenceUtil { + + public static final String KEEP_SCREEN_ON = "keep_screen_on"; + public static final String NOW_PLAYING_SCREEN_ID = "now_playing_screen_id"; + public static final String CAROUSEL_EFFECT = "carousel_effect"; + public static final String COLORED_NOTIFICATION = "colored_notification"; + public static final String CLASSIC_NOTIFICATION = "classic_notification"; + public static final String GAPLESS_PLAYBACK = "gapless_playback"; + public static final String ALBUM_ART_ON_LOCKSCREEN = "album_art_on_lockscreen"; + public static final String BLURRED_ALBUM_ART = "blurred_album_art"; + public static final String TOGGLE_HEADSET = "toggle_headset"; + public static final String DOMINANT_COLOR = "dominant_color"; + public static final String GENERAL_THEME = "general_theme"; + public static final String CIRCULAR_ALBUM_ART = "circular_album_art"; + public static final String USER_NAME = "user_name"; + public static final String TOGGLE_FULL_SCREEN = "toggle_full_screen"; + public static final String TOGGLE_VOLUME = "toggle_volume"; + public static final String TOGGLE_TAB_TITLES = "toggle_tab_titles"; + public static final String ROUND_CORNERS = "corner_window"; + public static final String TOGGLE_GENRE = "toggle_genre"; + public static final String PROFILE_IMAGE_PATH = "profile_image_path"; + public static final String BANNER_IMAGE_PATH = "banner_image_path"; + public static final String ADAPTIVE_COLOR_APP = "adaptive_color_app"; + public static final String TOGGLE_SEPARATE_LINE = "toggle_separate_line"; + private static final String GENRE_SORT_ORDER = "genre_sort_order"; + private static final String ALBUM_GRID_STYLE = "album_grid_style"; + private static final String ARTIST_GRID_STYLE = "artist_grid_style"; + private static final String LIBRARY_CATEGORIES = "library_categories"; + private static final String LAST_PAGE = "last_start_page"; + private static final String LAST_MUSIC_CHOOSER = "last_music_chooser"; + private static final String DEFAULT_START_PAGE = "default_start_page"; + private static final String INITIALIZED_BLACKLIST = "initialized_blacklist"; + private static final String ARTIST_SORT_ORDER = "artist_sort_order"; + private static final String ARTIST_SONG_SORT_ORDER = "artist_song_sort_order"; + private static final String ARTIST_ALBUM_SORT_ORDER = "artist_album_sort_order"; + private static final String ALBUM_SORT_ORDER = "album_sort_order"; + private static final String ALBUM_SONG_SORT_ORDER = "album_song_sort_order"; + private static final String SONG_SORT_ORDER = "song_sort_order"; + private static final String ALBUM_GRID_SIZE = "album_grid_size"; + private static final String ALBUM_GRID_SIZE_LAND = "album_grid_size_land"; + private static final String SONG_GRID_SIZE = "song_grid_size"; + private static final String SONG_GRID_SIZE_LAND = "song_grid_size_land"; + private static final String ARTIST_GRID_SIZE = "artist_grid_size"; + private static final String ARTIST_GRID_SIZE_LAND = "artist_grid_size_land"; + private static final String ALBUM_COLORED_FOOTERS = "album_colored_footers"; + private static final String SONG_COLORED_FOOTERS = "song_colored_footers"; + private static final String ARTIST_COLORED_FOOTERS = "artist_colored_footers"; + private static final String ALBUM_ARTIST_COLORED_FOOTERS = "album_artist_colored_footers"; + private static final String COLORED_APP_SHORTCUTS = "colored_app_shortcuts"; + private static final String AUDIO_DUCKING = "audio_ducking"; + private static final String LAST_ADDED_CUTOFF = "last_added_interval"; + private static final String LAST_SLEEP_TIMER_VALUE = "last_sleep_timer_value"; + private static final String NEXT_SLEEP_TIMER_ELAPSED_REALTIME = "next_sleep_timer_elapsed_real_time"; + private static final String IGNORE_MEDIA_STORE_ARTWORK = "ignore_media_store_artwork"; + private static final String LAST_CHANGELOG_VERSION = "last_changelog_version"; + private static final String INTRO_SHOWN = "intro_shown"; + private static final String AUTO_DOWNLOAD_IMAGES_POLICY = "auto_download_images_policy"; + private static final String START_DIRECTORY = "start_directory"; + private static final String SYNCHRONIZED_LYRICS_SHOW = "synchronized_lyrics_show"; + private static final String LOCK_SCREEN = "lock_screen"; + private static final String ALBUM_DETAIL_SONG_SORT_ORDER = "album_detail_song_sort_order"; + private static final String ARTIST_DETAIL_SONG_SORT_ORDER = "artist_detail_song_sort_order"; + private static final String LYRICS_OPTIONS = "lyrics_options"; + private static final String SAF_SDCARD_URI = "saf_sdcard_uri"; + private static final String DOCUMENT_TREE_URI = "document_tree_uri"; + private static final String CHOOSE_EQUALIZER = "choose_equalizer"; + private static final String TOGGLE_SHUFFLE = "toggle_shuffle"; + private static final String SONG_GRID_STYLE = "song_grid_style"; + private static final String TOGGLE_ANIMATIONS = "toggle_animations"; + private static final String TAG = "PreferenceUtil"; + private static PreferenceUtil sInstance; + private final SharedPreferences mPreferences; + + private PreferenceUtil(@NonNull final Context context) { + mPreferences = PreferenceManager.getDefaultSharedPreferences(context); + } + + public static PreferenceUtil getInstance(@NonNull final Context context) { + if (sInstance == null) { + sInstance = new PreferenceUtil(context.getApplicationContext()); + } + return sInstance; + } + + @StyleRes + public static int getThemeResFromPrefValue(String themePrefValue) { + switch (themePrefValue) { + case "dark": + return R.style.Theme_RetroMusic; + case "color": + return R.style.Theme_RetroMusic_Color; + case "acolor": + return R.style.Theme_RetroMusic_Black; + case "black": + return R.style.Theme_RetroMusic_Black; + case "light": + default: + return R.style.Theme_RetroMusic_Light; + } + } + + public int getAlbumDetailsPageStyle() { + + TypedArray typedArray = RetroApplication.getInstance(). + getResources().obtainTypedArray(R.array.pref_album_detail_style_values); + int layout = typedArray.getResourceId(mPreferences.getInt("album_detail_style", 0), -1); + typedArray.recycle(); + return layout; + } + + public final String getArtistSortOrder() { + return mPreferences.getString(ARTIST_SORT_ORDER, SortOrder.ArtistSortOrder.ARTIST_A_Z); + } + + public void setArtistSortOrder(final String sortOrder) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putString(ARTIST_SORT_ORDER, sortOrder); + editor.apply(); + } + + public final String getArtistSongSortOrder() { + return mPreferences.getString(ARTIST_SONG_SORT_ORDER, SortOrder.ArtistSongSortOrder.SONG_A_Z); + } + + public final String getArtistAlbumSortOrder() { + return mPreferences + .getString(ARTIST_ALBUM_SORT_ORDER, SortOrder.ArtistAlbumSortOrder.ALBUM_YEAR); + } + + public final String getAlbumSortOrder() { + return mPreferences.getString(ALBUM_SORT_ORDER, SortOrder.AlbumSortOrder.ALBUM_A_Z); + } + + public void setAlbumSortOrder(final String sortOrder) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putString(ALBUM_SORT_ORDER, sortOrder); + editor.apply(); + } + + public final String getAlbumSongSortOrder() { + return mPreferences + .getString(ALBUM_SONG_SORT_ORDER, SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST); + } + + public final String getSongSortOrder() { + return mPreferences.getString(SONG_SORT_ORDER, SortOrder.SongSortOrder.SONG_A_Z); + } + + public void setSongSortOrder(final String sortOrder) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putString(SONG_SORT_ORDER, sortOrder); + editor.commit(); + } + + public final String getGenreSortOrder() { + return mPreferences.getString(GENRE_SORT_ORDER, SortOrder.GenreSortOrder.GENRE_A_Z); + } + + public boolean isScreenOnEnabled() { + return mPreferences.getBoolean(KEEP_SCREEN_ON, false); + } + + public void setInitializedBlacklist() { + final Editor editor = mPreferences.edit(); + editor.putBoolean(INITIALIZED_BLACKLIST, true); + editor.apply(); + } + + public final boolean initializedBlacklist() { + return mPreferences.getBoolean(INITIALIZED_BLACKLIST, false); + } + + + public boolean circularAlbumArt() { + return mPreferences.getBoolean(CIRCULAR_ALBUM_ART, false); + } + + public boolean carouselEffect() { + return mPreferences.getBoolean(CAROUSEL_EFFECT, false); + } + + public ArrayList getLibraryCategoryInfos() { + String data = mPreferences.getString(LIBRARY_CATEGORIES, null); + if (data != null) { + Gson gson = new Gson(); + Type collectionType = new TypeToken>() { + }.getType(); + + try { + return gson.fromJson(data, collectionType); + } catch (JsonSyntaxException e) { + e.printStackTrace(); + } + } + + return getDefaultLibraryCategoryInfos(); + } + + public void setLibraryCategoryInfos(ArrayList categories) { + Gson gson = new Gson(); + Type collectionType = new TypeToken>() { + }.getType(); + + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putString(LIBRARY_CATEGORIES, gson.toJson(categories, collectionType)); + editor.apply(); + } + + public ArrayList getDefaultLibraryCategoryInfos() { + ArrayList defaultCategoryInfos = new ArrayList<>(5); + defaultCategoryInfos.add(new CategoryInfo(CategoryInfo.Category.SONGS, true)); + defaultCategoryInfos.add(new CategoryInfo(CategoryInfo.Category.ALBUMS, true)); + defaultCategoryInfos.add(new CategoryInfo(CategoryInfo.Category.ARTISTS, true)); + defaultCategoryInfos.add(new CategoryInfo(CategoryInfo.Category.GENRES, true)); + defaultCategoryInfos.add(new CategoryInfo(CategoryInfo.Category.PLAYLISTS, true)); + return defaultCategoryInfos; + } + + public boolean isRoundCorners() { + return mPreferences.getBoolean(ROUND_CORNERS, false); + } + + public void registerOnSharedPreferenceChangedListener( + SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener) { + mPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); + } + + public void unregisterOnSharedPreferenceChangedListener( + SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener) { + mPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); + } + + public final int getDefaultStartPage() { + return Integer.parseInt(mPreferences.getString(DEFAULT_START_PAGE, "-1")); + } + + + public final int getLastPage() { + return mPreferences.getInt(LAST_PAGE, 0); + } + + public void setLastPage(final int value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(LAST_PAGE, value); + editor.apply(); + } + + public final int getLastMusicChooser() { + return mPreferences.getInt(LAST_MUSIC_CHOOSER, 0); + } + + public void setLastMusicChooser(final int value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(LAST_MUSIC_CHOOSER, value); + editor.apply(); + } + + public final boolean coloredNotification() { + return mPreferences.getBoolean(COLORED_NOTIFICATION, true); + } + + public final boolean classicNotification() { + return mPreferences.getBoolean(CLASSIC_NOTIFICATION, false); + } + + public void setClassicNotification(final boolean value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putBoolean(CLASSIC_NOTIFICATION, value); + editor.apply(); + } + + public final NowPlayingScreen getNowPlayingScreen() { + int id = mPreferences.getInt(NOW_PLAYING_SCREEN_ID, 0); + for (NowPlayingScreen nowPlayingScreen : NowPlayingScreen.values()) { + if (nowPlayingScreen.id == id) { + return nowPlayingScreen; + } + } + return NowPlayingScreen.NORMAL; + } + + @SuppressLint("CommitPrefEdits") + public void setNowPlayingScreen(NowPlayingScreen nowPlayingScreen) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(NOW_PLAYING_SCREEN_ID, nowPlayingScreen.id); + editor.apply(); + } + + public void setColoredAppShortcuts(final boolean value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putBoolean(COLORED_APP_SHORTCUTS, value); + editor.apply(); + } + + public final boolean coloredAppShortcuts() { + return mPreferences.getBoolean(COLORED_APP_SHORTCUTS, true); + } + + public final boolean gaplessPlayback() { + return mPreferences.getBoolean(GAPLESS_PLAYBACK, false); + } + + public final boolean audioDucking() { + return mPreferences.getBoolean(AUDIO_DUCKING, true); + } + + public final boolean albumArtOnLockscreen() { + return mPreferences.getBoolean(ALBUM_ART_ON_LOCKSCREEN, true); + } + + public final boolean blurredAlbumArt() { + return mPreferences.getBoolean(BLURRED_ALBUM_ART, false); + } + + public final boolean ignoreMediaStoreArtwork() { + return mPreferences.getBoolean(IGNORE_MEDIA_STORE_ARTWORK, false); + } + + + public int getLastSleepTimerValue() { + return mPreferences.getInt(LAST_SLEEP_TIMER_VALUE, 30); + } + + public void setLastSleepTimerValue(final int value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(LAST_SLEEP_TIMER_VALUE, value); + editor.apply(); + } + + public long getNextSleepTimerElapsedRealTime() { + return mPreferences.getLong(NEXT_SLEEP_TIMER_ELAPSED_REALTIME, -1); + } + + public void setNextSleepTimerElapsedRealtime(final long value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putLong(NEXT_SLEEP_TIMER_ELAPSED_REALTIME, value); + editor.apply(); + } + + public final int getAlbumGridSize(Context context) { + return mPreferences + .getInt(ALBUM_GRID_SIZE, context.getResources().getInteger(R.integer.default_grid_columns)); + } + + public void setSongGridSize(final int gridSize) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(SONG_GRID_SIZE, gridSize); + editor.apply(); + } + + public final int getSongGridSize(Context context) { + return mPreferences + .getInt(SONG_GRID_SIZE, context.getResources().getInteger(R.integer.default_list_columns)); + } + + public void setArtistGridSize(final int gridSize) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(ARTIST_GRID_SIZE, gridSize); + editor.apply(); + } + + public final int getArtistGridSize(Context context) { + return mPreferences.getInt(ARTIST_GRID_SIZE, + context.getResources().getInteger(R.integer.default_list_artist_columns)); + } + + public void setAlbumGridSizeLand(final int gridSize) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(ALBUM_GRID_SIZE_LAND, gridSize); + editor.apply(); + } + + public final int getAlbumGridSizeLand(Context context) { + return mPreferences.getInt(ALBUM_GRID_SIZE_LAND, + context.getResources().getInteger(R.integer.default_grid_columns_land)); + } + + public void setSongGridSizeLand(final int gridSize) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(SONG_GRID_SIZE_LAND, gridSize); + editor.apply(); + } + + public final int getSongGridSizeLand(Context context) { + return mPreferences.getInt(SONG_GRID_SIZE_LAND, + context.getResources().getInteger(R.integer.default_list_columns_land)); + } + + public void setArtistGridSizeLand(final int gridSize) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(ARTIST_GRID_SIZE_LAND, gridSize); + editor.apply(); + } + + public final int getArtistGridSizeLand(Context context) { + return mPreferences.getInt(ARTIST_GRID_SIZE_LAND, + context.getResources().getInteger(R.integer.default_list_artist_columns_land)); + } + + public void setAlbumGridSize(final int gridSize) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(ALBUM_GRID_SIZE, gridSize); + editor.apply(); + } + + public void setAlbumColoredFooters(final boolean value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putBoolean(ALBUM_COLORED_FOOTERS, value); + editor.apply(); + } + + public final boolean albumColoredFooters() { + return mPreferences.getBoolean(ALBUM_COLORED_FOOTERS, false); + } + + public void setAlbumArtistColoredFooters(final boolean value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putBoolean(ALBUM_ARTIST_COLORED_FOOTERS, value); + editor.apply(); + } + + public final boolean albumArtistColoredFooters() { + return mPreferences.getBoolean(ALBUM_ARTIST_COLORED_FOOTERS, true); + } + + public void setSongColoredFooters(final boolean value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putBoolean(SONG_COLORED_FOOTERS, value); + editor.apply(); + } + + public final boolean songColoredFooters() { + return mPreferences.getBoolean(SONG_COLORED_FOOTERS, false); + } + + public void setArtistColoredFooters(final boolean value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putBoolean(ARTIST_COLORED_FOOTERS, value); + editor.apply(); + } + + public final boolean artistColoredFooters() { + return mPreferences.getBoolean(ARTIST_COLORED_FOOTERS, true); + } + + public void setLastChangeLogVersion(int version) { + mPreferences.edit().putInt(LAST_CHANGELOG_VERSION, version).apply(); + } + + public final int getLastChangelogVersion() { + return mPreferences.getInt(LAST_CHANGELOG_VERSION, -1); + } + + @SuppressLint("CommitPrefEdits") + public void setIntroShown() { + // don't use apply here + mPreferences.edit().putBoolean(INTRO_SHOWN, true).commit(); + } + + public final File getStartDirectory() { + return new File(mPreferences + .getString(START_DIRECTORY, FoldersFragment.getDefaultStartDirectory().getPath())); + } + + public void setStartDirectory(File file) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putString(START_DIRECTORY, FileUtil.safeGetCanonicalPath(file)); + editor.apply(); + } + + public final boolean introShown() { + return mPreferences.getBoolean(INTRO_SHOWN, false); + } + + public final String autoDownloadImagesPolicy() { + return mPreferences.getString(AUTO_DOWNLOAD_IMAGES_POLICY, "only_wifi"); + } + + public final boolean synchronizedLyricsShow() { + return mPreferences.getBoolean(SYNCHRONIZED_LYRICS_SHOW, true); + } + + public int getGeneralTheme() { + return getThemeResFromPrefValue(mPreferences.getString(GENERAL_THEME, "light")); + } + + public void setGeneralTheme(String theme) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putString(GENERAL_THEME, theme); + editor.apply(); + } + + public long getLastAddedCutoff() { + final CalendarUtil calendarUtil = new CalendarUtil(); + long interval; + + switch (mPreferences.getString(LAST_ADDED_CUTOFF, "")) { + case "today": + interval = calendarUtil.getElapsedToday(); + break; + case "this_week": + interval = calendarUtil.getElapsedWeek(); + break; + case "past_three_months": + interval = calendarUtil.getElapsedMonths(3); + break; + case "this_year": + interval = calendarUtil.getElapsedYear(); + break; + case "this_month": + default: + interval = calendarUtil.getElapsedMonth(); + break; + } + + return (System.currentTimeMillis() - interval) / 1000; + } + + public boolean getAdaptiveColor() { + return mPreferences.getBoolean(ADAPTIVE_COLOR_APP, false); + } + + public boolean getLockScreen() { + return mPreferences.getBoolean(LOCK_SCREEN, false); + } + + public String getUserName() { + return mPreferences.getString(USER_NAME, "User"); + } + + public void setUserName(String name) { + mPreferences.edit().putString(USER_NAME, name).apply(); + } + + public boolean getFullScreenMode() { + return mPreferences.getBoolean(TOGGLE_FULL_SCREEN, false); + } + + public void setFullScreenMode(int newValue) { + mPreferences.edit().putInt(TOGGLE_FULL_SCREEN, newValue).apply(); + } + + public String lyricsOptions() { + return mPreferences.getString(LYRICS_OPTIONS, "offline"); + } + + public void saveProfileImage(String profileImagePath) { + mPreferences.edit().putString(PROFILE_IMAGE_PATH, profileImagePath) + .apply(); + + } + + public String getProfileImage() { + return mPreferences.getString(PROFILE_IMAGE_PATH, ""); + } + + public String getBannerImage() { + return mPreferences.getString(BANNER_IMAGE_PATH, ""); + } + + public void setBannerImagePath(String bannerImagePath) { + mPreferences.edit().putString(BANNER_IMAGE_PATH, bannerImagePath) + .apply(); + } + + public String getAlbumDetailSongSortOrder() { + return mPreferences + .getString(ALBUM_DETAIL_SONG_SORT_ORDER, SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST); + } + + public void setAlbumDetailSongSortOrder(String sortOrder) { + Editor edit = this.mPreferences.edit(); + edit.putString(ALBUM_DETAIL_SONG_SORT_ORDER, sortOrder); + edit.apply(); + } + + public String getArtistDetailSongSortOrder() { + return mPreferences + .getString(ARTIST_DETAIL_SONG_SORT_ORDER, SortOrder.ArtistSongSortOrder.SONG_A_Z); + } + + public void setArtistDetailSongSortOrder(String sortOrder) { + Editor edit = this.mPreferences.edit(); + edit.putString(ARTIST_DETAIL_SONG_SORT_ORDER, sortOrder); + edit.apply(); + } + + public boolean getVolumeToggle() { + return mPreferences.getBoolean(TOGGLE_VOLUME, false); + } + + public int getLyricsOptions() { + return mPreferences.getInt(LYRICS_OPTIONS, 1); + } + + public void setLyricsOptions(int i) { + mPreferences.edit().putInt(LYRICS_OPTIONS, i).apply(); + } + + public boolean getHeadsetPlugged() { + return mPreferences.getBoolean(TOGGLE_HEADSET, false); + } + + public boolean tabTitles() { + return mPreferences.getBoolean(TOGGLE_TAB_TITLES, true); + } + + public boolean isDominantColor() { + return mPreferences.getBoolean(DOMINANT_COLOR, false); + } + + public boolean isGenreShown() { + return mPreferences.getBoolean(TOGGLE_GENRE, false); + } + + public String getSelectedEqualizer() { + return mPreferences.getString(CHOOSE_EQUALIZER, "system"); + } + + public boolean isShuffleModeOn() { + return mPreferences.getBoolean(TOGGLE_SHUFFLE, false); + } + + public void resetCarouselEffect() { + mPreferences.edit().putBoolean(CAROUSEL_EFFECT, false).apply(); + } + + public void resetCircularAlbumArt() { + mPreferences.edit().putBoolean(CIRCULAR_ALBUM_ART, false).apply(); + } + + @LayoutRes + public int getAlbumGridStyle(Context context) { + int pos = Integer.parseInt(mPreferences.getString(ALBUM_GRID_STYLE, "0")); + TypedArray typedArray = context.getResources().obtainTypedArray(R.array.pref_grid_style_layout); + int layoutRes = typedArray.getResourceId(pos, -1); + typedArray.recycle(); + if (layoutRes == -1) { + return R.layout.item_card; + } + return layoutRes; + } + + public void setAlbumGridStyle(int type) { + mPreferences.edit().putInt(ALBUM_GRID_STYLE, type).apply(); + } + + public int getArtistGridStyle(Context context) { + int pos = Integer.parseInt(mPreferences.getString(ARTIST_GRID_STYLE, "0")); + TypedArray typedArray = context.getResources().obtainTypedArray(R.array.pref_grid_style_layout); + int layoutRes = typedArray.getResourceId(pos, -1); + typedArray.recycle(); + if (layoutRes == -1) { + return R.layout.item_card; + } + return layoutRes; + } + + public void setArtistGridStyle(int viewAs) { + mPreferences.edit().putInt(ARTIST_GRID_STYLE, viewAs).apply(); + } + + public boolean toggleSeparateLine() { + return mPreferences.getBoolean(TOGGLE_SEPARATE_LINE, false); + } + + public int getSongGridStyle() { + return mPreferences.getInt(SONG_GRID_STYLE, R.layout.item_list); + } + + public void setSongGridStyle(int viewAs) { + mPreferences.edit().putInt(SONG_GRID_STYLE, viewAs).apply(); + } + + public boolean enableAnimations() { + return mPreferences.getBoolean(TOGGLE_ANIMATIONS, false); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/RetroColorUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/RetroColorUtil.java new file mode 100644 index 00000000..64da365c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/RetroColorUtil.java @@ -0,0 +1,189 @@ +package code.name.monkey.retromusic.util; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.graphics.Palette; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import code.name.monkey.appthemehelper.util.ColorUtil; + +public class RetroColorUtil { + + @Nullable + public static Palette generatePalette(Bitmap bitmap) { + return bitmap == null ? null : Palette.from(bitmap).clearFilters().generate(); + } + + public static int getTextColor(@Nullable Palette palette) { + if (palette == null) { + return -1; + } + + int inverse = -1; + if (palette.getVibrantSwatch() != null) { + inverse = palette.getVibrantSwatch().getRgb(); + } else if (palette.getLightVibrantSwatch() != null) { + inverse = palette.getLightVibrantSwatch().getRgb(); + } else if (palette.getDarkVibrantSwatch() != null) { + inverse = palette.getDarkVibrantSwatch().getRgb(); + } + + int background = getSwatch(palette).getRgb(); + + if (inverse != -1) { + return ColorUtils.getReadableText(inverse, background, 150); + } + return ColorUtil.stripAlpha(getSwatch(palette).getTitleTextColor()); + } + + @NonNull + public static Palette.Swatch getSwatch(@Nullable Palette palette) { + if (palette == null) { + return new Palette.Swatch(Color.WHITE, 1); + } + return getBestPaletteSwatchFrom(palette.getSwatches()); + + } + + public static int getMatColor(Context context, String typeColor) { + int returnColor = Color.BLACK; + int arrayId = context.getResources().getIdentifier("md_" + typeColor, "array", + context.getApplicationContext().getPackageName()); + + if (arrayId != 0) { + TypedArray colors = context.getResources().obtainTypedArray(arrayId); + int index = (int) (Math.random() * colors.length()); + returnColor = colors.getColor(index, Color.BLACK); + colors.recycle(); + } + return returnColor; + } + + @ColorInt + public static int getColor(@Nullable Palette palette, int fallback) { + if (palette != null) { + if (palette.getVibrantSwatch() != null) { + return palette.getVibrantSwatch().getRgb(); + } else if (palette.getDarkVibrantSwatch() != null) { + return palette.getDarkVibrantSwatch().getRgb(); + } else if (palette.getLightVibrantSwatch() != null) { + return palette.getLightVibrantSwatch().getRgb(); + } else if (palette.getMutedSwatch() != null) { + return palette.getMutedSwatch().getRgb(); + } else if (palette.getLightMutedSwatch() != null) { + return palette.getLightMutedSwatch().getRgb(); + } else if (palette.getDarkMutedSwatch() != null) { + return palette.getDarkMutedSwatch().getRgb(); + } else if (!palette.getSwatches().isEmpty()) { + return Collections.max(palette.getSwatches(), SwatchComparator.getInstance()).getRgb(); + } + } + return fallback; + } + + private static Palette.Swatch getTextSwatch(@Nullable Palette palette) { + if (palette == null) { + return new Palette.Swatch(Color.BLACK, 1); + } + if (palette.getVibrantSwatch() != null) { + return palette.getVibrantSwatch(); + } else { + return new Palette.Swatch(Color.BLACK, 1); + } + } + + @ColorInt + public static int getBackgroundColor(@Nullable Palette palette) { + return getProperBackgroundSwatch(palette).getRgb(); + } + + private static Palette.Swatch getProperBackgroundSwatch(@Nullable Palette palette) { + if (palette == null) { + return new Palette.Swatch(Color.BLACK, 1); + } + if (palette.getDarkMutedSwatch() != null) { + return palette.getDarkMutedSwatch(); + } else if (palette.getMutedSwatch() != null) { + return palette.getMutedSwatch(); + } else if (palette.getLightMutedSwatch() != null) { + return palette.getLightMutedSwatch(); + } else { + return new Palette.Swatch(Color.BLACK, 1); + } + } + + private static Palette.Swatch getBestPaletteSwatchFrom(Palette palette) { + if (palette != null) { + if (palette.getVibrantSwatch() != null) { + return palette.getVibrantSwatch(); + } else if (palette.getMutedSwatch() != null) { + return palette.getMutedSwatch(); + } else if (palette.getDarkVibrantSwatch() != null) { + return palette.getDarkVibrantSwatch(); + } else if (palette.getDarkMutedSwatch() != null) { + return palette.getDarkMutedSwatch(); + } else if (palette.getLightVibrantSwatch() != null) { + return palette.getLightVibrantSwatch(); + } else if (palette.getLightMutedSwatch() != null) { + return palette.getLightMutedSwatch(); + } else if (!palette.getSwatches().isEmpty()) { + return getBestPaletteSwatchFrom(palette.getSwatches()); + } + } + return null; + } + + private static Palette.Swatch getBestPaletteSwatchFrom(List swatches) { + if (swatches == null) { + return null; + } + return Collections.max(swatches, (opt1, opt2) -> { + int a = opt1 == null ? 0 : opt1.getPopulation(); + int b = opt2 == null ? 0 : opt2.getPopulation(); + return a - b; + }); + } + + + public static int getDominantColor(Bitmap bitmap, int defaultFooterColor) { + List swatchesTemp = Palette.from(bitmap).generate().getSwatches(); + List swatches = new ArrayList(swatchesTemp); + Collections.sort(swatches, (swatch1, swatch2) -> swatch2.getPopulation() - swatch1.getPopulation()); + return swatches.size() > 0 ? swatches.get(0).getRgb() : defaultFooterColor; + } + + @ColorInt + public static int shiftBackgroundColorForLightText(@ColorInt int backgroundColor) { + while (ColorUtil.isColorLight(backgroundColor)) { + backgroundColor = ColorUtil.darkenColor(backgroundColor); + } + return backgroundColor; + } + + + private static class SwatchComparator implements Comparator { + + private static SwatchComparator sInstance; + + static SwatchComparator getInstance() { + if (sInstance == null) { + sInstance = new SwatchComparator(); + } + return sInstance; + } + + @Override + public int compare(Palette.Swatch lhs, Palette.Swatch rhs) { + return lhs.getPopulation() - rhs.getPopulation(); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java new file mode 100755 index 00000000..e66e5627 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java @@ -0,0 +1,314 @@ +package code.name.monkey.retromusic.util; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.ContentUris; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Point; +import android.graphics.drawable.Drawable; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.os.Build; +import android.os.ResultReceiver; +import android.provider.BaseColumns; +import android.provider.MediaStore; +import android.support.annotation.ColorInt; +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.graphics.drawable.VectorDrawableCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.FrameLayout; +import android.widget.RelativeLayout; + +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Collections; +import java.util.List; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.TintHelper; +import code.name.monkey.retromusic.RetroApplication; + +public class RetroUtil { + + private static final int[] TEMP_ARRAY = new int[1]; + + public static int calculateNoOfColumns(Context context) { + DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); + float dpWidth = displayMetrics.widthPixels / displayMetrics.density; + return (int) (dpWidth / 180); + } + + public static Uri getAlbumArtUri(long paramInt) { + return ContentUris + .withAppendedId(Uri.parse("content://media/external/audio/albumart"), paramInt); + } + + public static String EncodeString(String string) { + return string.replace("%", "%25") + .replace(".", "%2E") + .replace("#", "%23") + .replace("$", "%24") + .replace("/", "%2F") + .replace("[", "%5B") + .replace("]", "%5D"); + } + + public static String DecodeString(String string) { + return string.replace("%25", "%") + .replace("%2E", ".") + .replace("%23", "#") + .replace("%24", "$") + .replace("%2F", "/") + .replace("%5B", "[") + .replace("%5D", "]"); + } + + public static boolean isTablet(@NonNull final Resources resources) { + return resources.getConfiguration().smallestScreenWidthDp >= 600; + } + + public static boolean isLandscape(@NonNull final Resources resources) { + return resources.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + } + + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + public static boolean isRTL(@NonNull Context context) { + Configuration config = context.getResources().getConfiguration(); + return config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + } + + + @TargetApi(19) + public static void setStatusBarTranslucent(@NonNull Window window) { + window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, + WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + } + + public static void setAllowDrawUnderStatusBar(@NonNull Window window) { + window.getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + } + + public static boolean isMarshMellow() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; + } + + public static boolean isNougat() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; + } + + public static boolean isOreo() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; + } + + public static float getDistance(float x1, float y1, float x2, float y2) { + return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + } + + public static float convertDpToPixel(float dp, Context context) { + Resources resources = context.getResources(); + DisplayMetrics metrics = resources.getDisplayMetrics(); + return dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT); + } + + public static float convertPixelsToDp(float px, Context context) { + Resources resources = context.getResources(); + DisplayMetrics metrics = resources.getDisplayMetrics(); + return px / ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT); + } + + + public static void openUrl(AppCompatActivity context, String str) { + Intent intent = new Intent("android.intent.action.VIEW"); + intent.setData(Uri.parse(str)); + intent.setFlags(268435456); + context.startActivity(intent); + } + + public static Point getScreenSize(@NonNull Context c) { + Display display = null; + if (c.getSystemService(Context.WINDOW_SERVICE) != null) { + display = ((WindowManager) c.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + } + Point size = new Point(); + if (display != null) { + display.getSize(size); + } + return size; + } + + + public static void hideSoftKeyboard(@Nullable Activity activity) { + if (activity != null) { + View currentFocus = activity.getCurrentFocus(); + if (currentFocus != null) { + InputMethodManager inputMethodManager = (InputMethodManager) activity + .getSystemService(Activity.INPUT_METHOD_SERVICE); + if (inputMethodManager != null) { + inputMethodManager.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0); + } + } + } + } + + public static void showIme(@NonNull View view) { + InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService + (Context.INPUT_METHOD_SERVICE); + // the public methods don't seem to work for me, so… reflection. + try { + Method showSoftInputUnchecked = InputMethodManager.class.getMethod( + "showSoftInputUnchecked", int.class, ResultReceiver.class); + showSoftInputUnchecked.setAccessible(true); + showSoftInputUnchecked.invoke(imm, 0, null); + } catch (Exception e) { + // ho hum + } + } + + + public static Drawable getVectorDrawable(@NonNull Resources res, @DrawableRes int resId, + @Nullable Resources.Theme theme) { + if (Build.VERSION.SDK_INT >= 21) { + return res.getDrawable(resId, theme); + } + return VectorDrawableCompat.create(res, resId, theme); + } + + public static Drawable getTintedVectorDrawable(@NonNull Context context, @DrawableRes int id, + @ColorInt int color) { + return TintHelper + .createTintedDrawable(getVectorDrawable(context.getResources(), id, context.getTheme()), + color); + } + + public static Drawable getTintedDrawable(@NonNull Context context, @DrawableRes int id, + @ColorInt int color) { + return TintHelper.createTintedDrawable(ContextCompat.getDrawable(context, id), color); + } + + public static Drawable getTintedDrawable(@DrawableRes int id) { + return TintHelper + .createTintedDrawable(ContextCompat.getDrawable(RetroApplication.getInstance(), id), + ThemeStore.accentColor(RetroApplication.getInstance())); + } + + public static Bitmap createBitmap(Drawable drawable, float sizeMultiplier) { + Bitmap bitmap = Bitmap.createBitmap((int) (drawable.getIntrinsicWidth() * sizeMultiplier), + (int) (drawable.getIntrinsicHeight() * sizeMultiplier), Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(bitmap); + drawable.setBounds(0, 0, c.getWidth(), c.getHeight()); + drawable.draw(c); + return bitmap; + } + + public static Drawable getTintedVectorDrawable(@NonNull Resources res, @DrawableRes int resId, + @Nullable Resources.Theme theme, @ColorInt int color) { + return TintHelper.createTintedDrawable(getVectorDrawable(res, resId, theme), color); + } + + public static boolean isAllowedToDownloadMetadata(final Context context) { + switch (PreferenceUtil.getInstance(context).autoDownloadImagesPolicy()) { + case "always": + return true; + case "only_wifi": + final ConnectivityManager connectivityManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo(); + return netInfo != null && netInfo.getType() == ConnectivityManager.TYPE_WIFI && netInfo + .isConnectedOrConnecting(); + case "never": + default: + return false; + } + } + + public static String getIPAddress(boolean useIPv4) { + try { + List interfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); + for (NetworkInterface intf : interfaces) { + List addrs = Collections.list(intf.getInetAddresses()); + for (InetAddress addr : addrs) { + if (!addr.isLoopbackAddress()) { + String sAddr = addr.getHostAddress(); + //boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr); + boolean isIPv4 = sAddr.indexOf(':') < 0; + + if (useIPv4) { + if (isIPv4) + return sAddr; + } else { + if (!isIPv4) { + int delim = sAddr.indexOf('%'); // drop ip6 zone suffix + return delim < 0 ? sAddr.toUpperCase() : sAddr.substring(0, delim).toUpperCase(); + } + } + } + } + } + } catch (Exception ex) { + } + return ""; + } + + public static Uri getSongUri(Context context, long id) { + final String[] projection = new String[]{ + BaseColumns._ID, MediaStore.MediaColumns.DATA, MediaStore.Audio.AudioColumns.ALBUM_ID + }; + final StringBuilder selection = new StringBuilder(); + selection.append(BaseColumns._ID + " IN ("); + selection.append(id); + selection.append(")"); + final Cursor c = context.getContentResolver().query( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection.toString(), + null, null); + + if (c == null) { + return null; + } + c.moveToFirst(); + + + try { + + Uri uri = Uri.parse(c.getString(1)); + c.close(); + + return uri; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static void statusBarHeight(View statusBar) { + statusBar.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(statusBar.getContext()))); + } + + public static int getStatusBarHeight(Context context) { + int result = 0; + int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resourceId > 0) { + result = context.getResources().getDimensionPixelSize(resourceId); + } + return result; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/SwipeAndDragHelper.java b/app/src/main/java/code/name/monkey/retromusic/util/SwipeAndDragHelper.java new file mode 100644 index 00000000..52870404 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/SwipeAndDragHelper.java @@ -0,0 +1,55 @@ +package code.name.monkey.retromusic.util; + +import android.graphics.Canvas; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; + +public class SwipeAndDragHelper extends ItemTouchHelper.Callback { + + private ActionCompletionContract contract; + + public SwipeAndDragHelper(ActionCompletionContract contract) { + this.contract = contract; + } + + @Override + public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; + return makeMovementFlags(dragFlags, 0); + } + + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { + contract.onViewMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition()); + return true; + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { + } + + @Override + public boolean isLongPressDragEnabled() { + return false; + } + + @Override + public void onChildDraw(Canvas c, + RecyclerView recyclerView, + RecyclerView.ViewHolder viewHolder, + float dX, + float dY, + int actionState, + boolean isCurrentlyActive) { + if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { + float alpha = 1 - (Math.abs(dX) / recyclerView.getWidth()); + viewHolder.itemView.setAlpha(alpha); + } + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + } + + public interface ActionCompletionContract { + void onViewMoved(int oldPosition, int newPosition); + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/TempUtils.java b/app/src/main/java/code/name/monkey/retromusic/util/TempUtils.java new file mode 100644 index 00000000..9d2b86aa --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/TempUtils.java @@ -0,0 +1,68 @@ +package code.name.monkey.retromusic.util; + +/** + * @author Hemanth S (h4h13). + */ +public class TempUtils { + + // Enums + public static final int TEMPO_STROLL = 0; + public static final int TEMPO_WALK = 1; + public static final int TEMPO_LIGHT_JOG = 2; + public static final int TEMPO_JOG = 3; + public static final int TEMPO_RUN = 4; + public static final int TEMPO_SPRINT = 5; + public static final int TEMPO_UNKNOWN = 6; + + // take BPM as an int + public static int getTempoFromBPM(int bpm) { + + // STROLL less than 60 + if (bpm < 60) { + return TEMPO_STROLL; + } + + // WALK between 60 and 70, or between 120 and 140 + else if (bpm < 70 || bpm >= 120 && bpm < 140) { + return TEMPO_WALK; + } + + // LIGHT_JOG between 70 and 80, or between 140 and 160 + else if (bpm < 80 || bpm >= 140 && bpm < 160) { + return TEMPO_LIGHT_JOG; + } + + // JOG between 80 and 90, or between 160 and 180 + else if (bpm < 90 || bpm >= 160 && bpm < 180) { + return TEMPO_JOG; + } + + // RUN between 90 and 100, or between 180 and 200 + else if (bpm < 100 || bpm >= 180 && bpm < 200) { + return TEMPO_RUN; + } + + // SPRINT between 100 and 120 + else if (bpm < 120) { + return TEMPO_SPRINT; + } + + // UNKNOWN + else { + return TEMPO_UNKNOWN; + } + } + + // take BPM as a string + public static int getTempoFromBPM(String bpm) { + // cast to an int from string + try { + // convert the string to an int + return getTempoFromBPM(Integer.parseInt(bpm.trim())); + } catch (NumberFormatException nfe) { + + // + return TEMPO_UNKNOWN; + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/ViewUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/ViewUtil.java new file mode 100644 index 00000000..c20887cb --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/ViewUtil.java @@ -0,0 +1,58 @@ +package code.name.monkey.retromusic.util; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; +import android.support.v4.view.ViewCompat; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.ViewGroup; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; +import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; + +public class ViewUtil { + + public final static int RETRO_MUSIC_ANIM_TIME = 1000; + + public static void setStatusBarHeight(final Context context, View statusBar) { + ViewGroup.LayoutParams lp = statusBar.getLayoutParams(); + lp.height = getStatusBarHeight(context); + statusBar.requestLayout(); + } + + public static int getStatusBarHeight(final Context context) { + int result = 0; + int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resourceId > 0) { + result = context.getResources().getDimensionPixelSize(resourceId); + } + return result; + } + + public static boolean hitTest(View v, int x, int y) { + final int tx = (int) (ViewCompat.getTranslationX(v) + 0.5f); + final int ty = (int) (ViewCompat.getTranslationY(v) + 0.5f); + final int left = v.getLeft() + tx; + final int right = v.getRight() + tx; + final int top = v.getTop() + ty; + final int bottom = v.getBottom() + ty; + + return (x >= left) && (x <= right) && (y >= top) && (y <= bottom); + } + + public static void setUpFastScrollRecyclerViewColor(Context context, + FastScrollRecyclerView recyclerView, int accentColor) { + recyclerView.setPopupBgColor(accentColor); + recyclerView.setPopupTextColor( + MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(accentColor))); + recyclerView.setThumbColor(accentColor); + recyclerView.setTrackColor(Color.TRANSPARENT); + //recyclerView.setTrackColor(ColorUtil.withAlpha(ATHUtil.resolveColor(context, R.attr.colorControlNormal), 0.12f)); + } + + public static float convertDpToPixel(float dp, Resources resources) { + DisplayMetrics metrics = resources.getDisplayMetrics(); + return dp * metrics.density; + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/color/ImageGradientColorizer.java b/app/src/main/java/code/name/monkey/retromusic/util/color/ImageGradientColorizer.java new file mode 100644 index 00000000..87b88332 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/color/ImageGradientColorizer.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 code.name.monkey.retromusic.util.color; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; + +/** + * A utility class to colorize bitmaps with a color gradient and a special blending mode + */ +public class ImageGradientColorizer { + + public Bitmap colorize(Drawable drawable, int backgroundColor, boolean isRtl) { + int width = drawable.getIntrinsicWidth(); + int height = drawable.getIntrinsicHeight(); + int size = Math.min(width, height); + int widthInset = (width - size) / 2; + int heightInset = (height - size) / 2; + drawable = drawable.mutate(); + drawable.setBounds(-widthInset, -heightInset, width - widthInset, height - heightInset); + Bitmap newBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(newBitmap); + // Values to calculate the luminance of a color + float lr = 0.2126f; + float lg = 0.7152f; + float lb = 0.0722f; + // Extract the red, green, blue components of the color extraction color in + // float and int form + int tri = Color.red(backgroundColor); + int tgi = Color.green(backgroundColor); + int tbi = Color.blue(backgroundColor); + float tr = tri / 255f; + float tg = tgi / 255f; + float tb = tbi / 255f; + // Calculate the luminance of the color extraction color + float cLum = (tr * lr + tg * lg + tb * lb) * 255; + ColorMatrix m = new ColorMatrix(new float[]{ + lr, lg, lb, 0, tri - cLum, + lr, lg, lb, 0, tgi - cLum, + lr, lg, lb, 0, tbi - cLum, + 0, 0, 0, 1, 0, + }); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + LinearGradient linearGradient = new LinearGradient(0, 0, size, 0, + new int[]{0, Color.argb(0.5f, 1, 1, 1), Color.BLACK}, + new float[]{0.0f, 0.4f, 1.0f}, Shader.TileMode.CLAMP); + paint.setShader(linearGradient); + Bitmap fadeIn = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); + Canvas fadeInCanvas = new Canvas(fadeIn); + drawable.clearColorFilter(); + drawable.draw(fadeInCanvas); + if (isRtl) { + // Let's flip the gradient + fadeInCanvas.translate(size, 0); + fadeInCanvas.scale(-1, 1); + } + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + fadeInCanvas.drawPaint(paint); + Paint coloredPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + coloredPaint.setColorFilter(new ColorMatrixColorFilter(m)); + coloredPaint.setAlpha((int) (0.5f * 255)); + canvas.drawBitmap(fadeIn, 0, 0, coloredPaint); + linearGradient = new LinearGradient(0, 0, size, 0, + new int[]{0, Color.argb(0.5f, 1, 1, 1), Color.BLACK}, + new float[]{0.0f, 0.6f, 1.0f}, Shader.TileMode.CLAMP); + paint.setShader(linearGradient); + fadeInCanvas.drawPaint(paint); + canvas.drawBitmap(fadeIn, 0, 0, null); + return newBitmap; + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/color/MediaNotificationProcessor.java b/app/src/main/java/code/name/monkey/retromusic/util/color/MediaNotificationProcessor.java new file mode 100644 index 00000000..af4d34dd --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/color/MediaNotificationProcessor.java @@ -0,0 +1,506 @@ +package code.name.monkey.retromusic.util.color; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.support.annotation.VisibleForTesting; +import android.support.v7.graphics.Palette; +import android.util.LayoutDirection; + +import code.name.monkey.appthemehelper.util.ColorUtil; + +import java.util.List; + +/** + * @author Hemanth S (h4h13). + */ +public class MediaNotificationProcessor { + + /** + * The fraction below which we select the vibrant instead of the light/dark vibrant color + */ + private static final float POPULATION_FRACTION_FOR_MORE_VIBRANT = 1.0f; + /** + * Minimum saturation that a muted color must have if there exists if deciding between two + * colors + */ + private static final float MIN_SATURATION_WHEN_DECIDING = 0.19f; + /** + * Minimum fraction that any color must have to be picked up as a text color + */ + private static final double MINIMUM_IMAGE_FRACTION = 0.002; + /** + * The population fraction to select the dominant color as the text color over a the colored + * ones. + */ + private static final float POPULATION_FRACTION_FOR_DOMINANT = 0.01f; + /** + * The population fraction to select a white or black color as the background over a color. + */ + private static final float POPULATION_FRACTION_FOR_WHITE_OR_BLACK = 2.5f; + private static final float BLACK_MAX_LIGHTNESS = 0.08f; + private static final float WHITE_MIN_LIGHTNESS = 0.90f; + private static final int RESIZE_BITMAP_AREA = 150 * 150; + private final ImageGradientColorizer mColorizer; + private final Context mContext; + private float[] mFilteredBackgroundHsl = null; + private Palette.Filter mBlackWhiteFilter = (rgb, hsl) -> !isWhiteOrBlack(hsl); + /** + * The context of the notification. This is the app context of the package posting the + * notification. + */ + private final Context mPackageContext; + private boolean mIsLowPriority; + private onColorThing onColorThing; + + public MediaNotificationProcessor(Context context, Context packageContext, onColorThing thing) { + this(context, packageContext, new ImageGradientColorizer()); + onColorThing = thing; + } + + @VisibleForTesting + MediaNotificationProcessor(Context context, Context packageContext, + ImageGradientColorizer colorizer) { + mContext = context; + mPackageContext = packageContext; + mColorizer = colorizer; + } + + /** + * Processes a builder of a media notification and calculates the appropriate colors that should + * be used. + * + * @param notification the notification that is being processed + * @param builder the recovered builder for the notification. this will be modified + */ + public int processNotification(Bitmap image) { + Bitmap bitmap; + Drawable drawable = new BitmapDrawable(mPackageContext.getResources(), image); + + int backgroundColor = 0; + + int width = drawable.getIntrinsicWidth(); + int height = drawable.getIntrinsicHeight(); + int area = width * height; + if (area > RESIZE_BITMAP_AREA) { + double factor = Math.sqrt((float) RESIZE_BITMAP_AREA / area); + width = (int) (factor * width); + height = (int) (factor * height); + } + bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, width, height); + drawable.draw(canvas); + // for the background we only take the left side of the image to ensure + // a smooth transition + Palette.Builder paletteBuilder = Palette.from(bitmap) + .setRegion(0, 0, bitmap.getWidth() / 2, bitmap.getHeight()) + .clearFilters() // we want all colors, red / white / black ones too! + .resizeBitmapArea(RESIZE_BITMAP_AREA); + Palette palette = paletteBuilder.generate(); + backgroundColor = findBackgroundColorAndFilter(palette); + // we want most of the full region again, slightly shifted to the right + + + float textColorStartWidthFraction = 0.4f; + paletteBuilder.setRegion((int) (bitmap.getWidth() * textColorStartWidthFraction), 0, + bitmap.getWidth(), + bitmap.getHeight()); + if (mFilteredBackgroundHsl != null) { + paletteBuilder.addFilter((rgb, hsl) -> { + // at least 10 degrees hue difference + float diff = Math.abs(hsl[0] - mFilteredBackgroundHsl[0]); + return diff > 10 && diff < 350; + }); + } + paletteBuilder.addFilter(mBlackWhiteFilter); + palette = paletteBuilder.generate(); + int foregroundColor = selectForegroundColor(backgroundColor, palette); + + onColorThing.bothColor(backgroundColor, foregroundColor); + return backgroundColor; + } + + private int selectForegroundColor(int backgroundColor, Palette palette) { + if (ColorUtil.isColorLight(backgroundColor)) { + return selectForegroundColorForSwatches(palette.getDarkVibrantSwatch(), + palette.getVibrantSwatch(), + palette.getDarkMutedSwatch(), + palette.getMutedSwatch(), + palette.getDominantSwatch(), + Color.BLACK); + } else { + return selectForegroundColorForSwatches(palette.getLightVibrantSwatch(), + palette.getVibrantSwatch(), + palette.getLightMutedSwatch(), + palette.getMutedSwatch(), + palette.getDominantSwatch(), + Color.WHITE); + } + } + + private int selectForegroundColorForSwatches(Palette.Swatch moreVibrant, + Palette.Swatch vibrant, Palette.Swatch moreMutedSwatch, Palette.Swatch mutedSwatch, + Palette.Swatch dominantSwatch, int fallbackColor) { + Palette.Swatch coloredCandidate = selectVibrantCandidate(moreVibrant, vibrant); + if (coloredCandidate == null) { + coloredCandidate = selectMutedCandidate(mutedSwatch, moreMutedSwatch); + } + if (coloredCandidate != null) { + if (dominantSwatch == coloredCandidate) { + return coloredCandidate.getRgb(); + } else if ((float) coloredCandidate.getPopulation() / dominantSwatch.getPopulation() + < POPULATION_FRACTION_FOR_DOMINANT + && dominantSwatch.getHsl()[1] > MIN_SATURATION_WHEN_DECIDING) { + return dominantSwatch.getRgb(); + } else { + return coloredCandidate.getRgb(); + } + } else if (hasEnoughPopulation(dominantSwatch)) { + return dominantSwatch.getRgb(); + } else { + return fallbackColor; + } + } + + private Palette.Swatch selectMutedCandidate(Palette.Swatch first, + Palette.Swatch second) { + boolean firstValid = hasEnoughPopulation(first); + boolean secondValid = hasEnoughPopulation(second); + if (firstValid && secondValid) { + float firstSaturation = first.getHsl()[1]; + float secondSaturation = second.getHsl()[1]; + float populationFraction = first.getPopulation() / (float) second.getPopulation(); + if (firstSaturation * populationFraction > secondSaturation) { + return first; + } else { + return second; + } + } else if (firstValid) { + return first; + } else if (secondValid) { + return second; + } + return null; + } + + private Palette.Swatch selectVibrantCandidate(Palette.Swatch first, Palette.Swatch second) { + boolean firstValid = hasEnoughPopulation(first); + boolean secondValid = hasEnoughPopulation(second); + if (firstValid && secondValid) { + int firstPopulation = first.getPopulation(); + int secondPopulation = second.getPopulation(); + if (firstPopulation / (float) secondPopulation + < POPULATION_FRACTION_FOR_MORE_VIBRANT) { + return second; + } else { + return first; + } + } else if (firstValid) { + return first; + } else if (secondValid) { + return second; + } + return null; + } + + private boolean hasEnoughPopulation(Palette.Swatch swatch) { + // We want a fraction that is at least 1% of the image + return swatch != null + && (swatch.getPopulation() / (float) RESIZE_BITMAP_AREA > MINIMUM_IMAGE_FRACTION); + } + + private int findBackgroundColorAndFilter(Palette palette) { + // by default we use the dominant palette + Palette.Swatch dominantSwatch = palette.getDominantSwatch(); + if (dominantSwatch == null) { + // We're not filtering on white or black + mFilteredBackgroundHsl = null; + return Color.WHITE; + } + if (!isWhiteOrBlack(dominantSwatch.getHsl())) { + mFilteredBackgroundHsl = dominantSwatch.getHsl(); + return dominantSwatch.getRgb(); + } + // Oh well, we selected black or white. Lets look at the second color! + List swatches = palette.getSwatches(); + float highestNonWhitePopulation = -1; + Palette.Swatch second = null; + for (Palette.Swatch swatch : swatches) { + if (swatch != dominantSwatch + && swatch.getPopulation() > highestNonWhitePopulation + && !isWhiteOrBlack(swatch.getHsl())) { + second = swatch; + highestNonWhitePopulation = swatch.getPopulation(); + } + } + if (second == null) { + // We're not filtering on white or black + mFilteredBackgroundHsl = null; + return dominantSwatch.getRgb(); + } + if (dominantSwatch.getPopulation() / highestNonWhitePopulation + > POPULATION_FRACTION_FOR_WHITE_OR_BLACK) { + // The dominant swatch is very dominant, lets take it! + // We're not filtering on white or black + mFilteredBackgroundHsl = null; + return dominantSwatch.getRgb(); + } else { + mFilteredBackgroundHsl = second.getHsl(); + return second.getRgb(); + } + } + + private boolean isWhiteOrBlack(float[] hsl) { + return isBlack(hsl) || isWhite(hsl); + } + + /** + * @return true if the color represents a color which is close to black. + */ + private boolean isBlack(float[] hslColor) { + return hslColor[2] <= BLACK_MAX_LIGHTNESS; + } + + /** + * @return true if the color represents a color which is close to white. + */ + private boolean isWhite(float[] hslColor) { + return hslColor[2] >= WHITE_MIN_LIGHTNESS; + } + + public void setIsLowPriority(boolean isLowPriority) { + mIsLowPriority = isLowPriority; + } + + public interface onColorThing { + void bothColor(int i, int i2); + } + + /** + * The fraction below which we select the vibrant instead of the light/dark vibrant color + *//* + private static final float POPULATION_FRACTION_FOR_MORE_VIBRANT = 1.0f; + *//** + * Minimum saturation that a muted color must have if there exists if deciding between two colors + *//* + private static final float MIN_SATURATION_WHEN_DECIDING = 0.19f; + *//** + * Minimum fraction that any color must have to be picked up as a text color + *//* + private static final double MINIMUM_IMAGE_FRACTION = 0.002; + *//** + * The population fraction to select the dominant color as the text color over a the colored + * ones. + *//* + private static final float POPULATION_FRACTION_FOR_DOMINANT = 0.01f; + *//** + * The population fraction to select a white or black color as the background over a color. + *//* + private static final float POPULATION_FRACTION_FOR_WHITE_OR_BLACK = 2.5f; + + private static final float BLACK_MAX_LIGHTNESS = 0.08f; + private static final float WHITE_MIN_LIGHTNESS = 0.90f; + private static final int RESIZE_BITMAP_AREA = 150 * 150; + private static float[] mFilteredBackgroundHsl = null; + private final ImageGradientColorizer mColorizer; + private final Context mContext; + *//** + * The context of the notification. This is the app context of the package posting the + * notification. + *//* + private final Context mPackageContext; + private static Palette.Filter mBlackWhiteFilter = (rgb, hsl) -> !isWhiteOrBlack(hsl); + private boolean mIsLowPriority; + + public MediaNotificationProcessor(Context context, Context packageContext) { + this(context, packageContext, new ImageGradientColorizer()); + } + + @VisibleForTesting + MediaNotificationProcessor(Context context, Context packageContext, + ImageGradientColorizer colorizer) { + mContext = context; + mPackageContext = packageContext; + mColorizer = colorizer; + } + + @Nullable + public static Palette.Builder generatePalette(Bitmap bitmap) { + return bitmap == null ? null : Palette.from(bitmap).clearFilters().resizeBitmapArea(RESIZE_BITMAP_AREA); + } + + public static int getBackgroundColor(Palette.Builder builder) { + return findBackgroundColorAndFilter(builder.generate()); + } + + public static int getTextColor(Palette.Builder builder) { + int backgroundColor = 0; + if (mFilteredBackgroundHsl != null) { + builder.addFilter((rgb, hsl) -> { + // at least 10 degrees hue difference + float diff = Math.abs(hsl[0] - mFilteredBackgroundHsl[0]); + return diff > 10 && diff < 350; + }); + } + builder.addFilter(mBlackWhiteFilter); + Palette palette = builder.generate(); + return selectForegroundColor(backgroundColor, palette); + } + + private static int selectForegroundColor(int backgroundColor, Palette palette) { + if (ColorUtil.isColorLight(backgroundColor)) { + return selectForegroundColorForSwatches(palette.getDarkVibrantSwatch(), + palette.getVibrantSwatch(), + palette.getDarkMutedSwatch(), + palette.getMutedSwatch(), + palette.getDominantSwatch(), + Color.BLACK); + } else { + return selectForegroundColorForSwatches(palette.getLightVibrantSwatch(), + palette.getVibrantSwatch(), + palette.getLightMutedSwatch(), + palette.getMutedSwatch(), + palette.getDominantSwatch(), + Color.WHITE); + } + } + + private static int selectForegroundColorForSwatches(Palette.Swatch moreVibrant, + Palette.Swatch vibrant, Palette.Swatch moreMutedSwatch, Palette.Swatch mutedSwatch, + Palette.Swatch dominantSwatch, int fallbackColor) { + Palette.Swatch coloredCandidate = selectVibrantCandidate(moreVibrant, vibrant); + if (coloredCandidate == null) { + coloredCandidate = selectMutedCandidate(mutedSwatch, moreMutedSwatch); + } + if (coloredCandidate != null) { + if (dominantSwatch == coloredCandidate) { + return coloredCandidate.getRgb(); + } else if ((float) coloredCandidate.getPopulation() / dominantSwatch.getPopulation() + < POPULATION_FRACTION_FOR_DOMINANT + && dominantSwatch.getHsl()[1] > MIN_SATURATION_WHEN_DECIDING) { + return dominantSwatch.getRgb(); + } else { + return coloredCandidate.getRgb(); + } + } else if (hasEnoughPopulation(dominantSwatch)) { + return dominantSwatch.getRgb(); + } else { + return fallbackColor; + } + } + + private static Palette.Swatch selectMutedCandidate(Palette.Swatch first, + Palette.Swatch second) { + boolean firstValid = hasEnoughPopulation(first); + boolean secondValid = hasEnoughPopulation(second); + if (firstValid && secondValid) { + float firstSaturation = first.getHsl()[1]; + float secondSaturation = second.getHsl()[1]; + float populationFraction = first.getPopulation() / (float) second.getPopulation(); + if (firstSaturation * populationFraction > secondSaturation) { + return first; + } else { + return second; + } + } else if (firstValid) { + return first; + } else if (secondValid) { + return second; + } + return null; + } + + private static Palette.Swatch selectVibrantCandidate(Palette.Swatch first, + Palette.Swatch second) { + boolean firstValid = hasEnoughPopulation(first); + boolean secondValid = hasEnoughPopulation(second); + if (firstValid && secondValid) { + int firstPopulation = first.getPopulation(); + int secondPopulation = second.getPopulation(); + if (firstPopulation / (float) secondPopulation + < POPULATION_FRACTION_FOR_MORE_VIBRANT) { + return second; + } else { + return first; + } + } else if (firstValid) { + return first; + } else if (secondValid) { + return second; + } + return null; + } + + private static boolean hasEnoughPopulation(Palette.Swatch swatch) { + // We want a fraction that is at least 1% of the image + return swatch != null + && (swatch.getPopulation() / (float) RESIZE_BITMAP_AREA > MINIMUM_IMAGE_FRACTION); + } + + public static int findBackgroundColorAndFilter(Palette palette) { + // by default we use the dominant palette + Palette.Swatch dominantSwatch = palette.getDominantSwatch(); + if (dominantSwatch == null) { + // We're not filtering on white or black + mFilteredBackgroundHsl = null; + return Color.WHITE; + } + if (!isWhiteOrBlack(dominantSwatch.getHsl())) { + mFilteredBackgroundHsl = dominantSwatch.getHsl(); + return dominantSwatch.getRgb(); + } + // Oh well, we selected black or white. Lets look at the second color! + List swatches = palette.getSwatches(); + float highestNonWhitePopulation = -1; + Palette.Swatch second = null; + for (Palette.Swatch swatch : swatches) { + if (swatch != dominantSwatch + && swatch.getPopulation() > highestNonWhitePopulation + && !isWhiteOrBlack(swatch.getHsl())) { + second = swatch; + highestNonWhitePopulation = swatch.getPopulation(); + } + } + if (second == null) { + // We're not filtering on white or black + mFilteredBackgroundHsl = null; + return dominantSwatch.getRgb(); + } + if (dominantSwatch.getPopulation() / highestNonWhitePopulation + > POPULATION_FRACTION_FOR_WHITE_OR_BLACK) { + // The dominant swatch is very dominant, lets take it! + // We're not filtering on white or black + mFilteredBackgroundHsl = null; + return dominantSwatch.getRgb(); + } else { + mFilteredBackgroundHsl = second.getHsl(); + return second.getRgb(); + } + } + + private static boolean isWhiteOrBlack(float[] hsl) { + return isBlack(hsl) || isWhite(hsl); + } + + *//** + * @return true if the color represents a color which is close to black. + *//* + private static boolean isBlack(float[] hslColor) { + return hslColor[2] <= BLACK_MAX_LIGHTNESS; + } + + *//** + * @return true if the color represents a color which is close to white. + *//* + private static boolean isWhite(float[] hslColor) { + return hslColor[2] >= WHITE_MIN_LIGHTNESS; + } + + public void setIsLowPriority(boolean isLowPriority) { + mIsLowPriority = isLowPriority; + }*/ +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/color/NotificationColorUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/color/NotificationColorUtil.java new file mode 100644 index 00000000..f85d97fd --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/color/NotificationColorUtil.java @@ -0,0 +1,134 @@ +package code.name.monkey.retromusic.util.color; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.VectorDrawable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.TextAppearanceSpan; +import android.util.Log; +import android.util.Pair; +import code.name.monkey.retromusic.util.ImageUtil; +import java.util.Arrays; +import java.util.WeakHashMap; + +/** + * Helper class to process legacy (Holo) notifications to make them look like quantum + * notifications. + * + * @hide + */ +public class NotificationColorUtil { + + private static final String TAG = "NotificationColorUtil"; + private static final Object sLock = new Object(); + private static NotificationColorUtil sInstance; + + private final WeakHashMap> mGrayscaleBitmapCache = + new WeakHashMap>(); + + public static NotificationColorUtil getInstance() { + synchronized (sLock) { + if (sInstance == null) { + sInstance = new NotificationColorUtil(); + } + return sInstance; + } + } + + /** + * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect gray". + * + * @param bitmap The bitmap to test. + * @return Whether the bitmap is grayscale. + */ + public boolean isGrayscale(Bitmap bitmap) { + synchronized (sLock) { + Pair cached = mGrayscaleBitmapCache.get(bitmap); + if (cached != null) { + if (cached.second == bitmap.getGenerationId()) { + return cached.first; + } + } + } + boolean result; + int generationId; + + result = ImageUtil.isGrayscale(bitmap); + // generationId and the check whether the Bitmap is grayscale can't be read atomically + // here. However, since the thread is in the process of posting the notification, we can + // assume that it doesn't modify the bitmap while we are checking the pixels. + generationId = bitmap.getGenerationId(); + + synchronized (sLock) { + mGrayscaleBitmapCache.put(bitmap, Pair.create(result, generationId)); + } + return result; + } + + /** + * Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect gray". + * + * @param d The drawable to test. + * @return Whether the drawable is grayscale. + */ + public boolean isGrayscale(Drawable d) { + if (d == null) { + return false; + } else if (d instanceof BitmapDrawable) { + BitmapDrawable bd = (BitmapDrawable) d; + return bd.getBitmap() != null && isGrayscale(bd.getBitmap()); + } else if (d instanceof AnimationDrawable) { + AnimationDrawable ad = (AnimationDrawable) d; + int count = ad.getNumberOfFrames(); + return count > 0 && isGrayscale(ad.getFrame(0)); + } else if (d instanceof VectorDrawable) { + // We just assume you're doing the right thing if using vectors + return true; + } else { + return false; + } + } + + /** + * Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close to a + * perfect gray". + * + * @param context The context to load the drawable from. + * @return Whether the drawable is grayscale. + */ + public boolean isGrayscale(Context context, int drawableResId) { + if (drawableResId != 0) { + try { + return isGrayscale(context.getDrawable(drawableResId)); + } catch (Resources.NotFoundException ex) { + Log.e(TAG, "Drawable not found: " + drawableResId); + return false; + } + } else { + return false; + } + } + + /** + * Inverts all the grayscale colors set by {@link android.text.style.TextAppearanceSpan}s on the + * text. + * + * @param charSequence The text to process. + * @return The color inverted text. + */ + + + private int processColor(int color) { + return Color.argb(Color.alpha(color), + 255 - Color.red(color), + 255 - Color.green(color), + 255 - Color.blue(color)); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/schedulers/BaseSchedulerProvider.java b/app/src/main/java/code/name/monkey/retromusic/util/schedulers/BaseSchedulerProvider.java new file mode 100644 index 00000000..6e610579 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/schedulers/BaseSchedulerProvider.java @@ -0,0 +1,20 @@ +package code.name.monkey.retromusic.util.schedulers; + +import android.support.annotation.NonNull; + +import io.reactivex.Scheduler; + +/** + * Created by hemanths on 12/08/17. + */ + +public interface BaseSchedulerProvider { + @NonNull + Scheduler computation(); + + @NonNull + Scheduler io(); + + @NonNull + Scheduler ui(); +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/schedulers/ImmediateScheduler.java b/app/src/main/java/code/name/monkey/retromusic/util/schedulers/ImmediateScheduler.java new file mode 100644 index 00000000..d5284bab --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/schedulers/ImmediateScheduler.java @@ -0,0 +1,30 @@ +package code.name.monkey.retromusic.util.schedulers; + +import android.support.annotation.NonNull; + +import io.reactivex.Scheduler; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by hemanths on 12/08/17. + */ + +public class ImmediateScheduler implements BaseSchedulerProvider { + @NonNull + @Override + public Scheduler computation() { + return Schedulers.trampoline(); + } + + @NonNull + @Override + public Scheduler io() { + return Schedulers.trampoline(); + } + + @NonNull + @Override + public Scheduler ui() { + return Schedulers.trampoline(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/schedulers/SchedulerProvider.java b/app/src/main/java/code/name/monkey/retromusic/util/schedulers/SchedulerProvider.java new file mode 100644 index 00000000..4ca45b14 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/schedulers/SchedulerProvider.java @@ -0,0 +1,44 @@ +package code.name.monkey.retromusic.util.schedulers; + +import android.support.annotation.NonNull; + +import io.reactivex.Scheduler; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by hemanths on 12/08/17. + */ + +public class SchedulerProvider implements BaseSchedulerProvider { + @NonNull + private static SchedulerProvider INSTANCE ; + + public SchedulerProvider() { + } + + public static synchronized SchedulerProvider getInstance() { + if (INSTANCE == null) { + INSTANCE = new SchedulerProvider(); + } + return INSTANCE; + } + + @Override + @NonNull + public Scheduler computation() { + return Schedulers.computation(); + } + + @Override + @NonNull + public Scheduler io() { + return Schedulers.io(); + } + + @Override + @NonNull + public Scheduler ui() { + return AndroidSchedulers.mainThread(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/AutofitRecyclerView.java b/app/src/main/java/code/name/monkey/retromusic/views/AutofitRecyclerView.java new file mode 100644 index 00000000..a513a46f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/AutofitRecyclerView.java @@ -0,0 +1,51 @@ +package code.name.monkey.retromusic.views; + +import android.content.Context; +import android.content.res.TypedArray; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; + +/** + * @author Hemanth S (h4h13). + */ +public class AutofitRecyclerView extends RecyclerView { + private GridLayoutManager manager; + private int columnWidth = -1; //default value + + public AutofitRecyclerView(Context context) { + super(context); + init(context, null); + } + + public AutofitRecyclerView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public AutofitRecyclerView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + if (attrs != null) { + int[] attrsArray = {android.R.attr.columnWidth}; + TypedArray array = context.obtainStyledAttributes(attrs, attrsArray); + columnWidth = array.getDimensionPixelSize(0, -1); + array.recycle(); + } + + manager = new GridLayoutManager(getContext(), 1, GridLayoutManager.HORIZONTAL,false); + setLayoutManager(manager); + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + super.onMeasure(widthSpec, heightSpec); + if (columnWidth > 0) { + int spanCount = Math.max(1, getMeasuredWidth() / columnWidth); + manager.setSpanCount(spanCount); + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/BottomNavigationViewEx.java b/app/src/main/java/code/name/monkey/retromusic/views/BottomNavigationViewEx.java new file mode 100644 index 00000000..ce2e4421 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/BottomNavigationViewEx.java @@ -0,0 +1,1050 @@ +package code.name.monkey.retromusic.views; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.internal.BottomNavigationItemView; +import android.support.design.internal.BottomNavigationMenuView; +import android.support.design.widget.BottomNavigationView; +import android.support.transition.Transition; +import android.support.transition.TransitionSet; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.util.SparseIntArray; +import android.util.TypedValue; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ATHUtil; + +/** + * Created by yu on 2016/11/10. + */ +@SuppressLint("RestrictedApi") +public class BottomNavigationViewEx extends BottomNavigationView { + // used for animation + private int mShiftAmount; + private float mScaleUpFactor; + private float mScaleDownFactor; + private boolean animationRecord; + private float mLargeLabelSize; + private float mSmallLabelSize; + private boolean visibilityTextSizeRecord; + private boolean visibilityHeightRecord; + private int mItemHeight; + private boolean textVisibility = true; + // used for animation end + + // used for setupWithViewPager + private ViewPager mViewPager; + private MyOnNavigationItemSelectedListener mMyOnNavigationItemSelectedListener; + private BottomNavigationViewExOnPageChangeListener mPageChangeListener; + private BottomNavigationMenuView mMenuView; + private BottomNavigationItemView[] mButtons; + // used for setupWithViewPager end + + public BottomNavigationViewEx(Context context) { + super(context); + tintColor( ); + } + + public BottomNavigationViewEx(Context context, AttributeSet attrs) { + super(context, attrs); + tintColor( ); + } + + public BottomNavigationViewEx(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + tintColor( ); + } + + /** + * get text height by font size + * + * @param fontSize + * @return + */ + private static int getFontHeight(float fontSize) { + Paint paint = new Paint(); + paint.setTextSize(fontSize); + Paint.FontMetrics fm = paint.getFontMetrics(); + return (int) Math.ceil(fm.descent - fm.top) + 2; + } + + /** + * dp to px + * + * @param context + * @param dpValue dp + * @return px + */ + public static int dp2px(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + private static void setItemIconColors(@NonNull BottomNavigationView view, @ColorInt int normalColor, @ColorInt int selectedColor) { + ColorStateList iconSl = new ColorStateList(new int[][]{{-16842912}, {16842912}}, new int[]{normalColor, selectedColor}); + view.setItemIconTintList(iconSl); + } + + private static void setItemTextColors(@NonNull BottomNavigationView view, @ColorInt int normalColor, @ColorInt int selectedColor) { + ColorStateList textSl = new ColorStateList(new int[][]{{-16842912}, {16842912}}, new int[]{normalColor, selectedColor}); + view.setItemTextColor(textSl); + } + + public void setIconAndTextColor(int i) { + tintColor(ATHUtil.resolveColor(getContext(), android.R.attr.textColorSecondary), i); + } + + private void tintColor() { + int color = ATHUtil.resolveColor(getContext(), android.R.attr.textColorSecondary); + int accentColor = ThemeStore.accentColor(getContext()); + tintColor(color, accentColor); + } + + private void tintColor(int color, int accentColor) { + setItemIconColors(this, color, accentColor); + setItemTextColors(this, color, accentColor); + } + + private void init() { + try { + addAnimationListener(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void addAnimationListener() { + /** + * 1. BottomNavigationMenuView mMenuView + * 2. private final BottomNavigationAnimationHelperBase mAnimationHelper; + * 3. private final TransitionSet mSet; + */ + BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + Object mAnimationHelper = getField(mMenuView.getClass(), mMenuView, "mAnimationHelper"); + TransitionSet mSet = getField(mAnimationHelper.getClass(), mAnimationHelper, "mSet"); + mSet.addListener(new Transition.TransitionListener() { + @Override + public void onTransitionStart(@NonNull Transition transition) { + } + + @Override + public void onTransitionEnd(@NonNull Transition transition) { + refreshTextViewVisibility(); + } + + @Override + public void onTransitionCancel(@NonNull Transition transition) { + refreshTextViewVisibility(); + } + + @Override + public void onTransitionPause(@NonNull Transition transition) { + } + + @Override + public void onTransitionResume(@NonNull Transition transition) { + } + }); + } + + private void refreshTextViewVisibility() { + if (!textVisibility) + return; + // 1. get mMenuView + BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + // 2. get mButtons + BottomNavigationItemView[] mButtons = getBottomNavigationItemViews(); + + int currentItem = getCurrentItem(); + + // 3. get field mShiftingMode and TextView in mButtons + for (BottomNavigationItemView button : mButtons) { + TextView mLargeLabel = getField(button.getClass(), button, "mLargeLabel"); + TextView mSmallLabel = getField(button.getClass(), button, "mSmallLabel"); + + if (mLargeLabel != null) { + mLargeLabel.clearAnimation(); + } + if (mSmallLabel != null) { + mSmallLabel.clearAnimation(); + } + + // mShiftingMode + boolean mShiftingMode = getField(button.getClass(), button, "mShiftingMode"); + boolean selected = button.getItemPosition() == currentItem; + if (mShiftingMode) { + if (selected) { + mLargeLabel.setVisibility(VISIBLE); + } else { + mLargeLabel.setVisibility(INVISIBLE); + } + mSmallLabel.setVisibility(INVISIBLE); + } else { + if (selected) { + mLargeLabel.setVisibility(VISIBLE); + mSmallLabel.setVisibility(INVISIBLE); + } else { + mLargeLabel.setVisibility(INVISIBLE); + mSmallLabel.setVisibility(VISIBLE); + } + } + } + } + + /** + * change the visibility of icon + * + * @param visibility + */ + public void setIconVisibility(boolean visibility) { + /* + 1. get field in this class + private final BottomNavigationMenuView mMenuView; + + 2. get field in mButtons + private BottomNavigationItemView[] mButtons; + + 3. get mIcon in mButtons + private ImageView mIcon + + 4. set mIcon visibility gone + + 5. change mItemHeight to only text size in mMenuView + */ + // 1. get mMenuView + final BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + // 2. get mButtons + BottomNavigationItemView[] mButtons = getBottomNavigationItemViews(); + // 3. get mIcon in mButtons + for (BottomNavigationItemView button : mButtons) { + ImageView mIcon = getField(button.getClass(), button, "mIcon"); + // 4. set mIcon visibility gone + mIcon.setVisibility(visibility ? View.VISIBLE : View.INVISIBLE); + } + + // 5. change mItemHeight to only text size in mMenuView + if (!visibility) { + // if not record mItemHeight + if (!visibilityHeightRecord) { + visibilityHeightRecord = true; + mItemHeight = getItemHeight(); + } + + // change mItemHeight + BottomNavigationItemView button = mButtons[0]; + if (null != button) { + final ImageView mIcon = getField(button.getClass(), button, "mIcon"); +// System.out.println("mIcon.getMeasuredHeight():" + mIcon.getMeasuredHeight()); + if (null != mIcon) { + mIcon.post(new Runnable() { + @Override + public void run() { +// System.out.println("mIcon.getMeasuredHeight():" + mIcon.getMeasuredHeight()); + setItemHeight(mItemHeight - mIcon.getMeasuredHeight()); + } + }); + } + } + } else { + // if not record the mItemHeight, we need do nothing. + if (!visibilityHeightRecord) + return; + + // restore it + setItemHeight(mItemHeight); + } + + mMenuView.updateMenuView(); + } + + /** + * change the visibility of text + * + * @param visibility + */ + public void setTextVisibility(boolean visibility) { + this.textVisibility = visibility; + /* + 1. get field in this class + private final BottomNavigationMenuView mMenuView; + + 2. get field in mButtons + private BottomNavigationItemView[] mButtons; + + 3. set text size in mButtons + private final TextView mLargeLabel + private final TextView mSmallLabel + + 4. change mItemHeight to only icon size in mMenuView + */ + // 1. get mMenuView + BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + // 2. get mButtons + BottomNavigationItemView[] mButtons = getBottomNavigationItemViews(); + + // 3. change field mShiftingMode value in mButtons + for (BottomNavigationItemView button : mButtons) { + TextView mLargeLabel = getField(button.getClass(), button, "mLargeLabel"); + TextView mSmallLabel = getField(button.getClass(), button, "mSmallLabel"); + + if (!visibility) { + // if not record the font size, record it + if (!visibilityTextSizeRecord && !animationRecord) { + visibilityTextSizeRecord = true; + mLargeLabelSize = mLargeLabel.getTextSize(); + mSmallLabelSize = mSmallLabel.getTextSize(); + } + + // if not visitable, set font size to 0 + mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, 0); + mSmallLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, 0); + + } else { + // if not record the font size, we need do nothing. + if (!visibilityTextSizeRecord) + break; + + // restore it + mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mLargeLabelSize); + mSmallLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSmallLabelSize); + } + } + + // 4 change mItemHeight to only icon size in mMenuView + if (!visibility) { + // if not record mItemHeight + if (!visibilityHeightRecord) { + visibilityHeightRecord = true; + mItemHeight = getItemHeight(); + } + + // change mItemHeight to only icon size in mMenuView + // private final int mItemHeight; + + // change mItemHeight +// System.out.println("mLargeLabel.getMeasuredHeight():" + getFontHeight(mSmallLabelSize)); + setItemHeight(mItemHeight - getFontHeight(mSmallLabelSize)); + + } else { + // if not record the mItemHeight, we need do nothing. + if (!visibilityHeightRecord) + return; + // restore mItemHeight + setItemHeight(mItemHeight); + } + + mMenuView.updateMenuView(); + } + + /** + * enable or disable click item animation(text scale and icon move animation in no item shifting mode) + * + * @param enable It means the text won't scale and icon won't move when active it in no item shifting mode if false. + */ + public void enableAnimation(boolean enable) { + /* + 1. get field in this class + private final BottomNavigationMenuView mMenuView; + + 2. get field in mButtons + private BottomNavigationItemView[] mButtons; + + 3. chang mShiftAmount to 0 in mButtons + private final int mShiftAmount + + change mScaleUpFactor and mScaleDownFactor to 1f in mButtons + private final float mScaleUpFactor + private final float mScaleDownFactor + + 4. change label font size in mButtons + private final TextView mLargeLabel + private final TextView mSmallLabel + */ + + // 1. get mMenuView + BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + // 2. get mButtons + BottomNavigationItemView[] mButtons = getBottomNavigationItemViews(); + // 3. change field mShiftingMode value in mButtons + for (BottomNavigationItemView button : mButtons) { + TextView mLargeLabel = getField(button.getClass(), button, "mLargeLabel"); + TextView mSmallLabel = getField(button.getClass(), button, "mSmallLabel"); + + // if disable animation, need animationRecord the source value + if (!enable) { + if (!animationRecord) { + animationRecord = true; + mShiftAmount = getField(button.getClass(), button, "mShiftAmount"); + mScaleUpFactor = getField(button.getClass(), button, "mScaleUpFactor"); + mScaleDownFactor = getField(button.getClass(), button, "mScaleDownFactor"); + + mLargeLabelSize = mLargeLabel.getTextSize(); + mSmallLabelSize = mSmallLabel.getTextSize(); + +// System.out.println("mShiftAmount:" + mShiftAmount + " mScaleUpFactor:" +// + mScaleUpFactor + " mScaleDownFactor:" + mScaleDownFactor +// + " mLargeLabel:" + mLargeLabelSize + " mSmallLabel:" + mSmallLabelSize); + } + // disable + setField(button.getClass(), button, "mShiftAmount", 0); + setField(button.getClass(), button, "mScaleUpFactor", 1); + setField(button.getClass(), button, "mScaleDownFactor", 1); + + // let the mLargeLabel font size equal to mSmallLabel + mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSmallLabelSize); + + // debug start +// mLargeLabelSize = mLargeLabel.getTextSize(); +// System.out.println("mLargeLabel:" + mLargeLabelSize); + // debug end + + } else { + // haven't change the value. It means it was the first call this method. So nothing need to do. + if (!animationRecord) + return; + // enable animation + setField(button.getClass(), button, "mShiftAmount", mShiftAmount); + setField(button.getClass(), button, "mScaleUpFactor", mScaleUpFactor); + setField(button.getClass(), button, "mScaleDownFactor", mScaleDownFactor); + // restore + mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mLargeLabelSize); + } + } + mMenuView.updateMenuView(); + } + + /** + * enable the shifting mode for navigation + * + * @param enable It will has a shift animation if true. Otherwise all items are the same width. + */ + public void enableShiftingMode(boolean enable) { + /* + 1. get field in this class + private final BottomNavigationMenuView mMenuView; + + 2. change field mShiftingMode value in mMenuView + private boolean mShiftingMode = true; + */ + // 1. get mMenuView + BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + // 2. change field mShiftingMode value in mMenuView + setField(mMenuView.getClass(), mMenuView, "mShiftingMode", enable); + + mMenuView.updateMenuView(); + } + + /** + * enable the shifting mode for each item + * + * @param enable It will has a shift animation for item if true. Otherwise the item text always be shown. + */ + public void enableItemShiftingMode(boolean enable) { + /* + 1. get field in this class + private final BottomNavigationMenuView mMenuView; + + 2. get field in this mMenuView + private BottomNavigationItemView[] mButtons; + + 3. change field mShiftingMode value in mButtons + private boolean mShiftingMode = true; + */ + // 1. get mMenuView + BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + // 2. get mButtons + BottomNavigationItemView[] mButtons = getBottomNavigationItemViews(); + // 3. change field mShiftingMode value in mButtons + for (BottomNavigationItemView button : mButtons) { + setField(button.getClass(), button, "mShiftingMode", enable); + } + mMenuView.updateMenuView(); + } + + /** + * get the current checked item position + * + * @return index of item, start from 0. + */ + public int getCurrentItem() { + /* + 1. get field in this class + private final BottomNavigationMenuView mMenuView; + + 2. get field in mMenuView + private BottomNavigationItemView[] mButtons; + + 3. get menu and traverse it to get the checked one + */ + + // 1. get mMenuView +// BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + // 2. get mButtons + BottomNavigationItemView[] mButtons = getBottomNavigationItemViews(); + // 3. get menu and traverse it to get the checked one + Menu menu = getMenu(); + for (int i = 0; i < mButtons.length; i++) { + if (menu.getItem(i).isChecked()) { + return i; + } + } + return 0; + } + + /** + * set the current checked item + * + * @param item start from 0. + */ + public void setCurrentItem(int item) { + // check bounds + if (item < 0 || item >= getMaxItemCount()) { + throw new ArrayIndexOutOfBoundsException("item is out of bounds, we expected 0 - " + + (getMaxItemCount() - 1) + ". Actually " + item); + } + + /* + 1. get field in this class + private final BottomNavigationMenuView mMenuView; + + 2. get field in mMenuView + private BottomNavigationItemView[] mButtons; + private final OnClickListener mOnClickListener; + + 3. call mOnClickListener.onClick(); + */ + // 1. get mMenuView + BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + // 2. get mButtons + BottomNavigationItemView[] mButtons = getBottomNavigationItemViews(); + // get mOnClickListener + View.OnClickListener mOnClickListener = getField(mMenuView.getClass(), mMenuView, "mOnClickListener"); + +// System.out.println("mMenuView:" + mMenuView + " mButtons:" + mButtons + " mOnClickListener" + mOnClickListener); + // 3. call mOnClickListener.onClick(); + mOnClickListener.onClick(mButtons[item]); + + } + + /** + * get menu item position in menu + * + * @param item + * @return position if success, -1 otherwise + */ + public int getMenuItemPosition(MenuItem item) { + // get item id + int itemId = item.getItemId(); + // get meunu + Menu menu = getMenu(); + int size = menu.size(); + for (int i = 0; i < size; i++) { + if (menu.getItem(i).getItemId() == itemId) { + return i; + } + } + return -1; + } + + /** + * get OnNavigationItemSelectedListener + * + * @return + */ + public OnNavigationItemSelectedListener getOnNavigationItemSelectedListener() { + // private OnNavigationItemSelectedListener mListener; + OnNavigationItemSelectedListener mListener = getField(BottomNavigationView.class, this, "mSelectedListener"); + return mListener; + } + + @Override + public void setOnNavigationItemSelectedListener(@Nullable OnNavigationItemSelectedListener listener) { + // if not set up with view pager, the same with father + if (null == mMyOnNavigationItemSelectedListener) { + super.setOnNavigationItemSelectedListener(listener); + return; + } + + mMyOnNavigationItemSelectedListener.setOnNavigationItemSelectedListener(listener); + } + + /** + * get private mMenuView + * + * @return + */ + private BottomNavigationMenuView getBottomNavigationMenuView() { + if (null == mMenuView) + mMenuView = getField(BottomNavigationView.class, this, "mMenuView"); + return mMenuView; + } + + /** + * get private mButtons in mMenuView + * + * @return + */ + public BottomNavigationItemView[] getBottomNavigationItemViews() { + if (null != mButtons) + return mButtons; + /* + * 1 private final BottomNavigationMenuView mMenuView; + * 2 private BottomNavigationItemView[] mButtons; + */ + BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + mButtons = getField(mMenuView.getClass(), mMenuView, "mButtons"); + return mButtons; + } + + /** + * get private mButton in mMenuView at position + * + * @param position + * @return + */ + public BottomNavigationItemView getBottomNavigationItemView(int position) { + return getBottomNavigationItemViews()[position]; + } + + /** + * get icon at position + * + * @param position + * @return + */ + public ImageView getIconAt(int position) { + /* + * 1 private final BottomNavigationMenuView mMenuView; + * 2 private BottomNavigationItemView[] mButtons; + * 3 private ImageView mIcon; + */ + BottomNavigationItemView mButtons = getBottomNavigationItemView(position); + ImageView mIcon = getField(BottomNavigationItemView.class, mButtons, "mIcon"); + return mIcon; + } + + /** + * get small label at position + * Each item has tow label, one is large, another is small. + * + * @param position + * @return + */ + public TextView getSmallLabelAt(int position) { + /* + * 1 private final BottomNavigationMenuView mMenuView; + * 2 private BottomNavigationItemView[] mButtons; + * 3 private final TextView mSmallLabel; + */ + BottomNavigationItemView mButtons = getBottomNavigationItemView(position); + TextView mSmallLabel = getField(BottomNavigationItemView.class, mButtons, "mSmallLabel"); + return mSmallLabel; + } + + /** + * get large label at position + * Each item has tow label, one is large, another is small. + * + * @param position + * @return + */ + public TextView getLargeLabelAt(int position) { + /* + * 1 private final BottomNavigationMenuView mMenuView; + * 2 private BottomNavigationItemView[] mButtons; + * 3 private final TextView mLargeLabel; + */ + BottomNavigationItemView mButtons = getBottomNavigationItemView(position); + TextView mLargeLabel = getField(BottomNavigationItemView.class, mButtons, "mLargeLabel"); + return mLargeLabel; + } + + /** + * return item count + * + * @return + */ + public int getItemCount() { + BottomNavigationItemView[] bottomNavigationItemViews = getBottomNavigationItemViews(); + if (null == bottomNavigationItemViews) + return 0; + return bottomNavigationItemViews.length; + } + + /** + * set all item small TextView size + * Each item has tow label, one is large, another is small. + * Small one will be shown when item state is normal + * Large one will be shown when item checked. + * + * @param sp + */ + public void setSmallTextSize(float sp) { + int count = getItemCount(); + for (int i = 0; i < count; i++) { + getSmallLabelAt(i).setTextSize(sp); + } + mMenuView.updateMenuView(); + } + + /** + * set all item large TextView size + * Each item has tow label, one is large, another is small. + * Small one will be shown when item state is normal. + * Large one will be shown when item checked. + * + * @param sp + */ + public void setLargeTextSize(float sp) { + int count = getItemCount(); + for (int i = 0; i < count; i++) { + getLargeLabelAt(i).setTextSize(sp); + } + mMenuView.updateMenuView(); + } + + /** + * set all item large and small TextView size + * Each item has tow label, one is large, another is small. + * Small one will be shown when item state is normal + * Large one will be shown when item checked. + * + * @param sp + */ + public void setTextSize(float sp) { + setLargeTextSize(sp); + setSmallTextSize(sp); + } + + /** + * set item ImageView size which at position + * + * @param position position start from 0 + * @param width in dp + * @param height in dp + */ + public void setIconSizeAt(int position, float width, float height) { + ImageView icon = getIconAt(position); + // update size + ViewGroup.LayoutParams layoutParams = icon.getLayoutParams(); + layoutParams.width = dp2px(getContext(), width); + layoutParams.height = dp2px(getContext(), height); + icon.setLayoutParams(layoutParams); + + mMenuView.updateMenuView(); + } + + /** + * set all item ImageView size + * + * @param width in dp + * @param height in dp + */ + public void setIconSize(float width, float height) { + int count = getItemCount(); + for (int i = 0; i < count; i++) { + setIconSizeAt(i, width, height); + } + } + + /** + * get menu item height + * + * @return in px + */ + public int getItemHeight() { + // 1. get mMenuView + final BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + // 2. get private final int mItemHeight in mMenuView + return getField(mMenuView.getClass(), mMenuView, "mItemHeight"); + } + + /** + * set menu item height + * + * @param height in px + */ + public void setItemHeight(int height) { + // 1. get mMenuView + final BottomNavigationMenuView mMenuView = getBottomNavigationMenuView(); + // 2. set private final int mItemHeight in mMenuView + setField(mMenuView.getClass(), mMenuView, "mItemHeight", height); + + mMenuView.updateMenuView(); + } + + /** + * set Typeface for all item TextView + * + * @attr ref android.R.styleable#TextView_typeface + * @attr ref android.R.styleable#TextView_textStyle + */ + public void setTypeface(Typeface typeface, int style) { + int count = getItemCount(); + for (int i = 0; i < count; i++) { + getLargeLabelAt(i).setTypeface(typeface, style); + getSmallLabelAt(i).setTypeface(typeface, style); + } + mMenuView.updateMenuView(); + } + + /** + * set Typeface for all item TextView + * + * @attr ref android.R.styleable#TextView_typeface + */ + public void setTypeface(Typeface typeface) { + int count = getItemCount(); + for (int i = 0; i < count; i++) { + getLargeLabelAt(i).setTypeface(typeface); + getSmallLabelAt(i).setTypeface(typeface); + } + mMenuView.updateMenuView(); + } + + /** + * get private filed in this specific object + * + * @param targetClass + * @param instance the filed owner + * @param fieldName + * @param + * @return field if success, null otherwise. + */ + private T getField(Class targetClass, Object instance, String fieldName) { + try { + Field field = targetClass.getDeclaredField(fieldName); + field.setAccessible(true); + return (T) field.get(instance); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } + + /** + * change the field value + * + * @param targetClass + * @param instance the filed owner + * @param fieldName + * @param value + */ + private void setField(Class targetClass, Object instance, String fieldName, Object value) { + try { + Field field = targetClass.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(instance, value); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + /** + * This method will link the given ViewPager and this BottomNavigationViewEx together so that + * changes in one are automatically reflected in the other. This includes scroll state changes + * and clicks. + * + * @param viewPager + */ + public void setupWithViewPager(@Nullable final ViewPager viewPager) { + setupWithViewPager(viewPager, false); + } + + /** + * This method will link the given ViewPager and this BottomNavigationViewEx together so that + * changes in one are automatically reflected in the other. This includes scroll state changes + * and clicks. + * + * @param viewPager + * @param smoothScroll whether ViewPager changed with smooth scroll animation + */ + public void setupWithViewPager(@Nullable final ViewPager viewPager, boolean smoothScroll) { + if (mViewPager != null) { + // If we've already been setup with a ViewPager, remove us from it + if (mPageChangeListener != null) { + mViewPager.removeOnPageChangeListener(mPageChangeListener); + } + } + + if (null == viewPager) { + mViewPager = null; + super.setOnNavigationItemSelectedListener(null); + return; + } + + mViewPager = viewPager; + + // Add our custom OnPageChangeListener to the ViewPager + if (mPageChangeListener == null) { + mPageChangeListener = new BottomNavigationViewExOnPageChangeListener(this); + } + viewPager.addOnPageChangeListener(mPageChangeListener); + + // Now we'll add a navigation item selected listener to set ViewPager's current item + OnNavigationItemSelectedListener listener = getOnNavigationItemSelectedListener(); + mMyOnNavigationItemSelectedListener = new MyOnNavigationItemSelectedListener(viewPager, this, smoothScroll, listener); + super.setOnNavigationItemSelectedListener(mMyOnNavigationItemSelectedListener); + } + + public void enableShiftingMode(int position, boolean enable) { + getBottomNavigationItemView(position).setShiftingMode(enable); + } + + public void setItemBackground(int position, int background) { + getBottomNavigationItemView(position).setItemBackground(background); + } + + public void setIconTintList(int position, ColorStateList tint) { + getBottomNavigationItemView(position).setIconTintList(tint); + } + + public void setTextTintList(int position, ColorStateList tint) { + getBottomNavigationItemView(position).setTextColor(tint); + } + + /** + * set margin top for all icons + * + * @param marginTop in px + */ + public void setIconsMarginTop(int marginTop) { + for (int i = 0; i < getItemCount(); i++) { + setIconMarginTop(i, marginTop); + } + } + + /** + * set margin top for icon + * + * @param position + * @param marginTop in px + */ + public void setIconMarginTop(int position, int marginTop) { + /* + 1. BottomNavigationItemView + 2. private final int mDefaultMargin; + */ + BottomNavigationItemView itemView = getBottomNavigationItemView(position); + setField(BottomNavigationItemView.class, itemView, "mDefaultMargin", marginTop); + mMenuView.updateMenuView(); + } + + + /** + * A {@link ViewPager.OnPageChangeListener} class which contains the + * necessary calls back to the provided {@link BottomNavigationViewEx} so that the tab position is + * kept in sync. + *

    + *

    This class stores the provided BottomNavigationViewEx weakly, meaning that you can use + * {@link ViewPager#addOnPageChangeListener(ViewPager.OnPageChangeListener) + * addOnPageChangeListener(OnPageChangeListener)} without removing the listener and + * not cause a leak. + */ + private static class BottomNavigationViewExOnPageChangeListener implements ViewPager.OnPageChangeListener { + private final WeakReference mBnveRef; + + public BottomNavigationViewExOnPageChangeListener(BottomNavigationViewEx bnve) { + mBnveRef = new WeakReference<>(bnve); + } + + @Override + public void onPageScrollStateChanged(final int state) { + } + + @Override + public void onPageScrolled(final int position, final float positionOffset, + final int positionOffsetPixels) { + } + + @Override + public void onPageSelected(final int position) { + final BottomNavigationViewEx bnve = mBnveRef.get(); + if (null != bnve) + bnve.setCurrentItem(position); +// Log.d("onPageSelected", "--------- position " + position + " ------------"); + } + } + + /** + * Decorate OnNavigationItemSelectedListener for setupWithViewPager + */ + private static class MyOnNavigationItemSelectedListener implements OnNavigationItemSelectedListener { + private final WeakReference viewPagerRef; + private OnNavigationItemSelectedListener listener; + private boolean smoothScroll; + private SparseIntArray items;// used for change ViewPager selected item + private int previousPosition = -1; + + + MyOnNavigationItemSelectedListener(ViewPager viewPager, BottomNavigationViewEx bnve, boolean smoothScroll, OnNavigationItemSelectedListener listener) { + this.viewPagerRef = new WeakReference<>(viewPager); + this.listener = listener; + this.smoothScroll = smoothScroll; + + // create items + Menu menu = bnve.getMenu(); + int size = menu.size(); + items = new SparseIntArray(size); + for (int i = 0; i < size; i++) { + int itemId = menu.getItem(i).getItemId(); + items.put(itemId, i); + } + } + + public void setOnNavigationItemSelectedListener(OnNavigationItemSelectedListener listener) { + this.listener = listener; + } + + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + int position = items.get(item.getItemId()); + // only set item when item changed + if (previousPosition == position) { + return true; + } + + // user listener + if (null != listener) { + boolean bool = listener.onNavigationItemSelected(item); + // if the selected is invalid, no need change the view pager + if (!bool) + return false; + } + + // change view pager + ViewPager viewPager = viewPagerRef.get(); + if (null == viewPager) + return false; + + viewPager.setCurrentItem(items.get(item.getItemId()), smoothScroll); + + // update previous position + previousPosition = position; + + return true; + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/BottomSheetListView.java b/app/src/main/java/code/name/monkey/retromusic/views/BottomSheetListView.java new file mode 100644 index 00000000..b84e0a4d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/BottomSheetListView.java @@ -0,0 +1,41 @@ +package code.name.monkey.retromusic.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.AbsListView; +import android.widget.ListView; + +public class BottomSheetListView extends ListView { + public BottomSheetListView(Context context, AttributeSet p_attrs) { + super(context, p_attrs); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return true; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (canScrollVertically(this)) { + getParent().requestDisallowInterceptTouchEvent(true); + } + return super.onTouchEvent(ev); + } + + public boolean canScrollVertically(AbsListView view) { + boolean canScroll = false; + + if (view != null && view.getChildCount() > 0) { + boolean isOnTop = view.getFirstVisiblePosition() != 0 || view.getChildAt(0).getTop() != 0; + boolean isAllItemsVisible = isOnTop && view.getLastVisiblePosition() == view.getChildCount(); + + if (isOnTop || isAllItemsVisible) { + canScroll = true; + } + } + + return canScroll; + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/BreadCrumbLayout.java b/app/src/main/java/code/name/monkey/retromusic/views/BreadCrumbLayout.java new file mode 100644 index 00000000..4f9019d7 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/BreadCrumbLayout.java @@ -0,0 +1,417 @@ +package code.name.monkey.retromusic.views; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import code.name.monkey.appthemehelper.ThemeStore; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import code.name.monkey.retromusic.R; + +/** + * @author Aidan Follestad (afollestad), modified for Phonograph by Karim Abou Zeid (kabouzeid) + */ +public class BreadCrumbLayout extends HorizontalScrollView implements View.OnClickListener { + + @ColorInt + private int contentColorActivated; + @ColorInt + private int contentColorDeactivated; + + public static class Crumb implements Parcelable { + + public Crumb(File file) { + this.file = file; + } + + private final File file; + private int scrollPos; + + public int getScrollPosition() { + return scrollPos; + } + + public void setScrollPosition(int scrollY) { + this.scrollPos = scrollY; + } + + public String getTitle() { + return file.getPath().equals("/") ? "root" : file.getName(); + } + + public File getFile() { + return file; + } + + @Override + public boolean equals(Object o) { + return (o instanceof Crumb) && ((Crumb) o).getFile() != null && + ((Crumb) o).getFile().equals(getFile()); + } + + @Override + public String toString() { + return "Crumb{" + + "file=" + file + + ", scrollPos=" + scrollPos + + '}'; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeSerializable(this.file); + dest.writeInt(this.scrollPos); + } + + protected Crumb(Parcel in) { + this.file = (File) in.readSerializable(); + this.scrollPos = in.readInt(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public Crumb createFromParcel(Parcel source) { + return new Crumb(source); + } + + @Override + public Crumb[] newArray(int size) { + return new Crumb[size]; + } + }; + } + + public interface SelectionCallback { + void onCrumbSelection(Crumb crumb, int index); + } + + public BreadCrumbLayout(Context context) { + super(context); + init(); + } + + public BreadCrumbLayout(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public BreadCrumbLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + // Stores currently visible crumbs + private List mCrumbs; + // Used in setActiveOrAdd() between clearing crumbs and adding the new set, nullified afterwards + private List mOldCrumbs; + // Stores user's navigation history, like a fragment back stack + private List mHistory; + + private LinearLayout mChildFrame; + private int mActive; + private SelectionCallback mCallback; + + private void init() { + contentColorActivated = ThemeStore.textColorPrimary(getContext()); + contentColorDeactivated = ThemeStore.textColorSecondary(getContext()); + setMinimumHeight((int) getResources().getDimension(R.dimen.tab_height)); + setClipToPadding(false); + setHorizontalScrollBarEnabled(false); + mCrumbs = new ArrayList<>(); + mHistory = new ArrayList<>(); + mChildFrame = new LinearLayout(getContext()); + addView(mChildFrame, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); + } + + public void addHistory(Crumb crumb) { + mHistory.add(crumb); + } + + public Crumb lastHistory() { + if (mHistory.size() == 0) return null; + return mHistory.get(mHistory.size() - 1); + } + + public boolean popHistory() { + if (mHistory.size() == 0) return false; + mHistory.remove(mHistory.size() - 1); + return mHistory.size() != 0; + } + + public int historySize() { + return mHistory.size(); + } + + public void clearHistory() { + mHistory.clear(); + } + + public void reverseHistory() { + Collections.reverse(mHistory); + } + + public void addCrumb(@NonNull Crumb crumb, boolean refreshLayout) { + LinearLayout view = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.bread_crumb, this, false); + view.setTag(mCrumbs.size()); + view.setOnClickListener(this); + + ImageView iv = (ImageView) view.getChildAt(1); + if (Build.VERSION.SDK_INT >= 19 && iv.getDrawable() != null) { + iv.getDrawable().setAutoMirrored(true); + } + iv.setVisibility(View.GONE); + + mChildFrame.addView(view, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + mCrumbs.add(crumb); + if (refreshLayout) { + mActive = mCrumbs.size() - 1; + requestLayout(); + } + invalidateActivatedAll(); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + //RTL works fine like this + View child = mChildFrame.getChildAt(mActive); + if (child != null) + smoothScrollTo(child.getLeft(), 0); + } + + public Crumb findCrumb(@NonNull File forDir) { + for (int i = 0; i < mCrumbs.size(); i++) { + if (mCrumbs.get(i).getFile().equals(forDir)) + return mCrumbs.get(i); + } + return null; + } + + public void clearCrumbs() { + try { + mOldCrumbs = new ArrayList<>(mCrumbs); + mCrumbs.clear(); + mChildFrame.removeAllViews(); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + + public Crumb getCrumb(int index) { + return mCrumbs.get(index); + } + + public void setCallback(SelectionCallback callback) { + mCallback = callback; + } + + private boolean setActive(Crumb newActive) { + mActive = mCrumbs.indexOf(newActive); + invalidateActivatedAll(); + boolean success = mActive > -1; + if (success) + requestLayout(); + return success; + } + + void invalidateActivatedAll() { + for (int i = 0; i < mCrumbs.size(); i++) { + Crumb crumb = mCrumbs.get(i); + invalidateActivated(mChildFrame.getChildAt(i), mActive == mCrumbs.indexOf(crumb), false, i < mCrumbs.size() - 1).setText(crumb.getTitle()); + } + } + + void removeCrumbAt(int index) { + mCrumbs.remove(index); + mChildFrame.removeViewAt(index); + } + + public boolean trim(String path, boolean dir) { + if (!dir) return false; + int index = -1; + for (int i = mCrumbs.size() - 1; i >= 0; i--) { + File fi = mCrumbs.get(i).getFile(); + if (fi.getPath().equals(path)) { + index = i; + break; + } + } + + boolean removedActive = index >= mActive; + if (index > -1) { + while (index <= mCrumbs.size() - 1) + removeCrumbAt(index); + if (mChildFrame.getChildCount() > 0) { + int lastIndex = mCrumbs.size() - 1; + invalidateActivated(mChildFrame.getChildAt(lastIndex), mActive == lastIndex, false, false); + } + } + return removedActive || mCrumbs.size() == 0; + } + + public boolean trim(File file) { + return trim(file.getPath(), file.isDirectory()); + } + + void updateIndices() { + for (int i = 0; i < mChildFrame.getChildCount(); i++) + mChildFrame.getChildAt(i).setTag(i); + } + + public void setActiveOrAdd(@NonNull Crumb crumb, boolean forceRecreate) { + if (forceRecreate || !setActive(crumb)) { + clearCrumbs(); + final List newPathSet = new ArrayList<>(); + + newPathSet.add(0, crumb.getFile()); + + File p = crumb.getFile(); + while ((p = p.getParentFile()) != null) { + newPathSet.add(0, p); + } + + for (int index = 0; index < newPathSet.size(); index++) { + final File fi = newPathSet.get(index); + crumb = new Crumb(fi); + + // Restore scroll positions saved before clearing + if (mOldCrumbs != null) { + for (Iterator iterator = mOldCrumbs.iterator(); iterator.hasNext(); ) { + Crumb old = iterator.next(); + if (old.equals(crumb)) { + crumb.setScrollPosition(old.getScrollPosition()); + iterator.remove(); // minimize number of linear passes by removing un-used crumbs from history + break; + } + } + } + + addCrumb(crumb, true); + } + + // History no longer needed + mOldCrumbs = null; + } + } + + public int size() { + return mCrumbs.size(); + } + + private TextView invalidateActivated(View view, final boolean isActive, final boolean noArrowIfAlone, final boolean allowArrowVisible) { + int contentColor = isActive ? contentColorActivated : contentColorDeactivated; + LinearLayout child = (LinearLayout) view; + TextView tv = (TextView) child.getChildAt(0); + tv.setTextColor(contentColor); + ImageView iv = (ImageView) child.getChildAt(1); + iv.setColorFilter(contentColor, PorterDuff.Mode.SRC_IN); + if (noArrowIfAlone && getChildCount() == 1) + iv.setVisibility(View.GONE); + else if (allowArrowVisible) + iv.setVisibility(View.VISIBLE); + else + iv.setVisibility(View.GONE); + return tv; + } + + public int getActiveIndex() { + return mActive; + } + + public void setActivatedContentColor(@ColorInt int contentColorActivated) { + this.contentColorActivated = contentColorActivated; + } + + public void setDeactivatedContentColor(@ColorInt int contentColorDeactivated) { + this.contentColorDeactivated = contentColorDeactivated; + } + + @Override + public void onClick(View v) { + if (mCallback != null) { + int index = (Integer) v.getTag(); + mCallback.onCrumbSelection(mCrumbs.get(index), index); + } + } + + public static class SavedStateWrapper implements Parcelable { + + public final int mActive; + public final List mCrumbs; + public final int mVisibility; + + public SavedStateWrapper(BreadCrumbLayout view) { + mActive = view.mActive; + mCrumbs = view.mCrumbs; + mVisibility = view.getVisibility(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(this.mActive); + dest.writeTypedList(mCrumbs); + dest.writeInt(this.mVisibility); + } + + protected SavedStateWrapper(Parcel in) { + this.mActive = in.readInt(); + this.mCrumbs = in.createTypedArrayList(Crumb.CREATOR); + this.mVisibility = in.readInt(); + } + + public static final Creator CREATOR = new Creator() { + public SavedStateWrapper createFromParcel(Parcel source) { + return new SavedStateWrapper(source); + } + + public SavedStateWrapper[] newArray(int size) { + return new SavedStateWrapper[size]; + } + }; + } + + public SavedStateWrapper getStateWrapper() { + return new SavedStateWrapper(this); + } + + public void restoreFromStateWrapper(SavedStateWrapper mSavedState) { + if (mSavedState != null) { + mActive = mSavedState.mActive; + for (Crumb c : mSavedState.mCrumbs) { + addCrumb(c, false); + } + requestLayout(); + setVisibility(mSavedState.mVisibility); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/CircularImageView.java b/app/src/main/java/code/name/monkey/retromusic/views/CircularImageView.java new file mode 100644 index 00000000..bfbef58b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/CircularImageView.java @@ -0,0 +1,310 @@ +package code.name.monkey.retromusic.views; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.AppCompatImageView; +import android.util.AttributeSet; +import android.util.Log; + +import code.name.monkey.retromusic.R; + +public class CircularImageView extends AppCompatImageView { + + private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; + + // Default Values + private static final float DEFAULT_BORDER_WIDTH = 4; + private static final float DEFAULT_SHADOW_RADIUS = 8.0f; + + // Properties + private float borderWidth; + private int canvasSize; + private float shadowRadius; + private int shadowColor = Color.BLACK; + + // Object used to draw + private Bitmap image; + private Drawable drawable; + private Paint paint; + private Paint paintBorder; + + //region Constructor & Init Method + public CircularImageView(final Context context) { + this(context, null); + } + + public CircularImageView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CircularImageView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs, defStyleAttr); + } + + private void init(Context context, AttributeSet attrs, int defStyleAttr) { + // Init paint + paint = new Paint(); + paint.setAntiAlias(true); + + paintBorder = new Paint(); + paintBorder.setAntiAlias(true); + + // Load the styled attributes and set their properties + TypedArray attributes = context + .obtainStyledAttributes(attrs, R.styleable.CircularImageView, defStyleAttr, 0); + + // Init Border + if (attributes.getBoolean(R.styleable.CircularImageView_civ_border, true)) { + float defaultBorderSize = + DEFAULT_BORDER_WIDTH * getContext().getResources().getDisplayMetrics().density; + setBorderWidth(attributes + .getDimension(R.styleable.CircularImageView_civ_border_width, defaultBorderSize)); + setBorderColor( + attributes.getColor(R.styleable.CircularImageView_civ_border_color, Color.WHITE)); + } + + // Init Shadow + if (attributes.getBoolean(R.styleable.CircularImageView_civ_shadow, false)) { + shadowRadius = DEFAULT_SHADOW_RADIUS; + drawShadow(attributes.getFloat(R.styleable.CircularImageView_civ_shadow_radius, shadowRadius), + attributes.getColor(R.styleable.CircularImageView_civ_shadow_color, shadowColor)); + } + attributes.recycle(); + } + //endregion + + //region Set Attr Method + public void setBorderWidth(float borderWidth) { + this.borderWidth = borderWidth; + requestLayout(); + invalidate(); + } + + public void setBorderColor(int borderColor) { + if (paintBorder != null) { + paintBorder.setColor(borderColor); + } + invalidate(); + } + + public void addShadow() { + if (shadowRadius == 0) { + shadowRadius = DEFAULT_SHADOW_RADIUS; + } + drawShadow(shadowRadius, shadowColor); + invalidate(); + } + + public void setShadowRadius(float shadowRadius) { + drawShadow(shadowRadius, shadowColor); + invalidate(); + } + + public void setShadowColor(int shadowColor) { + drawShadow(shadowRadius, shadowColor); + invalidate(); + } + + @Override + public ScaleType getScaleType() { + return SCALE_TYPE; + } + + @Override + public void setScaleType(ScaleType scaleType) { + if (scaleType != SCALE_TYPE) { + throw new IllegalArgumentException(String.format( + "ScaleType %s not supported. ScaleType.CENTER_CROP is used by default. So you don't need to use ScaleType.", + scaleType)); + } + } + //endregion + + //region Draw Method + @Override + public void onDraw(Canvas canvas) { + // Load the bitmap + loadBitmap(); + + // Check if image isn't null + if (image == null) { + return; + } + + if (!isInEditMode()) { + canvasSize = canvas.getWidth(); + if (canvas.getHeight() < canvasSize) { + canvasSize = canvas.getHeight(); + } + } + + // circleCenter is the x or y of the view's center + // radius is the radius in pixels of the cirle to be drawn + // paint contains the shader that will texture the shape + int circleCenter = (int) (canvasSize - (borderWidth * 2)) / 2; + // Draw Border + canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, + circleCenter + borderWidth - (shadowRadius + shadowRadius / 2), paintBorder); + // Draw CircularImageView + canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, + circleCenter - (shadowRadius + shadowRadius / 2), paint); + } + + private void loadBitmap() { + if (this.drawable == getDrawable()) { + return; + } + + this.drawable = getDrawable(); + this.image = drawableToBitmap(this.drawable); + updateShader(); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + canvasSize = w; + if (h < canvasSize) { + canvasSize = h; + } + if (image != null) { + updateShader(); + } + } + + private void drawShadow(float shadowRadius, int shadowColor) { + this.shadowRadius = shadowRadius; + this.shadowColor = shadowColor; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + setLayerType(LAYER_TYPE_SOFTWARE, paintBorder); + } + paintBorder.setShadowLayer(shadowRadius, 0.0f, shadowRadius / 2, shadowColor); + } + + private void updateShader() { + if (image == null) { + return; + } + + // Crop Center Image + image = cropBitmap(image); + + // Create Shader + BitmapShader shader = new BitmapShader(image, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + + // Center Image in Shader + Matrix matrix = new Matrix(); + matrix.setScale((float) canvasSize / (float) image.getWidth(), + (float) canvasSize / (float) image.getHeight()); + shader.setLocalMatrix(matrix); + + // Set Shader in Paint + paint.setShader(shader); + } + + private Bitmap cropBitmap(Bitmap bitmap) { + Bitmap bmp; + if (bitmap.getWidth() >= bitmap.getHeight()) { + bmp = Bitmap.createBitmap( + bitmap, + bitmap.getWidth() / 2 - bitmap.getHeight() / 2, + 0, + bitmap.getHeight(), bitmap.getHeight()); + } else { + bmp = Bitmap.createBitmap( + bitmap, + 0, + bitmap.getHeight() / 2 - bitmap.getWidth() / 2, + bitmap.getWidth(), bitmap.getWidth()); + } + return bmp; + } + + private Bitmap drawableToBitmap(Drawable drawable) { + if (drawable == null) { + return null; + } else if (drawable instanceof BitmapDrawable) { + return ((BitmapDrawable) drawable).getBitmap(); + } + + int intrinsicWidth = drawable.getIntrinsicWidth(); + int intrinsicHeight = drawable.getIntrinsicHeight(); + + if (!(intrinsicWidth > 0 && intrinsicHeight > 0)) { + return null; + } + + try { + // Create Bitmap object out of the drawable + Bitmap bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } catch (OutOfMemoryError e) { + // Simply return null of failed bitmap creations + Log.e(getClass().toString(), "Encountered OutOfMemoryError while generating bitmap!"); + return null; + } + } + //endregion + + //region Mesure Method + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = measureWidth(widthMeasureSpec); + int height = measureHeight(heightMeasureSpec); + /*int imageSize = (width < height) ? width : height; + setMeasuredDimension(imageSize, imageSize);*/ + setMeasuredDimension(width, height); + } + + private int measureWidth(int measureSpec) { + int result; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + if (specMode == MeasureSpec.EXACTLY) { + // The parent has determined an exact size for the child. + result = specSize; + } else if (specMode == MeasureSpec.AT_MOST) { + // The child can be as large as it wants up to the specified size. + result = specSize; + } else { + // The parent has not imposed any constraint on the child. + result = canvasSize; + } + + return result; + } + + private int measureHeight(int measureSpecHeight) { + int result; + int specMode = MeasureSpec.getMode(measureSpecHeight); + int specSize = MeasureSpec.getSize(measureSpecHeight); + + if (specMode == MeasureSpec.EXACTLY) { + // We were told how big to be + result = specSize; + } else if (specMode == MeasureSpec.AT_MOST) { + // The child can be as large as it wants up to the specified size. + result = specSize; + } else { + // Measure the text (beware: ascent is a negative number) + result = canvasSize; + } + + return (result + 2); + } + //endregion +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/DrawableGradient.java b/app/src/main/java/code/name/monkey/retromusic/views/DrawableGradient.java new file mode 100644 index 00000000..257584dc --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/DrawableGradient.java @@ -0,0 +1,22 @@ +package code.name.monkey.retromusic.views; + +import android.graphics.drawable.GradientDrawable; + +public class DrawableGradient extends GradientDrawable { + public DrawableGradient(Orientation orientations, int[] colors, int shape) { + super(orientations, colors); + try { + setShape(shape); + setGradientType(GradientDrawable.LINEAR_GRADIENT); + setCornerRadius(0); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public DrawableGradient SetTransparency(int transparencyPercent) { + this.setAlpha(255 - ((255 * transparencyPercent) / 100)); + return this; + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/HeightFitSquareLayout.java b/app/src/main/java/code/name/monkey/retromusic/views/HeightFitSquareLayout.java new file mode 100755 index 00000000..788a0374 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/HeightFitSquareLayout.java @@ -0,0 +1,39 @@ +package code.name.monkey.retromusic.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +public class HeightFitSquareLayout extends FrameLayout { + private boolean forceSquare = true; + + public HeightFitSquareLayout(Context context) { + super(context); + } + + public HeightFitSquareLayout(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + } + + public HeightFitSquareLayout(Context context, AttributeSet attributeSet, int i) { + super(context, attributeSet, i); + } + + @TargetApi(21) + public HeightFitSquareLayout(Context context, AttributeSet attributeSet, int i, int i2) { + super(context, attributeSet, i, i2); + } + + public void forceSquare(boolean z) { + this.forceSquare = z; + requestLayout(); + } + + protected void onMeasure(int i, int i2) { + if (this.forceSquare) { + i = i2; + } + super.onMeasure(i, i2); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/IconImageView.java b/app/src/main/java/code/name/monkey/retromusic/views/IconImageView.java new file mode 100644 index 00000000..42e3bbd2 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/IconImageView.java @@ -0,0 +1,33 @@ +package code.name.monkey.retromusic.views; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.util.AttributeSet; +import android.widget.ImageView; + +import code.name.monkey.appthemehelper.util.ATHUtil; + +import code.name.monkey.retromusic.R; + + +public class IconImageView extends android.support.v7.widget.AppCompatImageView { + public IconImageView(Context context) { + super(context); + init(context); + } + + public IconImageView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public IconImageView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + if (context == null) return; + setColorFilter(ATHUtil.resolveColor(context, R.attr.iconColor), PorterDuff.Mode.SRC_IN); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/LyricView.java b/app/src/main/java/code/name/monkey/retromusic/views/LyricView.java new file mode 100644 index 00000000..0f9660d3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/LyricView.java @@ -0,0 +1,876 @@ +package code.name.monkey.retromusic.views; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.os.Looper; +import android.support.annotation.IntDef; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; + +import org.mozilla.universalchardet.UniversalDetector; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + +import code.name.monkey.retromusic.R; + +/** + * Created by zhengken.me on 2016/11/27. + * ClassName : LyricView + * Description : + */ +public class LyricView extends View { + + public static final int LEFT = 0; + public static final int CENTER = 1; + public static final int RIGHT = 2; + private static final String TAG = "LyricView"; + private static final float SLIDE_COEFFICIENT = 0.2f; + + private static final int UNITS_SECOND = 1000; + private static final int UNITS_MILLISECOND = 1; + + private static final int FLING_ANIMATOR_DURATION = 500 * UNITS_MILLISECOND; + + private static final int THRESHOLD_Y_VELOCITY = 1600; + + private static final int INDICATOR_ICON_PLAY_MARGIN_LEFT = 7;//dp + private static final int INDICATOR_ICON_PLAY_WIDTH = 15;//sp + private static final int INDICATOR_LINE_MARGIN = 10;//dp + private static final int INDICATOR_TIME_TEXT_SIZE = 10;//sp + private static final int INDICATOR_TIME_MARGIN_RIGHT = 7;//dp + + private static final int DEFAULT_TEXT_SIZE = 16;//sp + private static final int DEFAULT_MAX_LENGTH = 300;//dp + private static final int DEFAULT_LINE_SPACE = 25;//dp + + private int mHintColor; + private int mDefaultColor; + private int mHighLightColor; + private int mTextAlign; + + + private int mLineCount; + private int mTextSize; + private float mLineHeight; + private LyricInfo mLyricInfo; + private String mDefaultHint; + private int mMaxLength; + + private TextPaint mTextPaint; + private Paint mBtnPlayPaint; + private Paint mLinePaint; + private Paint mTimerPaint; + + private boolean mFling = false; + private ValueAnimator mFlingAnimator; + private float mScrollY = 0; + private float mLineSpace = 0; + private boolean mIsShade; + private float mShaderWidth = 0; + private int mCurrentPlayLine = 0; + private boolean mShowIndicator; + + private VelocityTracker mVelocityTracker; + private float mVelocity = 0; + private float mDownX; + private float mDownY; + private float mLastScrollY; + private boolean mUserTouch = false; + Runnable hideIndicator = () -> { + setUserTouch(false); + invalidateView(); + }; + private int maxVelocity; + private int mLineNumberUnderIndicator = 0; + private Rect mBtnPlayRect = new Rect(); + private Rect mTimerRect; + private String mDefaultTime = "00:00"; + private int mLineColor = Color.parseColor("#EFEFEF"); + private int mBtnColor = Color.parseColor("#EFEFEF"); + private List mLineFeedRecord = new ArrayList<>(); + private boolean mEnableLineFeed = false; + private int mExtraHeight = 0; + private int mTextHeight; + private String mCurrentLyricFilePath = null; + private OnPlayerClickListener mClickListener; + + public LyricView(Context context) { + super(context); + initMyView(context); + } + + public LyricView(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + getAttrs(context, attributeSet); + initMyView(context); + + } + + public LyricView(Context context, AttributeSet attributeSet, int i) { + super(context, attributeSet, i); + getAttrs(context, attributeSet); + initMyView(context); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + return super.dispatchTouchEvent(event); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(event); + switch (event.getAction()) { + case MotionEvent.ACTION_CANCEL: + actionCancel(event); + break; + case MotionEvent.ACTION_DOWN: + actionDown(event); + break; + case MotionEvent.ACTION_MOVE: + actionMove(event); + break; + case MotionEvent.ACTION_UP: + actionUp(event); + break; + default: + break; + } + invalidateView(); + return true; + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + mBtnPlayRect.set((int) getRawSize(TypedValue.COMPLEX_UNIT_DIP, INDICATOR_ICON_PLAY_MARGIN_LEFT), + (int) (getHeight() * 0.5f - getRawSize(TypedValue.COMPLEX_UNIT_SP, INDICATOR_ICON_PLAY_WIDTH) * 0.5f), + (int) (getRawSize(TypedValue.COMPLEX_UNIT_SP, INDICATOR_ICON_PLAY_WIDTH) + getRawSize(TypedValue.COMPLEX_UNIT_DIP, INDICATOR_ICON_PLAY_MARGIN_LEFT)), + (int) (getHeight() * 0.5f + getRawSize(TypedValue.COMPLEX_UNIT_SP, INDICATOR_ICON_PLAY_WIDTH) * 0.5f)); + mShaderWidth = getWidth() * 0.4f; + } + + @Override + protected void onDraw(Canvas canvas) { + if (scrollable()) { + if (mShowIndicator) { + drawIndicator(canvas); + } + + for (int i = 0; i < mLineCount; i++) { + float x = 0; + switch (mTextAlign) { + case LEFT: + x = INDICATOR_ICON_PLAY_MARGIN_LEFT + INDICATOR_LINE_MARGIN + mBtnPlayRect.width(); + break; + case CENTER: + x = getWidth() * 0.5f; + break; + case RIGHT: + x = getWidth() - INDICATOR_LINE_MARGIN * 2 - mTimerRect.width() - INDICATOR_ICON_PLAY_MARGIN_LEFT; + break; + } + + float y; + if (mEnableLineFeed && i > 0) { + y = getMeasuredHeight() * 0.5f + i * mLineHeight - mScrollY + mLineFeedRecord.get(i - 1); + } else { + y = getMeasuredHeight() * 0.5f + i * mLineHeight - mScrollY; + } + +// float y = getHeight() * 0.5f + i * mLineHeight - mScrollY; + if (y < 0) { + continue; + } + if (y > getHeight()) { + break; + } + if (i == mCurrentPlayLine - 1) { + mTextPaint.setColor(mHighLightColor); + } else if (i == mLineNumberUnderIndicator && mShowIndicator) { + mTextPaint.setColor(Color.LTGRAY); + } else { + mTextPaint.setColor(mDefaultColor); + } + if (mIsShade && (y > getHeight() - mShaderWidth || y < mShaderWidth)) { + if (y < mShaderWidth) { + mTextPaint.setAlpha(26 + (int) (23000.0f * y / mShaderWidth * 0.01f)); + } else { + mTextPaint.setAlpha(26 + (int) (23000.0f * (getHeight() - y) / mShaderWidth * 0.01f)); + } + } else { + mTextPaint.setAlpha(255); + } + + if (mEnableLineFeed) { + StaticLayout staticLayout = new StaticLayout(mLyricInfo.songLines.get(i).content, mTextPaint, + mMaxLength, + Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + canvas.save(); + canvas.translate(x, y); + staticLayout.draw(canvas); + canvas.restore(); + } else { + canvas.drawText(mLyricInfo.songLines.get(i).content, x, y, mTextPaint); + } + } + } else { + mTextPaint.setColor(mHintColor); + canvas.drawText(mDefaultHint, getMeasuredWidth() / 2, getMeasuredHeight() / 2, mTextPaint); + } + } + + private void getAttrs(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LyricView); + mIsShade = ta.getBoolean(R.styleable.LyricView_fadeInFadeOut, false); + mDefaultHint = ta.getString(R.styleable.LyricView_hint) != null + ? ta.getString(R.styleable.LyricView_hint) + : getResources().getString(R.string.default_hint); + mHintColor = ta.getColor(R.styleable.LyricView_hintColor, Color.parseColor("#FFFFFF")); + mDefaultColor = ta.getColor(R.styleable.LyricView_textColor, Color.parseColor("#8D8D8D")); + mHighLightColor = ta.getColor(R.styleable.LyricView_highlightColor, Color.parseColor("#FFFFFF")); + mTextSize = ta.getDimensionPixelSize(R.styleable.LyricView_textSize, (int) getRawSize(TypedValue.COMPLEX_UNIT_SP, DEFAULT_TEXT_SIZE)); + mTextAlign = ta.getInt(R.styleable.LyricView_textAlign, CENTER); + mMaxLength = ta.getDimensionPixelSize(R.styleable.LyricView_maxLength, (int) getRawSize(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_MAX_LENGTH)); + mLineSpace = ta.getDimensionPixelSize(R.styleable.LyricView_lineSpace, (int) getRawSize(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_LINE_SPACE)); + ta.recycle(); + } + + public void setShade(boolean shade) { + mIsShade = shade; + invalidateView(); + } + + public void setHintColor(int hintColor) { + mHintColor = hintColor; + invalidateView(); + } + + public void setDefaultColor(int defaultColor) { + mDefaultColor = defaultColor; + invalidateView(); + } + + public void setHighLightColor(int highLightColor) { + mHighLightColor = highLightColor; + invalidateView(); + } + + public void setTextAlign(int textAlign) { + mTextAlign = textAlign; + invalidateView(); + } + + public void setLineCount(int lineCount) { + mLineCount = lineCount; + invalidateView(); + } + + public void setTextSize(int textSize) { + mTextSize = textSize; + invalidateView(); + } + + public void setDefaultHint(String defaultHint) { + mDefaultHint = defaultHint; + invalidateView(); + } + + public void setMaxLength(int maxLength) { + mMaxLength = maxLength; + invalidateView(); + } + + public void setOnPlayerClickListener(OnPlayerClickListener mClickListener) { + this.mClickListener = mClickListener; + } + + public void setAlignment(@Alignment int alignment) { + mTextAlign = alignment; + } + + public void setCurrentTimeMillis(long current) { + scrollToCurrentTimeMillis(current); + } + + public void setLyricFile(File file) { + + if (file == null || !file.exists()) { + reset(); + mCurrentLyricFilePath = ""; + return; + } else if (file.getPath().equals(mCurrentLyricFilePath)) { + return; + } else { + mCurrentLyricFilePath = file.getPath(); + reset(); + } + try { + + FileInputStream fis = new FileInputStream(file); + byte[] buf = new byte[1024]; + UniversalDetector detector = new UniversalDetector(null); + int nread; + while ((nread = fis.read(buf)) > 0 && !detector.isDone()) { + detector.handleData(buf, 0, nread); + } + + detector.dataEnd(); + String encoding = detector.getDetectedCharset(); + if (encoding != null) { + setLyricFile(file, encoding); + } else { + setLyricFile(file, "UTF-8"); + } + detector.reset(); + fis.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void setLyricFile(File file, String charsetName) { + if (file != null && file.exists()) { + try { + setupLyricResource(new FileInputStream(file), charsetName); + + for (int i = 0; i < mLyricInfo.songLines.size(); i++) { + + StaticLayout staticLayout = new StaticLayout(mLyricInfo.songLines.get(i).content, mTextPaint, + (int) getRawSize(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_MAX_LENGTH), + Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + + if (staticLayout.getLineCount() > 1) { + mEnableLineFeed = true; + mExtraHeight = mExtraHeight + (staticLayout.getLineCount() - 1) * mTextHeight; + } + + mLineFeedRecord.add(i, mExtraHeight); + + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } else { + invalidateView(); + } + } + + private void setLineSpace(float lineSpace) { + if (mLineSpace != lineSpace) { + mLineSpace = getRawSize(TypedValue.COMPLEX_UNIT_DIP, lineSpace); + measureLineHeight(); + mScrollY = measureCurrentScrollY(mCurrentPlayLine); + invalidateView(); + } + } + + public void reset() { + resetView(); + } + + private void actionCancel(MotionEvent event) { + releaseVelocityTracker(); + } + + private void actionDown(MotionEvent event) { + removeCallbacks(hideIndicator); + mLastScrollY = mScrollY; + mDownX = event.getX(); + mDownY = event.getY(); + if (mFlingAnimator != null) { + mFlingAnimator.cancel(); + mFlingAnimator = null; + } + setUserTouch(true); + } + + private boolean overScrolled() { + + return scrollable() && (mScrollY > mLineHeight * (mLineCount - 1) + mLineFeedRecord.get(mLineCount - 1) + (mEnableLineFeed ? mTextHeight : 0) || mScrollY < 0); + } + + private void actionMove(MotionEvent event) { + if (scrollable()) { + final VelocityTracker tracker = mVelocityTracker; + tracker.computeCurrentVelocity(UNITS_SECOND, maxVelocity); + mScrollY = mLastScrollY + mDownY - event.getY(); + mVelocity = tracker.getYVelocity(); + measureCurrentLine(); + } + } + + private void actionUp(MotionEvent event) { + + postDelayed(hideIndicator, 3 * UNITS_SECOND); + + releaseVelocityTracker(); + + if (scrollable()) { + if (overScrolled() && mScrollY < 0) { + smoothScrollTo(0); + return; + } + if (overScrolled() && mScrollY > mLineHeight * (mLineCount - 1) + mLineFeedRecord.get(mLineCount - 1) + (mEnableLineFeed ? mTextHeight : 0)) { + smoothScrollTo(mLineHeight * (mLineCount - 1) + mLineFeedRecord.get(mLineCount - 1) + (mEnableLineFeed ? mTextHeight : 0)); + return; + } + if (Math.abs(mVelocity) > THRESHOLD_Y_VELOCITY) { + doFlingAnimator(mVelocity); + return; + } + if (mShowIndicator && clickPlayer(event)) { + if (mLineNumberUnderIndicator != mCurrentPlayLine) { + mShowIndicator = false; + if (mClickListener != null) { + setUserTouch(false); + mClickListener.onPlayerClicked(mLyricInfo.songLines.get(mLineNumberUnderIndicator).start, mLyricInfo.songLines.get(mLineNumberUnderIndicator).content); + } + } + } + } + } + + private String measureCurrentTime() { + DecimalFormat format = new DecimalFormat("00"); + if (mLyricInfo != null && mLineCount > 0 && mLineNumberUnderIndicator - 1 < mLineCount && mLineNumberUnderIndicator > 0) { + return format.format(mLyricInfo.songLines.get(mLineNumberUnderIndicator - 1).start / 1000 / 60) + ":" + format.format(mLyricInfo.songLines.get(mLineNumberUnderIndicator - 1).start / 1000 % 60); + } + if (mLyricInfo != null && mLineCount > 0 && (mLineNumberUnderIndicator - 1) >= mLineCount) { + return format.format(mLyricInfo.songLines.get(mLineCount - 1).start / 1000 / 60) + ":" + format.format(mLyricInfo.songLines.get(mLineCount - 1).start / 1000 % 60); + } + if (mLyricInfo != null && mLineCount > 0 && mLineNumberUnderIndicator - 1 <= 0) { + return format.format(mLyricInfo.songLines.get(0).start / 1000 / 60) + ":" + format.format(mLyricInfo.songLines.get(0).start / 1000 % 60); + } + return mDefaultTime; + } + + private void drawIndicator(Canvas canvas) { + + //绘制 播放 按钮 + Path pathPlay = new Path(); + float yCoordinate = mBtnPlayRect.left + (float) Math.sqrt(Math.pow(mBtnPlayRect.width(), 2) - Math.pow(mBtnPlayRect.width() * 0.5f, 2)); + float remainWidth = mBtnPlayRect.right - yCoordinate; + + pathPlay.moveTo(mBtnPlayRect.centerX() - mBtnPlayRect.width() * 0.5f, mBtnPlayRect.centerY() - mBtnPlayRect.height() * 0.5f); + pathPlay.lineTo(mBtnPlayRect.centerX() - mBtnPlayRect.width() * 0.5f, mBtnPlayRect.centerY() + mBtnPlayRect.height() * 0.5f); + pathPlay.lineTo(yCoordinate, mBtnPlayRect.centerY()); + pathPlay.lineTo(mBtnPlayRect.centerX() - mBtnPlayRect.width() * 0.5f, mBtnPlayRect.centerY() - mBtnPlayRect.height() * 0.5f); + + canvas.drawPath(pathPlay, mBtnPlayPaint); + + //绘制 分割线 + Path pathLine = new Path(); + pathLine.moveTo(mBtnPlayRect.right + getRawSize(TypedValue.COMPLEX_UNIT_DIP, INDICATOR_LINE_MARGIN) - remainWidth, getMeasuredHeight() * 0.5f); + pathLine.lineTo(getWidth() - mTimerRect.width() - getRawSize(TypedValue.COMPLEX_UNIT_DIP, INDICATOR_TIME_MARGIN_RIGHT) - getRawSize(TypedValue.COMPLEX_UNIT_DIP, INDICATOR_LINE_MARGIN), getHeight() * 0.5f); + canvas.drawPath(pathLine, mLinePaint); + + //绘制 时间 + canvas.drawText(measureCurrentTime(), getWidth() - getRawSize(TypedValue.COMPLEX_UNIT_DIP, INDICATOR_TIME_MARGIN_RIGHT), (getHeight() + mTimerRect.height()) * 0.5f, mTimerPaint); + } + + private boolean clickPlayer(MotionEvent event) { + if (mBtnPlayRect != null && mDownX > (mBtnPlayRect.left - INDICATOR_ICON_PLAY_MARGIN_LEFT) && mDownX < (mBtnPlayRect.right + INDICATOR_ICON_PLAY_MARGIN_LEFT) && mDownY > (mBtnPlayRect.top - INDICATOR_ICON_PLAY_MARGIN_LEFT) && mDownY < (mBtnPlayRect.bottom + INDICATOR_ICON_PLAY_MARGIN_LEFT)) { + float upX = event.getX(); + float upY = event.getY(); + return upX > (mBtnPlayRect.left - INDICATOR_ICON_PLAY_MARGIN_LEFT) && upX < (mBtnPlayRect.right + INDICATOR_ICON_PLAY_MARGIN_LEFT) && upY > (mBtnPlayRect.top - INDICATOR_ICON_PLAY_MARGIN_LEFT) && upY < (mBtnPlayRect.bottom + INDICATOR_ICON_PLAY_MARGIN_LEFT); + } + return false; + } + + private void doFlingAnimator(float velocity) { + + float distance = (velocity / Math.abs(velocity) * (Math.abs(velocity) * SLIDE_COEFFICIENT)); + float to = Math.min(Math.max(0, (mScrollY - distance)), (mLineCount - 1) * mLineHeight + mLineFeedRecord.get(mLineCount - 1) + (mEnableLineFeed ? mTextHeight : 0)); + + mFlingAnimator = ValueAnimator.ofFloat(mScrollY, to); + mFlingAnimator.addUpdateListener(animation -> { + mScrollY = (float) animation.getAnimatedValue(); + measureCurrentLine(); + invalidateView(); + }); + + mFlingAnimator.addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationStart(Animator animation) { + super.onAnimationStart(animation); + mVelocity = 0; + mFling = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mFling = false; + } + + @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); + } + }); + + mFlingAnimator.setDuration(FLING_ANIMATOR_DURATION); + mFlingAnimator.setInterpolator(new DecelerateInterpolator()); + mFlingAnimator.start(); + } + + private void setUserTouch(boolean isUserTouch) { + if (isUserTouch) { + mUserTouch = true; + mShowIndicator = true; + } else { + mUserTouch = false; + mShowIndicator = false; + } + } + + private void releaseVelocityTracker() { + if (mVelocityTracker != null) { + mVelocityTracker.clear(); + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + private void initMyView(Context context) { + maxVelocity = ViewConfiguration.get(context).getScaledMaximumFlingVelocity(); + initPaint(); + initAllBounds(); + } + + private void initAllBounds() { + setRawTextSize(mTextSize); + + setLineSpace(mLineSpace); + measureLineHeight(); + + mTimerRect = new Rect(); + mTimerPaint.getTextBounds(mDefaultTime, 0, mDefaultTime.length(), mTimerRect); + + + } + + private void initPaint() { + mTextPaint = new TextPaint(); + mTextPaint.setDither(true); + mTextPaint.setAntiAlias(true); + Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/circular_std_book.otf"); + mTextPaint.setTypeface(typeface); + + switch (mTextAlign) { + case LEFT: + mTextPaint.setTextAlign(Paint.Align.LEFT); + break; + case CENTER: + mTextPaint.setTextAlign(Paint.Align.CENTER); + break; + case RIGHT: + mTextPaint.setTextAlign(Paint.Align.RIGHT); + break; + } + + mBtnPlayPaint = new Paint(); + mBtnPlayPaint.setDither(true); + mBtnPlayPaint.setAntiAlias(true); + mBtnPlayPaint.setColor(mBtnColor); + mBtnPlayPaint.setStyle(Paint.Style.FILL_AND_STROKE); + mBtnPlayPaint.setAlpha(128); + + mLinePaint = new Paint(); + mLinePaint.setDither(true); + mLinePaint.setAntiAlias(true); + mLinePaint.setColor(mLineColor); + mLinePaint.setAlpha(64); + mLinePaint.setStrokeWidth(1.0f); + mLinePaint.setStyle(Paint.Style.STROKE); + + mTimerPaint = new Paint(); + mTimerPaint.setDither(true); + mTimerPaint.setAntiAlias(true); + mTimerPaint.setColor(Color.WHITE); + mTimerPaint.setTextAlign(Paint.Align.RIGHT); + mTimerPaint.setTextSize(getRawSize(TypedValue.COMPLEX_UNIT_SP, INDICATOR_TIME_TEXT_SIZE)); + + + } + + private float measureCurrentScrollY(int line) { + if (mEnableLineFeed && line > 1) { + return (line - 1) * mLineHeight + mLineFeedRecord.get(line - 1); + } + return (line - 1) * mLineHeight; + } + + private void invalidateView() { + if (Looper.getMainLooper() == Looper.myLooper()) { + // 当前线程是主UI线程,直接刷新。 + invalidate(); + } else { + // 当前线程是非UI线程,post刷新。 + postInvalidate(); + } + } + + private void measureLineHeight() { + Rect lineBound = new Rect(); + mTextPaint.getTextBounds(mDefaultHint, 0, mDefaultHint.length(), lineBound); + mTextHeight = lineBound.height(); + mLineHeight = mTextHeight + mLineSpace; + } + + /** + * To measure current showing line number based on the view's scroll Y + */ + private void measureCurrentLine() { + float baseScrollY = mScrollY + mLineHeight * 0.5f; + + if (mEnableLineFeed) { + for (int i = mLyricInfo.songLines.size(); i >= 0; i--) { + if (baseScrollY > measureCurrentScrollY(i) + mLineSpace * 0.2) { + mLineNumberUnderIndicator = i - 1; + break; + } + } + } else { + mLineNumberUnderIndicator = (int) (baseScrollY / mLineHeight); + } + + + } + + private void smoothScrollTo(float toY) { + final ValueAnimator animator = ValueAnimator.ofFloat(mScrollY, toY); + animator.addUpdateListener(valueAnimator -> { + mScrollY = (Float) valueAnimator.getAnimatedValue(); + invalidateView(); + }); + + animator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationCancel(Animator animator) { + } + + @Override + public void onAnimationEnd(Animator animator) { + mFling = false; + measureCurrentLine(); + invalidateView(); + } + + @Override + public void onAnimationRepeat(Animator animator) { + } + + @Override + public void onAnimationStart(Animator animator) { + mFling = true; + } + }); + animator.setDuration(640); + animator.setInterpolator(new LinearInterpolator()); + + animator.start(); + } + + private boolean scrollable() { + return mLyricInfo != null && mLyricInfo.songLines != null && mLyricInfo.songLines.size() > 0; + } + + private void scrollToCurrentTimeMillis(long time) { + + int position = 0; + if (scrollable()) { + for (int i = 0, size = mLineCount; i < size; i++) { + LineInfo lineInfo = mLyricInfo.songLines.get(i); + if (lineInfo != null && lineInfo.start >= time) { + position = i; + break; + } + if (i == mLineCount - 1) { + position = mLineCount; + } + } + } + if (mCurrentPlayLine != position) { + mCurrentPlayLine = position; + if (!mFling && !mUserTouch) { + smoothScrollTo(measureCurrentScrollY(position)); + } + } + } + + private void setupLyricResource(InputStream inputStream, String charsetName) { + if (inputStream != null) { + try { + LyricInfo lyricInfo = new LyricInfo(); + lyricInfo.songLines = new ArrayList<>(); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, charsetName); + BufferedReader reader = new BufferedReader(inputStreamReader); + String line; + while ((line = reader.readLine()) != null) { + analyzeLyric(lyricInfo, line); + } + reader.close(); + inputStream.close(); + inputStreamReader.close(); + + mLyricInfo = lyricInfo; + mLineCount = mLyricInfo.songLines.size(); + invalidateView(); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + invalidateView(); + } + } + + /** + * 逐行解析歌词内容 + */ + private void analyzeLyric(LyricInfo lyricInfo, String line) { + int index = line.lastIndexOf("]"); + if (line.startsWith("[offset:")) { + // time offset + lyricInfo.songOffset = Long.parseLong(line.substring(8, index).trim()); + return; + } + if (line.startsWith("[ti:")) { + // title + lyricInfo.songTitle = line.substring(4, index).trim(); + return; + } + if (line.startsWith("[ar:")) { + // artist + lyricInfo.songArtist = line.substring(4, index).trim(); + return; + } + if (line.startsWith("[al:")) { + // album + lyricInfo.songAlbum = line.substring(4, index).trim(); + return; + } + if (line.startsWith("[by:")) { + return; + } + if (index >= 9 && line.trim().length() > index + 1) { + // lyrics + LineInfo lineInfo = new LineInfo(); + lineInfo.content = line.substring(10, line.length()); + lineInfo.start = measureStartTimeMillis(line.substring(0, index)); + lyricInfo.songLines.add(lineInfo); + } + } + + /** + * 从字符串中获得时间值 + */ + private long measureStartTimeMillis(String str) { + long minute = Long.parseLong(str.substring(1, 3)); + long second = Long.parseLong(str.substring(4, 6)); + long millisecond = Long.parseLong(str.substring(7, 9)); + return millisecond + second * 1000 + minute * 60 * 1000; + } + + private void resetLyricInfo() { + if (mLyricInfo != null) { + if (mLyricInfo.songLines != null) { + mLyricInfo.songLines.clear(); + mLyricInfo.songLines = null; + } + mLyricInfo = null; + } + } + + private void resetView() { + mCurrentPlayLine = 0; + resetLyricInfo(); + invalidateView(); + mLineCount = 0; + mScrollY = 0; + mEnableLineFeed = false; + mLineFeedRecord.clear(); + mExtraHeight = 0; + } + + private float getRawSize(int unit, float size) { + Context context = getContext(); + Resources resources; + if (context == null) { + resources = Resources.getSystem(); + } else { + resources = context.getResources(); + } + return TypedValue.applyDimension(unit, size, resources.getDisplayMetrics()); + } + + private void setRawTextSize(float size) { + if (size != mTextPaint.getTextSize()) { + mTextPaint.setTextSize(size); + measureLineHeight(); + mScrollY = measureCurrentScrollY(mCurrentPlayLine); + invalidateView(); + } + } + + @IntDef({LEFT, CENTER, RIGHT}) + @Retention(RetentionPolicy.SOURCE) + public @interface Alignment { + } + + public interface OnPlayerClickListener { + void onPlayerClicked(long progress, String content); + } + + private class LyricInfo { + List songLines; + + String songArtist; + String songTitle; + String songAlbum; + + long songOffset; + } + + private class LineInfo { + String content; + long start; + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/MetalRecyclerViewPager.java b/app/src/main/java/code/name/monkey/retromusic/views/MetalRecyclerViewPager.java new file mode 100644 index 00000000..c6319bc3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/MetalRecyclerViewPager.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2017. Alexander Bilchuk + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 code.name.monkey.retromusic.views; + +import android.content.Context; +import android.content.res.TypedArray; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.PagerSnapHelper; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.SnapHelper; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.ViewGroup; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder; + +public class MetalRecyclerViewPager extends RecyclerView { + + private int itemMargin; + + public MetalRecyclerViewPager(Context context) { + super(context); + init(context, null); + } + + public MetalRecyclerViewPager(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public MetalRecyclerViewPager(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs); + } + + private void init(Context context, @Nullable AttributeSet attrs) { + if (attrs != null) { + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MetalRecyclerViewPager, 0, 0); + itemMargin = (int) typedArray.getDimension(R.styleable.MetalRecyclerViewPager_itemMargin, 0f); + typedArray.recycle(); + } + + setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); + SnapHelper snapHelper = new PagerSnapHelper(); + snapHelper.attachToRecyclerView(this); + } + + public void setAdapter(Adapter adapter) { + if (MetalAdapter.class.isInstance(adapter)) { + MetalAdapter metalAdapter = (MetalAdapter) adapter; + metalAdapter.setItemMargin(itemMargin); + metalAdapter.updateDisplayMetrics(); + } else { + throw new IllegalArgumentException("Only MetalAdapter is allowed here"); + } + super.setAdapter(adapter); + } + + public static abstract class MetalAdapter extends RecyclerView.Adapter { + + private DisplayMetrics metrics; + private int itemMargin; + private int itemWidth; + + public MetalAdapter(@NonNull DisplayMetrics metrics) { + this.metrics = metrics; + } + + void setItemMargin(int itemMargin) { + this.itemMargin = itemMargin; + } + + void updateDisplayMetrics() { + itemWidth = metrics.widthPixels - itemMargin * 2; + } + + @Override + public void onBindViewHolder(VH holder, int position) { + int currentItemWidth = itemWidth; + + if (position == 0) { + currentItemWidth += itemMargin; + holder.rootLayout.setPadding(0, 0, 0, 0); + } else if (position == getItemCount() - 1) { + currentItemWidth += itemMargin; + holder.rootLayout.setPadding(0, 0, 0, 0); + } + + int height = holder.rootLayout.getLayoutParams().height; + holder.rootLayout.setLayoutParams(new ViewGroup.LayoutParams(currentItemWidth, height)); + } + + + } + + public static abstract class MetalViewHolder extends MediaEntryViewHolder { + + ViewGroup rootLayout; + + public MetalViewHolder(View itemView) { + super(itemView); + rootLayout = (ViewGroup) itemView.findViewById(R.id.root_layout); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/NetworkImageView.java b/app/src/main/java/code/name/monkey/retromusic/views/NetworkImageView.java new file mode 100644 index 00000000..07a369a0 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/NetworkImageView.java @@ -0,0 +1,41 @@ +package code.name.monkey.retromusic.views; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; + +import com.bumptech.glide.Glide; + +import code.name.monkey.retromusic.R; + +/** + * @author Hemanth S (h4h13). + */ +public class NetworkImageView extends CircularImageView { + + public NetworkImageView(Context context) { + super(context); + init(context, null); + } + + public NetworkImageView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public NetworkImageView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs); + } + + private void init(Context context, AttributeSet attributeSet) { + TypedArray attributes = context + .obtainStyledAttributes(attributeSet, R.styleable.NetworkImageView, 0, 0); + String url = attributes.getString(R.styleable.NetworkImageView_url_link); + Glide.with(context).load(url).asBitmap() + .error(R.drawable.ic_person_flat) + .placeholder(R.drawable.ic_person_flat) + .into(this); + attributes.recycle(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/PlayPauseDrawable.java b/app/src/main/java/code/name/monkey/retromusic/views/PlayPauseDrawable.java new file mode 100644 index 00000000..6e9cb3aa --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/PlayPauseDrawable.java @@ -0,0 +1,213 @@ +package code.name.monkey.retromusic.views; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.CornerPathEffect; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.util.Property; +import android.view.animation.DecelerateInterpolator; + +import code.name.monkey.retromusic.R; + + +public class PlayPauseDrawable extends Drawable { + private static final long PLAY_PAUSE_ANIMATION_DURATION = 250; + + private static final Property PROGRESS = + new Property(Float.class, "progress") { + @Override + public Float get(@NonNull PlayPauseDrawable d) { + return d.getProgress(); + } + + @Override + public void set(@NonNull PlayPauseDrawable d, Float value) { + d.setProgress(value); + } + }; + + private final Path leftPauseBar = new Path(); + private final Path rightPauseBar = new Path(); + private final Paint paint = new Paint(); + private final float pauseBarWidth; + private final float pauseBarHeight; + private final float pauseBarDistance; + + private float width; + private float height; + + private float progress; + private boolean isPlay; + private boolean isPlaySet; + + private Animator animator; + + public PlayPauseDrawable(@NonNull Context context) { + final Resources res = context.getResources(); + paint.setAntiAlias(true); + paint.setStyle(Paint.Style.FILL); + paint.setColor(Color.WHITE); + + pauseBarWidth = res.getDimensionPixelSize(R.dimen.pause_bar_width); + pauseBarHeight = res.getDimensionPixelSize(R.dimen.pause_bar_height); + pauseBarDistance = res.getDimensionPixelSize(R.dimen.pause_bar_distance); + } + + /** + * Linear interpolate between a and b with parameter t. + */ + private static float lerp(float a, float b, float t) { + return a + (b - a) * t; + } + + @Override + protected void onBoundsChange(@NonNull final Rect bounds) { + super.onBoundsChange(bounds); + if (bounds.width() > 0 && bounds.height() > 0) { + width = bounds.width(); + height = bounds.height(); + } + } + + @Override + public void draw(@NonNull Canvas canvas) { + leftPauseBar.rewind(); + rightPauseBar.rewind(); + + // The current distance between the two pause bars. + final float barDist = lerp(pauseBarDistance, 0f, progress); + // The current width of each pause bar. + float rawBarWidth = lerp(pauseBarWidth, pauseBarHeight / 1.75f, progress); + // We have to round the bar width when finishing the progress to prevent the gap + // that might occur onDraw because of a pixel is lost when casting float to int instead of rounding it. + final float barWidth = progress == 1f ? Math.round(rawBarWidth) : rawBarWidth; + // The current position of the left pause bar's top left coordinate. + final float firstBarTopLeft = lerp(0f, barWidth, progress); + // The current position of the right pause bar's top right coordinate. + final float secondBarTopRight = lerp(2f * barWidth + barDist, barWidth + barDist, progress); + + // Draw the left pause bar. The left pause bar transforms into the + // top half of the play button triangle by animating the position of the + // rectangle's top left coordinate and expanding its bottom width. + leftPauseBar.moveTo(0f, 0f); + leftPauseBar.lineTo(firstBarTopLeft, -pauseBarHeight); + leftPauseBar.lineTo(barWidth, -pauseBarHeight); + leftPauseBar.lineTo(barWidth, 0f); + leftPauseBar.close(); + + // Draw the right pause bar. The right pause bar transforms into the + // bottom half of the play button triangle by animating the position of the + // rectangle's top right coordinate and expanding its bottom width. + rightPauseBar.moveTo(barWidth + barDist, 0f); + rightPauseBar.lineTo(barWidth + barDist, -pauseBarHeight); + rightPauseBar.lineTo(secondBarTopRight, -pauseBarHeight); + rightPauseBar.lineTo(2 * barWidth + barDist, 0f); + rightPauseBar.close(); + + final int saveCount = canvas.save(); + + // Translate the play button a tiny bit to the right so it looks more centered. + canvas.translate(lerp(0f, pauseBarHeight / 8f, progress), 0f); + + // (1) Pause --> Play: rotate 0 to 90 degrees clockwise. + // (2) Play --> Pause: rotate 90 to 180 degrees clockwise. + final float rotationProgress = isPlay ? 1f - progress : progress; + final float startingRotation = isPlay ? 90f : 0f; + canvas.rotate(lerp(startingRotation, startingRotation + 90f, rotationProgress), width / 2f, height / 2f); + + // Position the pause/play button in the center of the drawable's bounds. + canvas.translate(Math.round(width / 2f - ((2f * barWidth + barDist) / 2f)), Math.round(height / 2f + (pauseBarHeight / 2f))); + + // Draw the two bars that form the animated pause/play button. + canvas.drawPath(leftPauseBar, paint); + canvas.drawPath(rightPauseBar, paint); + + canvas.restoreToCount(saveCount); + } + + @NonNull + private Animator getPausePlayAnimator() { + isPlaySet = !isPlaySet; + final Animator anim = ObjectAnimator.ofFloat(this, PROGRESS, isPlay ? 1f : 0f, isPlay ? 0f : 1f); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + isPlay = !isPlay; + } + }); + return anim; + } + + private float getProgress() { + return progress; + } + + private void setProgress(float progress) { + this.progress = progress; + invalidateSelf(); + } + + @Override + public void setAlpha(int alpha) { + paint.setAlpha(alpha); + invalidateSelf(); + } + + @Override + public void setColorFilter(ColorFilter cf) { + paint.setColorFilter(cf); + invalidateSelf(); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + public void setPlay(boolean animate) { + if (animate) { + if (!isPlaySet) { + togglePlayPause(); + } + } else { + isPlaySet = true; + isPlay = true; + setProgress(1f); + } + } + + public void setPause(boolean animate) { + if (animate) { + if (isPlaySet) { + togglePlayPause(); + } + } else { + isPlaySet = false; + isPlay = false; + setProgress(0f); + } + } + + public void togglePlayPause() { + if (animator != null) { + animator.cancel(); + } + + animator = getPausePlayAnimator(); + animator.setInterpolator(new DecelerateInterpolator()); + animator.setDuration(PLAY_PAUSE_ANIMATION_DURATION); + animator.start(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/RoundCornerFrameLayout.java b/app/src/main/java/code/name/monkey/retromusic/views/RoundCornerFrameLayout.java new file mode 100644 index 00000000..a4654663 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/RoundCornerFrameLayout.java @@ -0,0 +1,70 @@ +package code.name.monkey.retromusic.views; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Path; +import android.graphics.RectF; +import android.graphics.Region; +import android.util.AttributeSet; +import android.widget.FrameLayout; +import code.name.monkey.retromusic.R; + +/** + * Frame layout that has rounded corners (it clips content too). + * + * @author Anton Chekulaev + */ +public class RoundCornerFrameLayout extends FrameLayout { + + private final Path stencilPath = new Path(); + private float cornerRadius = 0; + + public RoundCornerFrameLayout(Context context) { + this(context, null); + } + + public RoundCornerFrameLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public RoundCornerFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + TypedArray attrArray = context + .obtainStyledAttributes(attrs, R.styleable.RoundCornerFrameLayout, 0, 0); + try { + cornerRadius = attrArray.getDimension(R.styleable.RoundCornerFrameLayout_corner_radius, 0f); + } finally { + attrArray.recycle(); + } + } + + /*@Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + // compute the path + stencilPath.reset(); + stencilPath.addRoundRect(0, 0, w, h, cornerRadius, cornerRadius, Path.Direction.CW); + stencilPath.close(); + + } +*/ + @Override + protected void dispatchDraw(Canvas canvas) { + final int count = canvas.save(); + final Path path = new Path(); + final RectF rect = new RectF(0, 0, canvas.getWidth(), canvas.getHeight()); + final float[] arrayRadius = {cornerRadius, cornerRadius, cornerRadius, cornerRadius, + cornerRadius, cornerRadius, cornerRadius, cornerRadius}; + + path.addRoundRect(rect, arrayRadius, Path.Direction.CW); + canvas.clipPath(path, Region.Op.REPLACE); + canvas.clipPath(path); + + super.dispatchDraw(canvas); + + canvas.restoreToCount(count); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/RoundedBottomSheetDialogFragment.java b/app/src/main/java/code/name/monkey/retromusic/views/RoundedBottomSheetDialogFragment.java new file mode 100644 index 00000000..75458e9c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/RoundedBottomSheetDialogFragment.java @@ -0,0 +1,30 @@ +package code.name.monkey.retromusic.views; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.BottomSheetDialog; +import android.support.design.widget.BottomSheetDialogFragment; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * Created by yu on 2016/11/10. + */ +@SuppressLint("RestrictedApi") +public class RoundedBottomSheetDialogFragment extends BottomSheetDialogFragment { + @Override + public int getTheme() { + //noinspection ConstantConditions + return PreferenceUtil.getInstance(getContext()).getGeneralTheme() == R.style.Theme_RetroMusic_Light ? R.style.BottomSheetDialogTheme : R.style.BottomSheetDialogThemeDark; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + //noinspection ConstantConditions + return new BottomSheetDialog(getContext(), getTheme()); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/SansFontCollapsingToolbarLayout.java b/app/src/main/java/code/name/monkey/retromusic/views/SansFontCollapsingToolbarLayout.java new file mode 100644 index 00000000..8c64add3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/SansFontCollapsingToolbarLayout.java @@ -0,0 +1,41 @@ +package code.name.monkey.retromusic.views; + +import android.content.Context; +import android.graphics.Typeface; +import android.support.design.widget.CollapsingToolbarLayout; +import android.util.AttributeSet; + +import code.name.monkey.appthemehelper.util.TypefaceHelper; +import code.name.monkey.retromusic.R; + +/** + * @author Hemanth S (h4h13). + */ + +public class SansFontCollapsingToolbarLayout extends CollapsingToolbarLayout { + public SansFontCollapsingToolbarLayout(Context context) { + super(context); + init(context); + } + + public SansFontCollapsingToolbarLayout(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public SansFontCollapsingToolbarLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + Typeface typefaceBold = TypefaceHelper.get(context, getResources().getString(R.string.sans_bold)); + setExpandedTitleTypeface(typefaceBold); + setCollapsedTitleTypeface(typefaceBold); + + } + + public void setTitle(int i) { + setTitle(getContext().getString(i)); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/VerticalTextView.java b/app/src/main/java/code/name/monkey/retromusic/views/VerticalTextView.java new file mode 100644 index 00000000..023480b9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/VerticalTextView.java @@ -0,0 +1,44 @@ +package code.name.monkey.retromusic.views; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.view.Gravity; + +public class VerticalTextView extends android.support.v7.widget.AppCompatTextView { + final boolean topDown; + + public VerticalTextView(Context context, AttributeSet attrs) { + super(context, attrs); + final int gravity = getGravity(); + if (Gravity.isVertical(gravity) && (gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) { + setGravity((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) | Gravity.TOP); + topDown = false; + } else + topDown = true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(heightMeasureSpec, widthMeasureSpec); + setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); + } + + @Override + protected boolean setFrame(int l, int t, int r, int b) { + return super.setFrame(l, t, l + (b - t), t + (r - l)); + } + + @Override + public void draw(Canvas canvas) { + if (topDown) { + canvas.translate(getHeight(), 0); + canvas.rotate(90); + } else { + canvas.translate(0, getWidth()); + canvas.rotate(-90); + } + canvas.clipRect(0, 0, getWidth(), getHeight(), android.graphics.Region.Op.REPLACE); + super.draw(canvas); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/WidthFitSquareLayout.java b/app/src/main/java/code/name/monkey/retromusic/views/WidthFitSquareLayout.java new file mode 100755 index 00000000..8e0ec1c4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/WidthFitSquareLayout.java @@ -0,0 +1,39 @@ +package code.name.monkey.retromusic.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +public class WidthFitSquareLayout extends FrameLayout { + private boolean forceSquare = true; + + public WidthFitSquareLayout(Context context) { + super(context); + } + + public WidthFitSquareLayout(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + } + + public WidthFitSquareLayout(Context context, AttributeSet attributeSet, int i) { + super(context, attributeSet, i); + } + + @TargetApi(21) + public WidthFitSquareLayout(Context context, AttributeSet attributeSet, int i, int i2) { + super(context, attributeSet, i, i2); + } + + public void forceSquare(boolean z) { + this.forceSquare = z; + requestLayout(); + } + + protected void onMeasure(int i, int i2) { + if (this.forceSquare) { + i2 = i; + } + super.onMeasure(i, i2); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeContentObserver.java b/app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeContentObserver.java new file mode 100644 index 00000000..7938da1d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeContentObserver.java @@ -0,0 +1,46 @@ +package code.name.monkey.retromusic.volume; + +import android.database.ContentObserver; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Handler; +import android.support.annotation.NonNull; + +public class AudioVolumeContentObserver extends ContentObserver { + + private final OnAudioVolumeChangedListener mListener; + private final AudioManager mAudioManager; + private final int mAudioStreamType; + private int mLastVolume; + + AudioVolumeContentObserver(@NonNull Handler handler, @NonNull AudioManager audioManager, + int audioStreamType, + @NonNull OnAudioVolumeChangedListener listener) { + + super(handler); + mAudioManager = audioManager; + mAudioStreamType = audioStreamType; + mListener = listener; + mLastVolume = audioManager.getStreamVolume(mAudioStreamType); + } + + /** + * Depending on the handler this method may be executed on the UI thread + */ + @Override + public void onChange(boolean selfChange, Uri uri) { + if (mAudioManager != null && mListener != null) { + int maxVolume = mAudioManager.getStreamMaxVolume(mAudioStreamType); + int currentVolume = mAudioManager.getStreamVolume(mAudioStreamType); + if (currentVolume != mLastVolume) { + mLastVolume = currentVolume; + mListener.onAudioVolumeChanged(currentVolume, maxVolume); + } + } + } + + @Override + public boolean deliverSelfNotifications() { + return super.deliverSelfNotifications(); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeObserver.java b/app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeObserver.java new file mode 100644 index 00000000..53ff9593 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeObserver.java @@ -0,0 +1,45 @@ +package code.name.monkey.retromusic.volume; + +import android.content.Context; +import android.media.AudioManager; +import android.os.Handler; +import android.support.annotation.NonNull; + +public class AudioVolumeObserver { + + private final Context mContext; + private final AudioManager mAudioManager; + private AudioVolumeContentObserver mAudioVolumeContentObserver; + + public AudioVolumeObserver(@NonNull Context context) { + mContext = context; + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + } + + public void register(int audioStreamType, @NonNull OnAudioVolumeChangedListener listener) { + + Handler handler = new Handler(); + // with this handler AudioVolumeContentObserver#onChange() + // will be executed in the main thread + // To execute in another thread you can use a Looper + // +info: https://stackoverflow.com/a/35261443/904907 + + mAudioVolumeContentObserver = new AudioVolumeContentObserver( + handler, + mAudioManager, + audioStreamType, + listener); + + mContext.getContentResolver().registerContentObserver( + android.provider.Settings.System.CONTENT_URI, + true, + mAudioVolumeContentObserver); + } + + public void unregister() { + if (mAudioVolumeContentObserver != null) { + mContext.getContentResolver().unregisterContentObserver(mAudioVolumeContentObserver); + mAudioVolumeContentObserver = null; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/volume/OnAudioVolumeChangedListener.java b/app/src/main/java/code/name/monkey/retromusic/volume/OnAudioVolumeChangedListener.java new file mode 100644 index 00000000..5c13f34b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/volume/OnAudioVolumeChangedListener.java @@ -0,0 +1,6 @@ +package code.name.monkey.retromusic.volume; + +public interface OnAudioVolumeChangedListener { + + void onAudioVolumeChanged(int currentVolume, int maxVolume); +} \ No newline at end of file diff --git a/app/src/main/res/anim/bounce.xml b/app/src/main/res/anim/bounce.xml new file mode 100644 index 00000000..32cafd2f --- /dev/null +++ b/app/src/main/res/anim/bounce.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/grid_layout_animation_from_bottom.xml b/app/src/main/res/anim/grid_layout_animation_from_bottom.xml new file mode 100644 index 00000000..2ef4ca16 --- /dev/null +++ b/app/src/main/res/anim/grid_layout_animation_from_bottom.xml @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/app/src/main/res/anim/item_animation_fade.xml b/app/src/main/res/anim/item_animation_fade.xml new file mode 100644 index 00000000..29d4c38a --- /dev/null +++ b/app/src/main/res/anim/item_animation_fade.xml @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/anim/item_animation_fall_down.xml b/app/src/main/res/anim/item_animation_fall_down.xml new file mode 100644 index 00000000..a13e21e6 --- /dev/null +++ b/app/src/main/res/anim/item_animation_fall_down.xml @@ -0,0 +1,23 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/item_animation_from_right.xml b/app/src/main/res/anim/item_animation_from_right.xml new file mode 100644 index 00000000..f59e44d0 --- /dev/null +++ b/app/src/main/res/anim/item_animation_from_right.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/item_animation_slide_from_bottom.xml b/app/src/main/res/anim/item_animation_slide_from_bottom.xml new file mode 100644 index 00000000..4fe1e244 --- /dev/null +++ b/app/src/main/res/anim/item_animation_slide_from_bottom.xml @@ -0,0 +1,15 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/layout_animation_fade.xml b/app/src/main/res/anim/layout_animation_fade.xml new file mode 100644 index 00000000..a81df4bb --- /dev/null +++ b/app/src/main/res/anim/layout_animation_fade.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/layout_animation_fall_down.xml b/app/src/main/res/anim/layout_animation_fall_down.xml new file mode 100644 index 00000000..6736b9f7 --- /dev/null +++ b/app/src/main/res/anim/layout_animation_fall_down.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/anim/layout_animation_slide_from_bottom.xml b/app/src/main/res/anim/layout_animation_slide_from_bottom.xml new file mode 100644 index 00000000..59f55f1d --- /dev/null +++ b/app/src/main/res/anim/layout_animation_slide_from_bottom.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/anim/layout_animation_slide_right.xml b/app/src/main/res/anim/layout_animation_slide_right.xml new file mode 100644 index 00000000..9ea2fa97 --- /dev/null +++ b/app/src/main/res/anim/layout_animation_slide_right.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/animator/slide_down.xml b/app/src/main/res/animator/slide_down.xml new file mode 100644 index 00000000..14d15cb5 --- /dev/null +++ b/app/src/main/res/animator/slide_down.xml @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/app/src/main/res/animator/slide_up.xml b/app/src/main/res/animator/slide_up.xml new file mode 100644 index 00000000..bc065bf2 --- /dev/null +++ b/app/src/main/res/animator/slide_up.xml @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/default_album_art.webp b/app/src/main/res/drawable-hdpi/default_album_art.webp new file mode 100644 index 0000000000000000000000000000000000000000..e613740ac2dd63480d8544e92ff5c80fbd3618b1 GIT binary patch literal 1610 zcmWIYbaQiJV_*n(bqWXzuuw1qvM01N%w^QNz;uDhZlcE`pQTF{D=iH5VAvqUnVI*e zX6EYG0VnPX#qCc`Wf8jO@#@9A8QkC2Ms3Zyx;kw5QVP~TbFNgc^loau7V&0_m(R}` zeXmPjUtb@$x9TgDdgZ;UCE~PZg#u%}!&Re{latkaW1*i5p-}+LE#0Sgj2YlNrpNy>R;-XL4H;-T5x6)>UZ|y9-Y?KtS zM2ofmwAxh_XrUd3if9h^mpr4Kjc1HSu^z=Qa~~PkvV5rDF<{M zFRCy2KNKqmR2rr1+2{2g7NkIZjQ{lSZJwZD|Mui2d!$$Zs;mBDVv@0E{k!?@H<0~j z{L$Nd^09k+t5z&+)pGca@HS9Uo$%kgPn^rVu15X{naX}y=%_wQh*#ME-!ezQSe>W4 zNbnfPIqN4Tn~^7jOQwXVu&N z{|?4x#WT<4nN{|sH97NTVdV{P2X)?GCu_n_t8BD-uFA5xKa=TSe7&+l+tZIC1@jM0 zDKPV6c53$jo#S<}P~1d2{h#=4mxh3s;g)-^?l^a}^3L%P@kNavvbhS%{|YT#?6jam zIWe1s%hh=5r1PdducwJ;7JZ�Cl5!#DrMe&6wR(7FOQ$`&{hqgIbHLc-BST zOSq%f>b!6E`B=@uX{$qSO#J0@Wlq`0gSqaf@Bd$8{(6_hHjQN$q%3Zqw11g&@9(eU z8GNGeHOhDbnvG8}?)Ug7UTVR^vc>SnM#sY~DTfXunZI6DApL8%tlyL93X!L`w0`(p zQ)U)r;W&3Sy)rF)ZsT;L^B3=ZeciV(G9Y*FwcQP3mt>DGwcB@epN>kY*RfoaJb_Jn zzN|=%Fi%}m&T2i2;bwo?oZ>U3LUx7xjYq?$C#L^?E>k+`afAFciN?)aU%t3?gy$Hy zWykcEk5>vN*{J^bcQNJDg{4m3Jh#h^ZhI*7G@w(Y_&}kv&h$f5YNQM9Zq+~gnBU@Y p<>fi)!gFe0^OuJ0WRUw=c)RGTCgUU1MJqe~7!=%ZAfgt?0sxT!`5piO literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/default_artist_art.webp b/app/src/main/res/drawable-hdpi/default_artist_art.webp new file mode 100644 index 0000000000000000000000000000000000000000..80da81cba72640254cdac30bde05b0377948fe0e GIT binary patch literal 2092 zcmds0`9ITt9RFAmrD8cNxkIrw=9p?3O+y*Jv2x7H&6EyJ2t|&s4z~`+7jt)v)zs81 z*PMkgH6$s=WGTlK^YvAF)b~I5e&0X69PzHH}ax=qW=vhL~e9nm%EcEbX~OZ|7?iZWAe zEnw5XHrJG7==Ig%o1nz6tcGR@ls0mw3I`V94C@FlX`r+v*R}@UPTDSC)ctp<~QVQx@wR)awncxFBHJC5R|HL#BEtx@>~gs z?2y+E)kr-P~wxfzneLXEK;u8e=p~qmSSh~F_)ZQi!se1vq;l4Mw7U~*8#wxucXL77mp8s=RsfrH zS$tf2--1uKy`BAeK(!1Ml_m2W-txhZ{YVN_^_h94qy9mw$V6!LU*#7f zYH;X-Vsx{R(dUu`fw#M4vVm^rT@tG~j;eKcZ|{H_Vo`OKBLZU6ieHqEg>BRDqqvuq zMa-OHt~H$ z6+CX$vw9vWoI}jjt;KtIXnfw>iz+8_zhMva@~jv54z47{-m~iVFGp4KKd}d6sA?lV zp0eD`!8wmyoICtRYk0OBojN(cw`%psfg-|8fx+V}zkG@ZRtuEBAkKL?xdYVhOfyk^3EB$+e#YSRI^(nDa5y-Tr zC%dn^NKX?0pwO665&x$UwcK8+I&S}jw#n#G7`JEkKHXJ^7RG3}I_|$AYFHtvYG_sO zAy=oF1YQLwv@3rfWmje(wURSP*y0!{54}kGlB%}bDA{eSV(Q3y5IkYbtD&|I0g^9p zgcVncvZH-$om3iPD5zDv%K(C5#Y$ct&=*sJgOi%a z-SiB}?Ttb2yRFpx_oT6T)`_|)*0t&mGCet?_K%nrfhIfA6O?oXg-UGVAn}eN7_$*n?$nYTEPKN*&>2dq9hoOs&d-pRf`uV^q!(jxAdLS zmIUV(xeml!&9N!vk~2AiByIGA;84#C+3O9CT#~h8BACE+30$1wFt2CrRZRq?>75fSpP>gMb&r}XX5AiFts14;Oa3in8O x0~&vp=wFz!dHixI$%+;7AzdU0G%|fLF4YuQh%R5PzDq4{^pETZzourn{u@kb?VA7q literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_notification.png b/app/src/main/res/drawable-hdpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..f151b30a24e8ed3359bafe34100d88ecf6fc070e GIT binary patch literal 352 zcmV-m0iXVfP)oE=&Y<)H#Ms0Oin@t{*ngC+Q6v zXkr>@tqF3tKyyt{iwpFn33}rKl{GLfN^w3Ef3Co6P?dXaJfBz@$6f**6ypXxpe!0+ ycoA%)xa9G|-{=)ILJNg()z*LV*UZ2C<7)>f4hKWDhUUEh0000hii)d3+LzWd6C?EFU!{wA@O+1)CPI`r!)L2ByY0ZmYZU*4C->9w%JQPrKjao zA*+74(8lnooMlkvNr*Kd+jwOJ4m&YF*c-<1mmlGPlz9^Da);w5^ZvQA(W>O-<>h{J zfz%1}?VeB8|9NG=5Rm*?dgkq|Y0~c%;r?hglPgfVAy{>;_0JcTe2)3+yt`6t^fdIaU>`Jb~E>a=;U_w>*)Cm%KO zzFgH(13&ZidMbMDRV&^WytwC}YU8~8VDG%2POrYziEzH!BvjY0xA64KRIa(K-{aQK z_`%ApC1;g+(sae2L&3bywHMWQ&U0Uze(s2f?hW}R0v$CmW_3CTg8PKoopw)ZP&%+s z(%iSW^u#e+-Pmfcy9}oc6y9X`FRFZQrh6*$mM!PaaF<6{k0r^!F7@O6J}s(gMbwMK zfA;FKYJQE}n!xSxS1KTNMddAt`8IOer_6(yT(0oeZR%JsY5x?hn1gN~4y+Lqsx|yC z(Cc(!j@^$y#@FTAQS14A1Z|ri_(ZbVue!sqOwwgf%zr!6BWLtB)wzaL#XSENnxr7i zcW&3)9S+ih3s3xKZ{=#YRIOPRw|JFC;l8%GWctID|g`#q!$WsQqe& LX$_FzWMBXQz{LXK literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/default_artist_art.webp b/app/src/main/res/drawable-mdpi/default_artist_art.webp new file mode 100644 index 0000000000000000000000000000000000000000..f51df8bb9d32db6b39749f75b8b0c5f7b0333f07 GIT binary patch literal 1444 zcmWIYbaR`-%D@or>J$(bV4*Mp$Sz1^n9Hao!z9CGH_>CZkLproC8fzb3^oXHX6F5= znOXQc;PBo5r^_13%(Wj(-c&~(wygq@esJ`;*p)GG2>LP8wYBI~F2&H&5Pc}Nvcv3?Q8a@e! z&S^9#x_tKSo7iw8IJbOHL-V(rVvT=~)EI<(Iqv`ovt_Xi5j$G#XMeixS#pjq{i+cx zVAnXzcR3livteH2iV3-QPb}NKu`lg5gDyCL%MN>QuX6pz#XdnFXel*mzzV!nI5IHnX5^(h~i zj9$2G(wy*C?5;Pb&cgmS?8QMs?=DrJ0@dGYV8N_^M2F&izUDNtugpevNz?$^Z2OS z8#XyBY?)=~QRUKLBiOhkp>Tq+xbhvK%-223Qr6aQiimo6t4=F3?{`k=rwix5hdkz) z_>xh5X zSHz=7*S>GEs*6zhy!Gvp8E4C@pW7Ut?P8v~sN(kfMFAeUdS70K%U|~rXt~5UEn?b+ zwcETeImL&t%KSXAbi=bb3DLV<`fT4gc=DQW@G1}R5Oyn?w1Qgr~wwsoynKet8Q-Ew|YzG$7x$#cxFPG$($ zJ~Omb2nugH6xSksZRPdenSnY|8+q2R{-3beP(fhnD%G7APJ26)p4>ROQkhpj%-7rE z>wCH6ghldCzw>2%{CA_wO+?1RS8IXZq4>RXRwVOvmxr34UBUlCN!rr&ux9T|-PSpq zuRfhOH|M%$?{WjvA3GL!ip$J;)1qpBT-~BMUb#bDsUq~*D(8o$7j)h_&qzF(aN+gN z{}b=&&njNLByIiuqwSAoIsBJdV0ZoDj(t9PHr^jN=FZVO>+$Jab;gs%H=Fg^tFQ9p zUaiV0+v~XRvG00!0j1VcX(rL1UWzu`f2}*-VXu5KvF&S^%_OyH${aJZGeX~=fTlDM F1pvP6)_ec} literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_notification.png b/app/src/main/res/drawable-mdpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..611a6484480c50a471d77c2b1638451b5e0d1b0c GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj+dW+zLn>}1CrIQx`2YWZn?ns# z$Nzur4f_N3DQ?xV_$O~|;it>}@4|1pXu$BeiZZdcHBhewx@KH)3Y|%E>gT+cFcF^n<;=a*Xp~-hxpJAhlsgb0%z;lL= ox*13RadfCNY`m}_tCfL)X`|JPf~x!opcfcCUHx3vIVCg!0FQK9#{d8T literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-v21/notification_selector.xml b/app/src/main/res/drawable-v21/notification_selector.xml new file mode 100644 index 00000000..83aed83c --- /dev/null +++ b/app/src/main/res/drawable-v21/notification_selector.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/rect_selector.xml b/app/src/main/res/drawable-v21/rect_selector.xml new file mode 100644 index 00000000..08954384 --- /dev/null +++ b/app/src/main/res/drawable-v21/rect_selector.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/rect_selector_dark.xml b/app/src/main/res/drawable-v21/rect_selector_dark.xml new file mode 100644 index 00000000..f76d5d15 --- /dev/null +++ b/app/src/main/res/drawable-v21/rect_selector_dark.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/rect_selector_strong.xml b/app/src/main/res/drawable-v21/rect_selector_strong.xml new file mode 100644 index 00000000..cd085cf4 --- /dev/null +++ b/app/src/main/res/drawable-v21/rect_selector_strong.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/rect_selector_strong_dark.xml b/app/src/main/res/drawable-v21/rect_selector_strong_dark.xml new file mode 100644 index 00000000..fdeae459 --- /dev/null +++ b/app/src/main/res/drawable-v21/rect_selector_strong_dark.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/round_selector.xml b/app/src/main/res/drawable-v21/round_selector.xml new file mode 100644 index 00000000..09c5b530 --- /dev/null +++ b/app/src/main/res/drawable-v21/round_selector.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/round_selector_dark.xml b/app/src/main/res/drawable-v21/round_selector_dark.xml new file mode 100644 index 00000000..0619a3df --- /dev/null +++ b/app/src/main/res/drawable-v21/round_selector_dark.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/round_selector_mask.xml b/app/src/main/res/drawable-v21/round_selector_mask.xml new file mode 100644 index 00000000..a6f3dfaa --- /dev/null +++ b/app/src/main/res/drawable-v21/round_selector_mask.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/widget_selector.xml b/app/src/main/res/drawable-v21/widget_selector.xml new file mode 100644 index 00000000..f0360419 --- /dev/null +++ b/app/src/main/res/drawable-v21/widget_selector.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/widget_selector_light.xml b/app/src/main/res/drawable-v21/widget_selector_light.xml new file mode 100644 index 00000000..86c53d73 --- /dev/null +++ b/app/src/main/res/drawable-v21/widget_selector_light.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_background.xml b/app/src/main/res/drawable-v24/ic_launcher_background.xml new file mode 100644 index 00000000..077dc79b --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_background.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable-xhdpi/default_album_art.webp b/app/src/main/res/drawable-xhdpi/default_album_art.webp new file mode 100644 index 0000000000000000000000000000000000000000..d2c2aab3d7e87986ea0215815f44168aceb97bbe GIT binary patch literal 3094 zcmWIYbaUh5VPFV%bqWXzuuxzEvM0zh&SliHV6kAao9MCFXX%o~ixyn9;MgFB6M<{N|cMu}asU)*Z9IK}vG*)Ow&=ZqSvSMKXwQQWgY z?p6NcESbj|?4t^XemJzV9cX|4Ui|3Cu!%F4FzD+r-}U{H>pUlw;d^kcbii{-2iq(6 z-L69*X7p zcFSzx8D_2aUAoCw6I4dAy$&$_%~-Wr&h7EXZORzVIu^iRs+;`^m?o>H|8_AnVKTqC zm9KCLnkN{pUzK#Q`B-gmpmyPE>za zCl`-B2`hUu?C%$y14_?ZahRAp^DbM5DUZ%q^NU+HAe!TS>ozW&Y9sz+&K-v!M2! zV9VJIZrG}X11n`?K6-vnU%9W&@ebco#>Sf|(>7wskCOHm!m_;jtST~J<ut}03KB;z%=1r1NDH?>Cy@ zWsh#witgUFP?LdOa9U5!l%h-jwp%S(&Y*Dg}cqMrue8#dlSB`~0 zPbpm|cZ7BEf(gv89rk?>WnfU@6E!>RDtB06-aAhDV&(?61G0*$k3s?%luegy*)oBl zN|OKC&y>XJDb}Zr1CCzod|I<`lE<@t2j;JB`ClBE_fMRcK6#paRy=1(>6WNOmUpHq zM_Ucc9!u!HVX#OnKKSJ8Cc~)w^6<3n=Z>b{e0YF`FQw!OgUhpA{~HDe3`^g;=<=3TH122)o?>0& z?au5LE!@y~XaW=Oi%%bp)QY%%VVxs=m@8buX@Rt>X72AdYfGP+x@5RbUn#X^#rN;# z$rt9cW!wzt-^(DbS-|m!sqS^*?Aae@O`HCLW$)=uhUSm!jCRIcC|3c7WRG4m&xE^= zo_mVw*mi_)n}}^%GD~a8%<^`(Q{gtV?}}}Z^|-&0_t%^5kY&cpCJFj*ukP`x%KX29 z-B)|{_Io8Jj6BMQvuA#1i4oRsvHrg~-E+G1{Zw)PS9)>p9vLQhJbtj}vRdr#Bg>Ym ypL!nqJz$pZqpwL#JgwUUqD((9YBV!n;ZBV^Z}aL{oxsQH6%0(m7tkUXl?wo_2dS_C literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/default_artist_art.webp b/app/src/main/res/drawable-xhdpi/default_artist_art.webp new file mode 100644 index 0000000000000000000000000000000000000000..3d4cd6425be033cab626652ad11e8eb4f39f2d0c GIT binary patch literal 4148 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 ReIx(?002ovPDHLkV1k!*#<>6h literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/default_album_art.webp b/app/src/main/res/drawable-xxhdpi/default_album_art.webp new file mode 100644 index 0000000000000000000000000000000000000000..059faa03464077669044354138fd0c81918436f9 GIT binary patch literal 5064 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/default_artist_art.webp b/app/src/main/res/drawable-xxhdpi/default_artist_art.webp new file mode 100644 index 0000000000000000000000000000000000000000..cbdfae6d0be062861845d372993acf93b6ad3b22 GIT binary patch literal 6310 zcmeHKcTiJXw@(6uqVyt2ln{ECA{}WLP+9<`N)e<;lSuKRg7hLt7ep}hdchzdMWh5m zM-fCR5-AY`LNOFkQQ)H}-Y4jrZ{B}z%w%R~l5@^p>(|zf!5MY+G-d$6SWQLGNKYCX zzxA1h34{dlXOLu&oQgZ0shyk4k(DVvNcND9-0|{PpL=7s1hZ?q?TDKGZa{8kt=Rd? z9e!{BJi7A=i=x$px7&Js<*k{9H9{C@BuV?8m~BS__n+kt1byt&9qA_|29+$q;efFj{(e0b;xXYUfVG$yo7w=O-ZmzA{9WnzJSpKvkD8t-YDzOU(#cpGfaO4L+aRkabdjD?j8s& zQ}?CfUtYTfr#E?4O@&g|j!)a7ABj@ZLV_$n-M<3bxcE?Z?e zy(-$SZr@_~Dz{WUu93fVWb{*eacPQ`2pCdzYov4q|P%| zHMhE+Hd;Qsdc*grjFt6wQ2u2>w=npte%&gyot8`w^N1S-2p_uJ<3$A#gF}MMH%}HF zAkx$i$Afvx%)3puSvU@+^kzYH<+wWa*(GpmiMK%q6ua(yLGG7Q-c$eC^tf0+H~+Tq zVmZ9)Nd4U1w>xutCi=JRqXDC7#ZTLA~mxwPv-CB7ljzvuI(sl-Gm~U144?rsRjg;q z1Q8ko9PxtNr>^*RQ)dxASk6}H>3ou%O_MoDx+(09VN}vueoHnlcP&H3O0bZ`_-R z$%}Vto-W3Bm3DdiZf(T6UmQgx&dAKEf6bmz_0}U7T}W~)C~psa_-^*S%6E*5Dn0>e z`EkZdGD9c|(X^LV6>QH_DzblE7FNG;^Zn#7J^ODk%R>32d}$P3!&C;8%JbGtF8w@= zsh7Mbj((3~S+^n{b3ElICdEL&Ho_1j##v_@wST!X^lRS{k3Fc09zZ9QpSd2j;>=iI zYYE;WL$YBo@T%ZR<3c8IYj70cg_uLmaLgY!&!Kc!rQ zL<<(bmti`Rh1H=xGxfA()KHJbGx@zV0)&B)P-VOSQQ}s?+Zp|XuT)&hVr4uQU&GDS zNkm=evjorS01+116$S@!%z1T@r$^G=cJzU=$|iWyfdU}H0BND1fz_^)0>-qyj_ErU`g zky>r#S=LUJp!-LdCG^ur+p_vm?qa3t2}(eI&VMMwdXj92dB+L-Ls7gOpV=Y=R3BDW zM>P7lEbvhTJzaG~+mh)*F9}@qi_TEMSl>!zN8R;HHG1HBKU!1?tTZBFpVC4QHNz%p z6*xq424|w#GJTls?NR@U0gzqu3suUEt`hQ^y2l z)5d%aXF7_+RjYM3(@HQ~CItF}UEd7%t+8n}J9@am0akORhNBNDPgD&8j&SA*dYx|W zui@>5N5|YJh2fr^XSNFH(<4Tp>DJ9_hpq~`|CM1O;7ijjFtX`!8w-)|^#qX0&rmx! zEjwnzHwsde165k<$gQ5=0|^adk$I5+VRj>4JPkHaj?|%?6@x z0vyfojOwY3uyQ=|^^!lvNR8?pf0{--RG-?P#K&qCBaNNI6)<>PD>xRlyyJFZMVc*g zQ=tM3)g7>z)F{pz>xJQKr$s~R z7ccZX5igW6yhT5KcxO;EKVSB}j<_v+GX`*r!;TBUVm}~_L)czvFzgfK>`2h!iEuR# zQ5G&uuZTPrBAc~Bf{2X?Af?-6wSU{3rebPqwQNnHZL4w?S=Zn)V=PE!&I`Z$n#p%H z8HLNcTf#;^Y5&o<_>^X7>>G_|)^-a5*qg6#fZW81uv2MmB2*k;?uV$2zhXX1_PkaH z5ZkSLHZ9lJ4e6wEe#LQWfPzl|K<54ck{Jkq(s~Sdjh%nQtdyu$1O?MC+-NlYa7)iZ zhn7>atKL~MJ-oN%%(*vqzTx`pY=LM}Ttv_GgCfXNh4qHp!JdP?8*wfQQ-_SHxSVw_ zO7l@&WFC?zPtkMbGMTvw<+O`!RCjc&Z^~8i04|*GEhU?s8Q0IP#s*kvdPzOL$#zXH z3kjVHfs-$g7`xt?ijsA)nrUgQcRJSKj6l$%ys1JodBR0h%n~GlIv)*s3RjA6%2+J= zIf8k;ln$Fk86z5aESL&A33i!hZUe>$j{$$F6&o*#vy>7O<2`AA0SzL?obQT#X=<$W zfN;i2=X848_f1m7VRWZXmC`T?o3X6lg*>4X5#yStNML{q)RN`$Iv6^v5=1G&l0=t6 zl7+@a_}|Zyc3Cb|Jb|cYVlxf8B_Bg5Z}vrU>rAY6>6&8{%doj1h=WJelUMn&R3C6M zG&lV`-!tn++EUndQYd3Fo2;;FBdZtF%gUX&7t(Qw%bmIb=jg*#kmoGen^BOF?zihM z3$0=kS7rOmVYbV)pOZI3gi@!#Co6}do(%faaXjJ9=1WGOJ3qjN)MPI7DAgA->Xe8V zajfdyku}eJZ09UDc4u;U0YyOK+O3KKeoesRs=3y zGZ>1_7$78opFhDF&1%@3ZF0i%C{tsYCoPZDim5G`f~?azlj5Q_AYG%am^S;cJy?!jL_h1&d;iNn>S~nRNBG*UT=WO$8<*7(XM4K7Q z3z&AE=>iWJI`A+<)jIywne^*SqZVoO;~E~6_QM;(de3qqExAMcd1J&p=sF=milGFI z@Fm!@lNv9>LbP}eYcnV_M4XedU!C+Q@_WNJ)Hy1*L~eTfR>y57aS@MaGEQfJe&4amVCL=f->Zot4-#MeaVQa4}E;<%z0*24{7HiewD zzfny5?%wSWFC@5fh?i^Pzd9oh4P{gf%rb|=C@L;Qj8+KxdjNm|#v704EPzdWWlA0!DZI0f31Zd z2+eSJ4F1e)!?1eq-K;ZDngW*WVLyMsas%I$tCJSEKM3Po*PK_tW72FH_x{Og)$>*Y ztbzDZKq>odR__CB7nr`i*tBDBg8B`PX@B=Jtx;on=X+W^ z;?)~6|7zpLw3zSTVORgtWmgXdHh+^ zNn3iXO6TMpOHN_dy}@+ub$^cPPp)+tzbhS&Reup$;27;>w3zK+bS|%G=m~=zY<&$| j6ZY-?yOig!&vegMK{K1nPFyMnCT9juS3j3^P6yOAzDX``J&uZ`l0d4DI<7`)GLA zK$kBuaQw3XTC1Yt&Nio6f>1hNgh=j=0Okg)EB3L4S4pd1Bq2IC(V^s26ds{!d6`{g zPhd#oUVq|~-hqW4C5i@a*LA7iyaJk0kow&mW9Mm7RKOY}8ye3l zjBBb8n&)Nc_a0Tf(AbzY{zCBj`NbAA?m*>0Bz&fe-H4yM@yRd7;N@SC?D2}b)!>ae zOWf@WAWRyzJvc^{oj0Z>vd&8_H|AG79tXT<_9}KXEQ7{hZNH63rTW~|_@mHUeG1+X z$t^bNLa-!?xaC`D$#3^cDck&-41AnzJc0ItW|EiL%1Jiqgt}J!fuU=K$g~e1CZO4* zaef=Pgpz#Q@J z>>lW)8KpTJ<`~J3KE^SU|11J>jO4#E`Y#%Z+Li~~c}65Muh-*Jh0G1RF{VUJ{CjR0 zx;CkwunPAFkM@Np2YxBy{R=+i=h{^euGNA=>hLz3qaRn_Vx1NAG!yKR3Fz~K8q(Vc zfMA%lb^WZ8{#@ZWtVYEk?Xf7--YB7ou;Du%Q=tpR=NEbq(}baeC`ko{TqoE~@FwNu$Q^q)Hk!?Fen{E>8q)K*&*8*ao*w!xUS+Rl574()$$j^=pVq7fQGDX@UW*CO`;kMtr1*&*+xVrE3kvPjxxdzY z=%X9V7XoTgHBB)^8W3bRj|jscX85A&M#%>BuJ+O;TOeq7iuyT9_bgk!u~X1J;K$_6 zoH|`iXi&Kk>4EaKN9%qO>u4|7wEiL#G9I5dvV#Tjfuh zIA5>Hgrqd0SQoi~kUoRE^SWi}KLBjF_&)qYP&4i}H1$&{R$vN&axj>8XH!%Vaa%xH zwS+^Er#Ga91@%H$e3QHAg7ETA7%4EKzf#I$Bi~wiAI&q_%aaZh!Rr*zELM ztafbUVp3YNnJXUe(e~Mq+nwbk{L|k0KV|9{QAW^83co;$Ichj(hX7~S#3Dvsda{I& z$~fCm7FZIrTK;dW)ck-hIXjLP&=u4I@^=oyu@lbrHV(-7Eq5?hQh+bB&4%Ux!2K5Z zeGk|(e4Ca0Xow~AuLsrwR);38o0r9ypWh&`Mg2odUW?|vUR=d1eW5@K063yMiJM*S zin!~wTzn-PsCGAv+u(Jfn|hgX)l+qPKuE|4m#g>AXH+SD!NzEJn|q`Y@aM(drSNs) z-bdx*QerQR#_*YQ$0ssNhHLt*;ssBh0RTh-a_{PYs)|->ybGK{nP8A|E8SxDMH2%= zn4$e~(N_Qf*-Nmz|Mb9q*%f$xVfR=ca)Ss|F>i zn$`FbBBi1Zzej*mUW(!88^noZQ|vb(@GFZ>7hG1D*`VC@mWg=vQpMzn={p5!y!+@ zPRzhd4O?-Z%s2A4u>b(`-{O>`BN-j&QTZuuyHLLPr?6^zn?e zJo>Hj%b!vzn!QEuZpX3?z|GP&*otj){3Dt)(`6DXeR>@14~`vQO}4(!ZWEO{1z!Fi z4&mH3=@{L??xwX)N#iAnIh({(D(FSmldrWkC)Dk-7N)qf*C0lUBa(tWmQ(O@v+G-F z188Z*BZR}O;OFJ_K)qg@;tJk10dLx#`3)gma7LQ@OBCv*@ojsYC;%W=daW-D2xFYu zB&I3%Ub|9}VKy3q$w4g-ed&{w=cGHSoAY9oyy8%A!>nsipuWqo%4z_>be_4%mL2o& zVw_2rHLF-lI_yX%vW$;fY{gB-iG!;Gq}viBkJ#gc%kKJCAz#>*dMdGqCf=o_0Olz(g=IPOGU%fh`jKlzla| z=e)KWSZRZoyiHoWG8@)yox9WAz@K7p7g@dLuqx>u*udrJ!UPB|=<iJLAEJ;iCG< zRS&z6(F${;qV#@bJBBNUwCqm>zr%h$*fOdXt1veNcoKLU0NiY%+8Ej3rK|8gaYG?5 z22z!FD?n)ZK3OAE01#IGJ3RSvh?s2Y`xTSn`qV@L$DpaBc^J-Ri(kDkImlVk7O$PED8v7tmiIh3!YUXClBaDUBYHe}Qc}{TPlp-q&5- zW98u=XM;bdwG9AJ?!u@q9lmvm*WelhWyu=%WCT~J(-ZuIz}M)yj>JdIZZh(G&oXjD z#zsM7o>cI!Z)d1%u2YOYLHg|VIMhZT( zdD7!xzalfgv$J!!A&QLn=)Cu}DHZG_&BEe5gK0b0KDq;&tPv^8ZtO~& z8g#c<7v~!CHX`OzFFwIcAiwltn$#XlgtGK(DENYJ^ZCh{1BVbwus|*QYu+0~+j=ck zMe1BnyG~?HUf3Sgl$Bmc=UeCWEO)?g(0!8OfTzBD<&BbdIf{(i{{iek#L}er z)^TT(rhQ5be*3(g<+ifMsY7=j-$<}daUAeW+j_XjovkkSjt`O4Y(G}te6_Q<)KS9{%h_@5J!!>HC63*x~8=)Y58T0v3UGSfBb8fS|$E6a4&N{GE^^aDS|BUKYO k5vE#Bqbv(IeJ*}=oTas!3AW4PW|g0hY8@N_&wuOV-~Ohe@Bjb+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/default_artist_art.webp b/app/src/main/res/drawable-xxxhdpi/default_artist_art.webp new file mode 100644 index 0000000000000000000000000000000000000000..2eab1f63082cbf300d8a354346f6a4a32b6f723e GIT binary patch literal 14792 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 C%XA_D literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/np_blur_card.webp b/app/src/main/res/drawable-xxxhdpi/np_blur_card.webp new file mode 100644 index 0000000000000000000000000000000000000000..876064dfbf55184f4aae75a200d80170c9366151 GIT binary patch literal 4236 zcmWIYbaQJFU|*83>$g zpX0bS>*}hFoR<_&xryaB)PCUK$N2q#-4FKr48I@9*D${)R;aW%yXA#!UiS6%ajSIf zmtgmB<-BKmtG>QkRlaetTd$N!#zj_t5)7ShQ;HH-RjynKzeMFg*~M=gMp6gcA9~~U9fwB7Ly^m{2E6x~@1{VvhX(J(n&Nu? z-h7ZcS42}Ixi$U4N^BT6S1}rmn%T{*?C|G!#jAnJz96y@XSB++M^rCJw ztB=;|Xw8|?T79%uhqWV+>exY1tE)daw?g$nNM`|k;OT4J%c3{_j|Mg>zemdld{A2jH&bL*OgH{KOEQ&RDO6W5O=_NNo?#DBdgBqFBPJgp8POS4uA7?Q`LEn*kAVw zc*Otd?!0~Q$TUS$Y~~FbG54+p_C*!1CNMAl`uKwDex9RDOEef5RBxCw9JCRL$U1&c J(d7xcV*w}4q}Bic literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/np_card.webp b/app/src/main/res/drawable-xxxhdpi/np_card.webp new file mode 100644 index 0000000000000000000000000000000000000000..a55044c5419fb5c66d115a85f2e299ba53dd026e GIT binary patch literal 4886 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 E07asajQ{`u literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/np_full.webp b/app/src/main/res/drawable-xxxhdpi/np_full.webp new file mode 100644 index 0000000000000000000000000000000000000000..96f66d300acc91037af9863a575777591ad8bb26 GIT binary patch literal 5502 zcmeHKc|4R`10Gb?27?k}j3vZG8bc`~!q}w@W1C^fjN4+3WSLMR%-CDZRl1Z!$r_Di zxN#-M)(lauv5ajjg^{buf79FFU9E(Sod6Pw>hLAw_~6TIcrFY<@iw;)SAN^3NRh zoKIaeJ}1sA_`E@aS`(0)v&@8Rw9h`ojXVP^lDzv-G| zL}9-%x5JsA%6M;CPR|z6Ri!~<*Cz(Qc)H@hiTJN7CA^X2gf zGPXPT^!%pI{F3GJSp6U3=}R2uoEAstmBN%4}I9RoqXH0)6zHx_Y6_whH+G8iIl@u+9;2Au}H z)neX{ekkcnNsW%{j%r<(3Ecu(maaQqX?LX*9YDyBY0BuOIF00}bavSTd0hJ4KFU7J zIqBqb-jMeLCNtjK16KY*2XW+pDrwHds=-IDc;mLQNa*&^qdQ2|xS6&Xy0XJ8r}nDQ z6~JSGi)~|ue6yG9&h8Mjetu{A?!(EPqdpI8Z#c}4m$CNdGd;DltiDPu{BuQ)XO^Y&k_=fVmo@y>{R_FqAgEe?K zFw+wer0ah#KX|gly7jcqf+(l}1A(L`W7X4BjE5ceXJ=dm<#x`cF$AmVd>Lqx(8X0- zkJya?&puX8-5$RZ%otGbj9pEQ_9O3gIjs_&aaGCX7PavkUAM0r58-R8{3LqK+o29` zhZi5?Qi?h|WD){uvwkAv2kCfyNaPi$YCI-el3FkhtMr8VH^Emm^!9)yg5Vm^;f!SI-&E+0eQBH?&4{iE*>j@~l3tZ$sirfA z7f*k#I8>_i0D%(-E_+ICiBexLh<*7fj zS@^yOQ*F&r)n3xlX>ioEJvn`P#nf*KbQ!ibJqwri@ui%oN3{-}s9!TD?NnT)uIFvz z7ws|b4&bFvm$VM*5*LQO&Fq3oC(H~gdUeA=hNpaA*@WKg?Q(^53+rk(@F5SzwnL!@ zBA2gt@mikm7rwV`bhRv@@$SVIPz(YvFz{5Vvv|n@6iG`@_Y9mA2mrGRKbs%JiK>N= zqQvSqV0OFJUYq|k7JKx(;&wu`4MTK%7?P%8i*?0xy3O3^|))|g|JDM4L#dw)bEkPVSJpuI$wuu%qQ}5IaP$HQ8+t9DtvK9p+7cu-w#Wnv@^ajgkj-B zSj~KF&OM+heBzw=`m#Hg(FNhyIjg3MRj`QnW2e~iB?4ZGdpkoYA^vFFd`X8a03cN4 zH82pfdq1ZRQ|W)-MXM$z!W=%I)*?YT?)Eg){z;6PN1VKylTG-;@{B@mO&x7WKC;vV zs2}n?aaZ(oWze1+Q7yc%tL;dpLJ;SXBdtb>mZ`)F0LYy*^S zkT9Ev8f~KdUN)7ln6DR#sfgU2P0NI{rB#R>=;X6ktQIr-pur>twZHnpW4q^9lcv}j zj6kn^Q*M@oWQAgKX-oa3rbD}vJPuz))HiGYJlKGabj>^YR)t-8-glx7^qOd70hgtF zE|sFgAQC)=2Wdyjxv8)VcCfMgm_k`--B5PshRj=cpq*cx?S)he6RJU=sDVQOE*a@E zqVALtN8V9D!Xd3ZQG2C+bo7O|u;$}b&6l_kl$h-rS`+*+kbAsBA-PHUO23#60&-q_ kA#wBjLG&;P95n+Vmb$I6>}EzSORhHB17s<~4G93i?>|je-v9sr literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/np_holiday.webp b/app/src/main/res/drawable-xxxhdpi/np_holiday.webp new file mode 100644 index 0000000000000000000000000000000000000000..697a9cb8132637610d6d25ad9ff7a4ecbb935269 GIT binary patch literal 16800 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 L-1!KjUH||9`#^L` literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/np_normal.webp b/app/src/main/res/drawable-xxxhdpi/np_normal.webp new file mode 100644 index 0000000000000000000000000000000000000000..e943b35cd1256f9a5c7a847a09e0955ca8107b3d GIT binary patch literal 5214 zcmeHJX;72r7XA`KAcA3!h)~5K1X&`HO)3{;kxf~JYM_81`(mPiMIi)a6H$U9vdEAc zG=S2u!~y~mSxQ@k3Pc!@KuReDLIDv8VM%V=nfphR+qt*X{weQ|_x20pZ0lM@SVZiPmnIa1 zdAJC{o)l2k2-}Pi?8l3Bo_RExJb3$s)cpCHcCwtc9B0e=6QagJVI$v}bQi_Rs@L!i zPWa&pcyo4$>RM(I_jf;wM{^X{^k{LU#(bLq$@qm^h-H)u`>VD=n{j(slFGOYpGFxWOUG7Z)#>} zcfHtB2ZqaOglO?t;Efy4{a1r{DtDq(S1g(u5$n9^@5SQmfF-o?|Nrc^gNte6ZP>+h zu7-f_FH_gFK-4}66&3C` ztT;cNXIrft>s;4*zG#Rzb-1F6WH>DbN6OWe%H0LG@nv3lOw_kmdehMB)d=-?yBlIs zpt|0i^Ylf}g=C}Vw(LI}8jCz2rY6yliK>3v@=p-u<38VZ_E+kMIsgcSP4YzGw+Imx)4j)XPdwdzUxi}CS-Lp{K zu=i=`3&L!v(Z<7w=Hj?UTL-~#WjBoUyU$-Q9RN<;!I0ueRzQrwb6^aJ0NM}q07b+o zz=LSP&HI=hJwz6lz>*?CJ<=tWQ`$ev-c2{8FKP6fV8S)E93+ioSsRPfS{@XO$5wMpSob# zE%~ma#1R@W~N{9uhy}Pu+UPlVSLi$OCejC#k5}^#f zT7S%u8>OWCjGK;SG{`?=S=Qw#M-s>Pyp<&RD#@Nh+>u%YDwCcHRyefyo<3;;Z1YoL z1hNHA8I^@3u5*kd5())5^ z)_pvFwC=Xrn3BUKK1!uz&4Rkxqs@8@vozUqy>4*ld`eUP zI8Lqcn*Ltion(J{go{Eam7g^Ib;alp`+r{1*9=Oq16h)*GuB>dV#o^A*a1$-z?F#$ zg6m2F!D%zTT0^uJ_G#pC zrA(G1ykGazqArr|-YA8&*i?%`S zRv4`1Ws24uRPUOr886qD0}AYGBjy<5v|2hc(0C)E5dfH~Gy?RW9;CvQfYrM~j^z!rptcO+oz%FS!osUi3JS4Nu|4t<6?Z!Mjb$ijB- zdD>yP>a?HJg`jT=PiL9xR4Oii*DPpyu2AbIwE)MMeLm{aD}O%+j&c>=Zq{JQT{6QK z`pawj1uafZ3{A*cMRU8$dErrkxBR}qEeFRKbEq-7PGhPmN9^JqnSeWZo>oWr8m&v9 ob@nOS=IML06swFJrGGZE;v5MPU<5Hwu)S4FJ=P*vCjQsI0X$vhy8r+H literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/np_plain.webp b/app/src/main/res/drawable-xxxhdpi/np_plain.webp new file mode 100644 index 0000000000000000000000000000000000000000..711c56b477f940c6a23788dbfcb11ee63016a9e8 GIT binary patch literal 5188 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 + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/abs_last_added_playlist.xml b/app/src/main/res/drawable/abs_last_added_playlist.xml new file mode 100644 index 00000000..00f45bc1 --- /dev/null +++ b/app/src/main/res/drawable/abs_last_added_playlist.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/abs_shuffle.xml b/app/src/main/res/drawable/abs_shuffle.xml new file mode 100644 index 00000000..ddd4e70a --- /dev/null +++ b/app/src/main/res/drawable/abs_shuffle.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/abs_timer.xml b/app/src/main/res/drawable/abs_timer.xml new file mode 100644 index 00000000..9bd6f56d --- /dev/null +++ b/app/src/main/res/drawable/abs_timer.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/abs_top_tracks_playlist.xml b/app/src/main/res/drawable/abs_top_tracks_playlist.xml new file mode 100644 index 00000000..045a506d --- /dev/null +++ b/app/src/main/res/drawable/abs_top_tracks_playlist.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_image.xml b/app/src/main/res/drawable/background_image.xml new file mode 100644 index 00000000..34810f56 --- /dev/null +++ b/app/src/main/res/drawable/background_image.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_bottom_sheet_dialog_fragment.xml b/app/src/main/res/drawable/bg_bottom_sheet_dialog_fragment.xml new file mode 100644 index 00000000..fbe53f28 --- /dev/null +++ b/app/src/main/res/drawable/bg_bottom_sheet_dialog_fragment.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/black_overlay.xml b/app/src/main/res/drawable/black_overlay.xml new file mode 100644 index 00000000..46e84cfe --- /dev/null +++ b/app/src/main/res/drawable/black_overlay.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/card.xml b/app/src/main/res/drawable/card.xml new file mode 100644 index 00000000..ace882f3 --- /dev/null +++ b/app/src/main/res/drawable/card.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/circler_corners.xml b/app/src/main/res/drawable/circler_corners.xml new file mode 100644 index 00000000..74954d1a --- /dev/null +++ b/app/src/main/res/drawable/circler_corners.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/color_circle_gradient.xml b/app/src/main/res/drawable/color_circle_gradient.xml new file mode 100644 index 00000000..119aa97f --- /dev/null +++ b/app/src/main/res/drawable/color_circle_gradient.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/color_gradient.xml b/app/src/main/res/drawable/color_gradient.xml new file mode 100755 index 00000000..fe3a193c --- /dev/null +++ b/app/src/main/res/drawable/color_gradient.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/color_progress_seek.xml b/app/src/main/res/drawable/color_progress_seek.xml new file mode 100755 index 00000000..8091c388 --- /dev/null +++ b/app/src/main/res/drawable/color_progress_seek.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient.xml b/app/src/main/res/drawable/gradient.xml new file mode 100644 index 00000000..dd54e4c6 --- /dev/null +++ b/app/src/main/res/drawable/gradient.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_1.xml b/app/src/main/res/drawable/gradient_1.xml new file mode 100644 index 00000000..056d7bfd --- /dev/null +++ b/app/src/main/res/drawable/gradient_1.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_2.xml b/app/src/main/res/drawable/gradient_2.xml new file mode 100644 index 00000000..d19895a2 --- /dev/null +++ b/app/src/main/res/drawable/gradient_2.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_3.xml b/app/src/main/res/drawable/gradient_3.xml new file mode 100644 index 00000000..25b845f8 --- /dev/null +++ b/app/src/main/res/drawable/gradient_3.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_4.xml b/app/src/main/res/drawable/gradient_4.xml new file mode 100644 index 00000000..beebb803 --- /dev/null +++ b/app/src/main/res/drawable/gradient_4.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_5.xml b/app/src/main/res/drawable/gradient_5.xml new file mode 100644 index 00000000..cf540a29 --- /dev/null +++ b/app/src/main/res/drawable/gradient_5.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_6.xml b/app/src/main/res/drawable/gradient_6.xml new file mode 100644 index 00000000..a48fbb39 --- /dev/null +++ b/app/src/main/res/drawable/gradient_6.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_7.xml b/app/src/main/res/drawable/gradient_7.xml new file mode 100644 index 00000000..975e235c --- /dev/null +++ b/app/src/main/res/drawable/gradient_7.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_8.xml b/app/src/main/res/drawable/gradient_8.xml new file mode 100644 index 00000000..bb56a690 --- /dev/null +++ b/app/src/main/res/drawable/gradient_8.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/hemanth_s.webp b/app/src/main/res/drawable/hemanth_s.webp new file mode 100644 index 0000000000000000000000000000000000000000..7348b33f22c9b0ffd46b1d828106cb0b7a16b7b3 GIT binary patch literal 15332 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 CsN3HF literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/holiday_background.xml b/app/src/main/res/drawable/holiday_background.xml new file mode 100644 index 00000000..55adb780 --- /dev/null +++ b/app/src/main/res/drawable/holiday_background.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_access_time_white_24dp.xml b/app/src/main/res/drawable/ic_access_time_white_24dp.xml new file mode 100644 index 00000000..5562133e --- /dev/null +++ b/app/src/main/res/drawable/ic_access_time_white_24dp.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_album_white_24dp.xml b/app/src/main/res/drawable/ic_album_white_24dp.xml new file mode 100644 index 00000000..6ae8cd83 --- /dev/null +++ b/app/src/main/res/drawable/ic_album_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_app_icon_with_shadow.xml b/app/src/main/res/drawable/ic_app_icon_with_shadow.xml new file mode 100644 index 00000000..9eaf3242 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_with_shadow.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_shortcut_background.xml b/app/src/main/res/drawable/ic_app_shortcut_background.xml new file mode 100644 index 00000000..914648b4 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_shortcut_background.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_shortcut_last_added.xml b/app/src/main/res/drawable/ic_app_shortcut_last_added.xml new file mode 100644 index 00000000..b80363f4 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_shortcut_last_added.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_app_shortcut_shuffle_all.xml b/app/src/main/res/drawable/ic_app_shortcut_shuffle_all.xml new file mode 100644 index 00000000..33fccfc9 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_shortcut_shuffle_all.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_app_shortcut_top_tracks.xml b/app/src/main/res/drawable/ic_app_shortcut_top_tracks.xml new file mode 100644 index 00000000..02fa94e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_shortcut_top_tracks.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow_forward_white_24dp.xml b/app/src/main/res/drawable/ic_arrow_forward_white_24dp.xml new file mode 100644 index 00000000..bcce82ff --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_forward_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_artist_white_24dp.xml b/app/src/main/res/drawable/ic_artist_white_24dp.xml new file mode 100644 index 00000000..87433a4b --- /dev/null +++ b/app/src/main/res/drawable/ic_artist_white_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_audio_tag_square.xml b/app/src/main/res/drawable/ic_audio_tag_square.xml new file mode 100644 index 00000000..3cfbf30c --- /dev/null +++ b/app/src/main/res/drawable/ic_audio_tag_square.xml @@ -0,0 +1,16 @@ + + + diff --git a/app/src/main/res/drawable/ic_audiotrack_black_24dp.xml b/app/src/main/res/drawable/ic_audiotrack_black_24dp.xml new file mode 100644 index 00000000..54dbfa78 --- /dev/null +++ b/app/src/main/res/drawable/ic_audiotrack_black_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_beer_white_24dp.xml b/app/src/main/res/drawable/ic_beer_white_24dp.xml new file mode 100644 index 00000000..347dc731 --- /dev/null +++ b/app/src/main/res/drawable/ic_beer_white_24dp.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_bookmark_music_white_24dp.xml b/app/src/main/res/drawable/ic_bookmark_music_white_24dp.xml new file mode 100644 index 00000000..fa10a8fa --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark_music_white_24dp.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_card_giftcard_white_24dp.xml b/app/src/main/res/drawable/ic_card_giftcard_white_24dp.xml new file mode 100644 index 00000000..2d7e2a83 --- /dev/null +++ b/app/src/main/res/drawable/ic_card_giftcard_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_close_white_24dp.xml b/app/src/main/res/drawable/ic_close_white_24dp.xml new file mode 100644 index 00000000..bbd0e311 --- /dev/null +++ b/app/src/main/res/drawable/ic_close_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cookie_white_24dp.xml b/app/src/main/res/drawable/ic_cookie_white_24dp.xml new file mode 100644 index 00000000..7d6ea675 --- /dev/null +++ b/app/src/main/res/drawable/ic_cookie_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_white_24dp.xml b/app/src/main/res/drawable/ic_delete_white_24dp.xml new file mode 100644 index 00000000..3a2050bf --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_discord_white_24dp.xml b/app/src/main/res/drawable/ic_discord_white_24dp.xml new file mode 100644 index 00000000..807fe077 --- /dev/null +++ b/app/src/main/res/drawable/ic_discord_white_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_drag_vertical_white_24dp.xml b/app/src/main/res/drawable/ic_drag_vertical_white_24dp.xml new file mode 100755 index 00000000..402b4b9e --- /dev/null +++ b/app/src/main/res/drawable/ic_drag_vertical_white_24dp.xml @@ -0,0 +1,24 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_edit_white_24dp.xml b/app/src/main/res/drawable/ic_edit_white_24dp.xml new file mode 100644 index 00000000..7a19f313 --- /dev/null +++ b/app/src/main/res/drawable/ic_edit_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_facebook.xml b/app/src/main/res/drawable/ic_facebook.xml new file mode 100644 index 00000000..6b2fa5b9 --- /dev/null +++ b/app/src/main/res/drawable/ic_facebook.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_fast_food_meal_white_24dp.xml b/app/src/main/res/drawable/ic_fast_food_meal_white_24dp.xml new file mode 100644 index 00000000..4598c484 --- /dev/null +++ b/app/src/main/res/drawable/ic_fast_food_meal_white_24dp.xml @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_favorite_border_white_24dp.xml b/app/src/main/res/drawable/ic_favorite_border_white_24dp.xml new file mode 100644 index 00000000..5e0d0bde --- /dev/null +++ b/app/src/main/res/drawable/ic_favorite_border_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_favorite_white_24dp.xml b/app/src/main/res/drawable/ic_favorite_white_24dp.xml new file mode 100644 index 00000000..66529059 --- /dev/null +++ b/app/src/main/res/drawable/ic_favorite_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_file_music_white_24dp.xml b/app/src/main/res/drawable/ic_file_music_white_24dp.xml new file mode 100644 index 00000000..efb25ba9 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_music_white_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_flag_white_24dp.xml b/app/src/main/res/drawable/ic_flag_white_24dp.xml new file mode 100644 index 00000000..a5658d37 --- /dev/null +++ b/app/src/main/res/drawable/ic_flag_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_folder_white_24dp.xml b/app/src/main/res/drawable/ic_folder_white_24dp.xml new file mode 100644 index 00000000..13fb2774 --- /dev/null +++ b/app/src/main/res/drawable/ic_folder_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_color_fill.xml b/app/src/main/res/drawable/ic_format_color_fill.xml new file mode 100644 index 00000000..ead2a834 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_color_fill.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_github_circle_white_24dp.xml b/app/src/main/res/drawable/ic_github_circle_white_24dp.xml new file mode 100644 index 00000000..b2446883 --- /dev/null +++ b/app/src/main/res/drawable/ic_github_circle_white_24dp.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_google_circles_communities_white_24dp.xml b/app/src/main/res/drawable/ic_google_circles_communities_white_24dp.xml new file mode 100644 index 00000000..58ee29f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_google_circles_communities_white_24dp.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_google_plus_white_24dp.xml b/app/src/main/res/drawable/ic_google_plus_white_24dp.xml new file mode 100644 index 00000000..6c2c66b0 --- /dev/null +++ b/app/src/main/res/drawable/ic_google_plus_white_24dp.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_hdr_strong_white_24dp.xml b/app/src/main/res/drawable/ic_hdr_strong_white_24dp.xml new file mode 100644 index 00000000..b788254c --- /dev/null +++ b/app/src/main/res/drawable/ic_hdr_strong_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_help_white_24dp.xml b/app/src/main/res/drawable/ic_help_white_24dp.xml new file mode 100644 index 00000000..d264f1e8 --- /dev/null +++ b/app/src/main/res/drawable/ic_help_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_home_white_24dp.xml b/app/src/main/res/drawable/ic_home_white_24dp.xml new file mode 100644 index 00000000..1d64d019 --- /dev/null +++ b/app/src/main/res/drawable/ic_home_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_image_white_24dp.xml b/app/src/main/res/drawable/ic_image_white_24dp.xml new file mode 100644 index 00000000..e7895e8b --- /dev/null +++ b/app/src/main/res/drawable/ic_image_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_instagram.xml b/app/src/main/res/drawable/ic_instagram.xml new file mode 100644 index 00000000..9256b833 --- /dev/null +++ b/app/src/main/res/drawable/ic_instagram.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml new file mode 100644 index 00000000..3727871a --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_right_white_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_right_white_24dp.xml new file mode 100644 index 00000000..faa8d22e --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_right_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_up_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_up_24dp.xml new file mode 100755 index 00000000..37ec57fd --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_up_24dp.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_keyboard_backspace_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_backspace_black_24dp.xml new file mode 100644 index 00000000..e1271464 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_backspace_black_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..3e01a542 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 00000000..7de11d5a --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_library_add_white_24dp.xml b/app/src/main/res/drawable/ic_library_add_white_24dp.xml new file mode 100644 index 00000000..d1a6c780 --- /dev/null +++ b/app/src/main/res/drawable/ic_library_add_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_library_music_white_24dp.xml b/app/src/main/res/drawable/ic_library_music_white_24dp.xml new file mode 100644 index 00000000..d166ec3d --- /dev/null +++ b/app/src/main/res/drawable/ic_library_music_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_white_24dp.xml b/app/src/main/res/drawable/ic_menu_white_24dp.xml new file mode 100644 index 00000000..046b129d --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_mic_white_24dp.xml b/app/src/main/res/drawable/ic_mic_white_24dp.xml new file mode 100644 index 00000000..441e9045 --- /dev/null +++ b/app/src/main/res/drawable/ic_mic_white_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_more_vert_white_24dp.xml b/app/src/main/res/drawable/ic_more_vert_white_24dp.xml new file mode 100644 index 00000000..c42c1dcd --- /dev/null +++ b/app/src/main/res/drawable/ic_more_vert_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_notifications_active_white_24dp.xml b/app/src/main/res/drawable/ic_notifications_active_white_24dp.xml new file mode 100644 index 00000000..08874789 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_active_white_24dp.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_patreon.xml b/app/src/main/res/drawable/ic_patreon.xml new file mode 100644 index 00000000..2e11a0d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_patreon.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_pause_white_24dp.xml b/app/src/main/res/drawable/ic_pause_white_24dp.xml new file mode 100644 index 00000000..bc3d2e0c --- /dev/null +++ b/app/src/main/res/drawable/ic_pause_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_pause_white_big.xml b/app/src/main/res/drawable/ic_pause_white_big.xml new file mode 100644 index 00000000..e3892586 --- /dev/null +++ b/app/src/main/res/drawable/ic_pause_white_big.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_person_flat.xml b/app/src/main/res/drawable/ic_person_flat.xml new file mode 100644 index 00000000..c0c3cbdf --- /dev/null +++ b/app/src/main/res/drawable/ic_person_flat.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_person_white_24dp.xml b/app/src/main/res/drawable/ic_person_white_24dp.xml new file mode 100644 index 00000000..c917f381 --- /dev/null +++ b/app/src/main/res/drawable/ic_person_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_play_arrow_white_24dp.xml b/app/src/main/res/drawable/ic_play_arrow_white_24dp.xml new file mode 100644 index 00000000..3a75768e --- /dev/null +++ b/app/src/main/res/drawable/ic_play_arrow_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_play_arrow_white_big.xml b/app/src/main/res/drawable/ic_play_arrow_white_big.xml new file mode 100644 index 00000000..34f71d45 --- /dev/null +++ b/app/src/main/res/drawable/ic_play_arrow_white_big.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_play_circle_filled_white_24dp.xml b/app/src/main/res/drawable/ic_play_circle_filled_white_24dp.xml new file mode 100644 index 00000000..4dcc3f3d --- /dev/null +++ b/app/src/main/res/drawable/ic_play_circle_filled_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_playlist_add_white_24dp.xml b/app/src/main/res/drawable/ic_playlist_add_white_24dp.xml new file mode 100644 index 00000000..2c9a92a8 --- /dev/null +++ b/app/src/main/res/drawable/ic_playlist_add_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_playlist_play_white_24dp.xml b/app/src/main/res/drawable/ic_playlist_play_white_24dp.xml new file mode 100644 index 00000000..47a35405 --- /dev/null +++ b/app/src/main/res/drawable/ic_playlist_play_white_24dp.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_popcorn_white_24dp.xml b/app/src/main/res/drawable/ic_popcorn_white_24dp.xml new file mode 100644 index 00000000..5f0f93fd --- /dev/null +++ b/app/src/main/res/drawable/ic_popcorn_white_24dp.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable/ic_queue_music_white_24dp.xml b/app/src/main/res/drawable/ic_queue_music_white_24dp.xml new file mode 100644 index 00000000..27472f3c --- /dev/null +++ b/app/src/main/res/drawable/ic_queue_music_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_recent_actors_white_24dp.xml b/app/src/main/res/drawable/ic_recent_actors_white_24dp.xml new file mode 100644 index 00000000..66d84251 --- /dev/null +++ b/app/src/main/res/drawable/ic_recent_actors_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_redo_white_24dp.xml b/app/src/main/res/drawable/ic_redo_white_24dp.xml new file mode 100644 index 00000000..07276a51 --- /dev/null +++ b/app/src/main/res/drawable/ic_redo_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_repeat_one_white_24dp.xml b/app/src/main/res/drawable/ic_repeat_one_white_24dp.xml new file mode 100644 index 00000000..782dfcb4 --- /dev/null +++ b/app/src/main/res/drawable/ic_repeat_one_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_repeat_white_24dp.xml b/app/src/main/res/drawable/ic_repeat_white_24dp.xml new file mode 100644 index 00000000..62cebf6d --- /dev/null +++ b/app/src/main/res/drawable/ic_repeat_white_24dp.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_rounded_corner.xml b/app/src/main/res/drawable/ic_rounded_corner.xml new file mode 100644 index 00000000..5c2c2437 --- /dev/null +++ b/app/src/main/res/drawable/ic_rounded_corner.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_save_white_24dp.xml b/app/src/main/res/drawable/ic_save_white_24dp.xml new file mode 100644 index 00000000..c9d3d399 --- /dev/null +++ b/app/src/main/res/drawable/ic_save_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_scanner_white_24dp.xml b/app/src/main/res/drawable/ic_scanner_white_24dp.xml new file mode 100644 index 00000000..28ccf065 --- /dev/null +++ b/app/src/main/res/drawable/ic_scanner_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_search_white_24dp.xml b/app/src/main/res/drawable/ic_search_white_24dp.xml new file mode 100644 index 00000000..4408efa2 --- /dev/null +++ b/app/src/main/res/drawable/ic_search_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_select_all_white_24dp.xml b/app/src/main/res/drawable/ic_select_all_white_24dp.xml new file mode 100644 index 00000000..a7029a97 --- /dev/null +++ b/app/src/main/res/drawable/ic_select_all_white_24dp.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_white_24dp.xml b/app/src/main/res/drawable/ic_settings_white_24dp.xml new file mode 100644 index 00000000..03555a89 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_share_white_24dp.xml b/app/src/main/res/drawable/ic_share_white_24dp.xml new file mode 100644 index 00000000..fbcafd12 --- /dev/null +++ b/app/src/main/res/drawable/ic_share_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_shuffle_white_24dp.xml b/app/src/main/res/drawable/ic_shuffle_white_24dp.xml new file mode 100644 index 00000000..c333702e --- /dev/null +++ b/app/src/main/res/drawable/ic_shuffle_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_skip_next_white_24dp.xml b/app/src/main/res/drawable/ic_skip_next_white_24dp.xml new file mode 100644 index 00000000..f81e98bb --- /dev/null +++ b/app/src/main/res/drawable/ic_skip_next_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_skip_previous_white_24dp.xml b/app/src/main/res/drawable/ic_skip_previous_white_24dp.xml new file mode 100644 index 00000000..ec3f1661 --- /dev/null +++ b/app/src/main/res/drawable/ic_skip_previous_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_sort_white_24dp.xml b/app/src/main/res/drawable/ic_sort_white_24dp.xml new file mode 100644 index 00000000..11cc5091 --- /dev/null +++ b/app/src/main/res/drawable/ic_sort_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_star_white_24dp.xml b/app/src/main/res/drawable/ic_star_white_24dp.xml new file mode 100644 index 00000000..a16151f0 --- /dev/null +++ b/app/src/main/res/drawable/ic_star_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_take_away_coffe_white_24dp.xml b/app/src/main/res/drawable/ic_take_away_coffe_white_24dp.xml new file mode 100644 index 00000000..93f951c6 --- /dev/null +++ b/app/src/main/res/drawable/ic_take_away_coffe_white_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_take_away_white_24dp.xml b/app/src/main/res/drawable/ic_take_away_white_24dp.xml new file mode 100644 index 00000000..efe7c722 --- /dev/null +++ b/app/src/main/res/drawable/ic_take_away_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_telegram_white.xml b/app/src/main/res/drawable/ic_telegram_white.xml new file mode 100644 index 00000000..c20227ea --- /dev/null +++ b/app/src/main/res/drawable/ic_telegram_white.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_theme_palette_white_24dp.xml b/app/src/main/res/drawable/ic_theme_palette_white_24dp.xml new file mode 100644 index 00000000..3673e4d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_theme_palette_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_timer_white_24dp.xml b/app/src/main/res/drawable/ic_timer_white_24dp.xml new file mode 100644 index 00000000..e71a9b8e --- /dev/null +++ b/app/src/main/res/drawable/ic_timer_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_trending_up_white_24dp.xml b/app/src/main/res/drawable/ic_trending_up_white_24dp.xml new file mode 100644 index 00000000..573d84f3 --- /dev/null +++ b/app/src/main/res/drawable/ic_trending_up_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_twitter_white_24dp.xml b/app/src/main/res/drawable/ic_twitter_white_24dp.xml new file mode 100755 index 00000000..3ecff0ea --- /dev/null +++ b/app/src/main/res/drawable/ic_twitter_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_unfold_more_black_24dp.xml b/app/src/main/res/drawable/ic_unfold_more_black_24dp.xml new file mode 100644 index 00000000..6c9dac13 --- /dev/null +++ b/app/src/main/res/drawable/ic_unfold_more_black_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_vector_square.xml b/app/src/main/res/drawable/ic_vector_square.xml new file mode 100644 index 00000000..c58ff194 --- /dev/null +++ b/app/src/main/res/drawable/ic_vector_square.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_carousel_black_24dp.xml b/app/src/main/res/drawable/ic_view_carousel_black_24dp.xml new file mode 100644 index 00000000..41ae3b6c --- /dev/null +++ b/app/src/main/res/drawable/ic_view_carousel_black_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_volume_down_white_24dp.xml b/app/src/main/res/drawable/ic_volume_down_white_24dp.xml new file mode 100644 index 00000000..6961d21e --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_down_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_volume_off_white_24dp.xml b/app/src/main/res/drawable/ic_volume_off_white_24dp.xml new file mode 100644 index 00000000..66e655aa --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_off_white_24dp.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_volume_up_white_24dp.xml b/app/src/main/res/drawable/ic_volume_up_white_24dp.xml new file mode 100644 index 00000000..e8a80cca --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_up_white_24dp.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_water_bottle_white_24dp.xml b/app/src/main/res/drawable/ic_water_bottle_white_24dp.xml new file mode 100644 index 00000000..cbd6c961 --- /dev/null +++ b/app/src/main/res/drawable/ic_water_bottle_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/line_button.xml b/app/src/main/res/drawable/line_button.xml new file mode 100644 index 00000000..ee063c5a --- /dev/null +++ b/app/src/main/res/drawable/line_button.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/lockscreen_gradient.xml b/app/src/main/res/drawable/lockscreen_gradient.xml new file mode 100644 index 00000000..10c5e26c --- /dev/null +++ b/app/src/main/res/drawable/lockscreen_gradient.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/luis_gmzz.webp b/app/src/main/res/drawable/luis_gmzz.webp new file mode 100644 index 0000000000000000000000000000000000000000..f77b703968b270963ecfc9908b3ce196f9443871 GIT binary patch literal 5022 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 CC5}u0 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/material_design_default.webp b/app/src/main/res/drawable/material_design_default.webp new file mode 100644 index 0000000000000000000000000000000000000000..5906200995807f5a34c137218692f2a03d9c43f5 GIT binary patch literal 24958 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 + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/mini_player_progress_drawable.xml b/app/src/main/res/drawable/mini_player_progress_drawable.xml new file mode 100644 index 00000000..712902f0 --- /dev/null +++ b/app/src/main/res/drawable/mini_player_progress_drawable.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/notification_selector.xml b/app/src/main/res/drawable/notification_selector.xml new file mode 100644 index 00000000..d7867f86 --- /dev/null +++ b/app/src/main/res/drawable/notification_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/progress_drawable_vertical.xml b/app/src/main/res/drawable/progress_drawable_vertical.xml new file mode 100644 index 00000000..07660805 --- /dev/null +++ b/app/src/main/res/drawable/progress_drawable_vertical.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rect_selector.xml b/app/src/main/res/drawable/rect_selector.xml new file mode 100644 index 00000000..b03bcafa --- /dev/null +++ b/app/src/main/res/drawable/rect_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rect_selector_dark.xml b/app/src/main/res/drawable/rect_selector_dark.xml new file mode 100644 index 00000000..68896bf4 --- /dev/null +++ b/app/src/main/res/drawable/rect_selector_dark.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rect_selector_strong.xml b/app/src/main/res/drawable/rect_selector_strong.xml new file mode 100644 index 00000000..74866e66 --- /dev/null +++ b/app/src/main/res/drawable/rect_selector_strong.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rect_selector_strong_dark.xml b/app/src/main/res/drawable/rect_selector_strong_dark.xml new file mode 100644 index 00000000..faf5f5c8 --- /dev/null +++ b/app/src/main/res/drawable/rect_selector_strong_dark.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/round_selected.xml b/app/src/main/res/drawable/round_selected.xml new file mode 100644 index 00000000..7b468848 --- /dev/null +++ b/app/src/main/res/drawable/round_selected.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/round_selected_dark.xml b/app/src/main/res/drawable/round_selected_dark.xml new file mode 100644 index 00000000..5f6350ed --- /dev/null +++ b/app/src/main/res/drawable/round_selected_dark.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/round_selector.xml b/app/src/main/res/drawable/round_selector.xml new file mode 100644 index 00000000..77f09a4c --- /dev/null +++ b/app/src/main/res/drawable/round_selector.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/round_selector_dark.xml b/app/src/main/res/drawable/round_selector_dark.xml new file mode 100644 index 00000000..d1720184 --- /dev/null +++ b/app/src/main/res/drawable/round_selector_dark.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/round_window.xml b/app/src/main/res/drawable/round_window.xml new file mode 100755 index 00000000..7e4dcae2 --- /dev/null +++ b/app/src/main/res/drawable/round_window.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/search_gradient.xml b/app/src/main/res/drawable/search_gradient.xml new file mode 100644 index 00000000..856e9def --- /dev/null +++ b/app/src/main/res/drawable/search_gradient.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow.xml b/app/src/main/res/drawable/shadow.xml new file mode 100644 index 00000000..2ebc5646 --- /dev/null +++ b/app/src/main/res/drawable/shadow.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow_down.xml b/app/src/main/res/drawable/shadow_down.xml new file mode 100755 index 00000000..623e2b6a --- /dev/null +++ b/app/src/main/res/drawable/shadow_down.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow_down_edited.xml b/app/src/main/res/drawable/shadow_down_edited.xml new file mode 100644 index 00000000..7e7178e2 --- /dev/null +++ b/app/src/main/res/drawable/shadow_down_edited.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow_down_strong.xml b/app/src/main/res/drawable/shadow_down_strong.xml new file mode 100755 index 00000000..cc2175df --- /dev/null +++ b/app/src/main/res/drawable/shadow_down_strong.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow_left_to_right.xml b/app/src/main/res/drawable/shadow_left_to_right.xml new file mode 100644 index 00000000..16ba6f80 --- /dev/null +++ b/app/src/main/res/drawable/shadow_left_to_right.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow_up.xml b/app/src/main/res/drawable/shadow_up.xml new file mode 100755 index 00000000..39160e50 --- /dev/null +++ b/app/src/main/res/drawable/shadow_up.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow_up_details.xml b/app/src/main/res/drawable/shadow_up_details.xml new file mode 100644 index 00000000..b81cbed3 --- /dev/null +++ b/app/src/main/res/drawable/shadow_up_details.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow_up_edited.xml b/app/src/main/res/drawable/shadow_up_edited.xml new file mode 100644 index 00000000..8c67be58 --- /dev/null +++ b/app/src/main/res/drawable/shadow_up_edited.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow_up_full_theme.xml b/app/src/main/res/drawable/shadow_up_full_theme.xml new file mode 100644 index 00000000..34a8df78 --- /dev/null +++ b/app/src/main/res/drawable/shadow_up_full_theme.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow_up_home.xml b/app/src/main/res/drawable/shadow_up_home.xml new file mode 100644 index 00000000..dab8e5e1 --- /dev/null +++ b/app/src/main/res/drawable/shadow_up_home.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow_up_strong.xml b/app/src/main/res/drawable/shadow_up_strong.xml new file mode 100755 index 00000000..e56f2bce --- /dev/null +++ b/app/src/main/res/drawable/shadow_up_strong.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_button_edit.xml b/app/src/main/res/drawable/shape_button_edit.xml new file mode 100644 index 00000000..49065e70 --- /dev/null +++ b/app/src/main/res/drawable/shape_button_edit.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_rounded_edit.xml b/app/src/main/res/drawable/shape_rounded_edit.xml new file mode 100644 index 00000000..ead9e011 --- /dev/null +++ b/app/src/main/res/drawable/shape_rounded_edit.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shuffle_line_background.xml b/app/src/main/res/drawable/shuffle_line_background.xml new file mode 100644 index 00000000..a551082d --- /dev/null +++ b/app/src/main/res/drawable/shuffle_line_background.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/slider_thumb.xml b/app/src/main/res/drawable/slider_thumb.xml new file mode 100644 index 00000000..7ac0f609 --- /dev/null +++ b/app/src/main/res/drawable/slider_thumb.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/square_play_button.xml b/app/src/main/res/drawable/square_play_button.xml new file mode 100644 index 00000000..6fe74edc --- /dev/null +++ b/app/src/main/res/drawable/square_play_button.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/square_play_button_design.xml b/app/src/main/res/drawable/square_play_button_design.xml new file mode 100644 index 00000000..c76f83ae --- /dev/null +++ b/app/src/main/res/drawable/square_play_button_design.xml @@ -0,0 +1,17 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/square_window.xml b/app/src/main/res/drawable/square_window.xml new file mode 100755 index 00000000..f18ea8dd --- /dev/null +++ b/app/src/main/res/drawable/square_window.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/switch_thumb_material.xml b/app/src/main/res/drawable/switch_thumb_material.xml new file mode 100755 index 00000000..8c359a89 --- /dev/null +++ b/app/src/main/res/drawable/switch_thumb_material.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/thumb_material.xml b/app/src/main/res/drawable/thumb_material.xml new file mode 100644 index 00000000..8bd8cf9b --- /dev/null +++ b/app/src/main/res/drawable/thumb_material.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/toggle_outline_buttons.xml b/app/src/main/res/drawable/toggle_outline_buttons.xml new file mode 100644 index 00000000..d0f3f291 --- /dev/null +++ b/app/src/main/res/drawable/toggle_outline_buttons.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/top_corners.xml b/app/src/main/res/drawable/top_corners.xml new file mode 100644 index 00000000..d17bd811 --- /dev/null +++ b/app/src/main/res/drawable/top_corners.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/widget_selector.xml b/app/src/main/res/drawable/widget_selector.xml new file mode 100755 index 00000000..68896bf4 --- /dev/null +++ b/app/src/main/res/drawable/widget_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/widget_selector_dark.xml b/app/src/main/res/drawable/widget_selector_dark.xml new file mode 100644 index 00000000..d7867f86 --- /dev/null +++ b/app/src/main/res/drawable/widget_selector_dark.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/widget_selector_light.xml b/app/src/main/res/drawable/widget_selector_light.xml new file mode 100644 index 00000000..b03bcafa --- /dev/null +++ b/app/src/main/res/drawable/widget_selector_light.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_album.xml b/app/src/main/res/layout-land/activity_album.xml new file mode 100644 index 00000000..034b439d --- /dev/null +++ b/app/src/main/res/layout-land/activity_album.xml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout-land/activity_album_tag_editor.xml b/app/src/main/res/layout-land/activity_album_tag_editor.xml new file mode 100644 index 00000000..760b15be --- /dev/null +++ b/app/src/main/res/layout-land/activity_album_tag_editor.xml @@ -0,0 +1,165 @@ + + + + + + +

    }Ka+EUMbur;AW=`=%7esG zde&Vc;NMcBqC~PsAiHfSh+{|-*0j72lOyc$-(qDHUKlk1X^ejfj$&m-TST?F&Sqc? z$BSwyv@sI?T27jm$8&2@hsB~MGD-_klW}msBSiR)t>)KiC2bnwz)sT0t&Wo=E}3*C z$%Wlzlb9N??9GfKMFqr~P$;C;q5O-g**~ti=BvmvoMj;#rEn=-b3)pM3E7pA{)4L7 z+a$oet+9ThYMP9nsM?JR!{nsLgbIEv)MeN|s2cVss&@B@suAHAfexgolhj^h+ik28 z4vdA%<2Exz=Mi);DW>Q|oyg$N zBFad-1{oVTO?3@(s(lW#M@1^1zw-8Jo5ScL)Ds_%ok$teWEZsq$82hOp=Nc4NMhI8 zq5{^y=5uw5NPo`i9>xAO|6D2leE{iB8Q|IX5c}nrt9FLJnr>;=E$I>5@}#E4)y0B?rV&pI~zR3O%)4D>&Sg27= z3qV~cohYY~0>+Ksy%Qvs2!?NZ*HH@U@%z*1iA3=i6`PrXFV~MLSQ#eKIe=y@9}(qh zH$#DX%gYn(ZU&mX7j2zMz->VK;hN(e`}f6Ntg5XB2)gnTF$fbd+I|pF$U8WfP&-+P&70r7;MVxo69d^e0qZY;jrP^b!yMByO+;BA~8p7O^ zDF2$0)kZ1n;Y+ox34>7_bzZav*UpprqAZsE^x-*EyGcFxv)Hat)&B5dXIrT3Wa7Yw zDF%8*p^Z(5m{eHQAHO{RZfo0*Vkp0O)1lyQejp|1TK#+Izw>yWDIW1wLb~cYa zhmq}}181_#&KR#<&|O5VyKni4<(J(Hh3^X{p+-o0XOVa$3X3%H8gsZ%*tOZvdbg5z z%G&%GIMxD&Km`U>ByM$O`7-B(=&39#p51!|gBczdyB+Qp4_dy_`Q8bDF?D1Mfucu&=@Z++zA zT@Jiib9^lfnOAZhzbO&k1R-|cZ2e%gT>x#xp?qabyX=ef1p3dhtg#;Ye_h$EuqJ0Ru?#7Y*_yhIz-6n5`DHAk|?|Ukx2_s65AbAK$6FXtQ! z-tExQjK!(xw}hLsb8_r&zJ$G@Z}0djdt4R)v&PP5*|pLXHheG6x)n2B2OC-#r8|2d zG;J*mZgyh!Up;na3@h$q(j+Zi0q4?2DvAm+LicWVW~DoMr3Bgzsm()?wytvDpv@{5}MIb?aqvO&4895r2jnMccVKsl6L zB~5;fNAB{uoHb2;b(_jLLwRe)yegmexj^|t29rvUifziWS$TXqla^kIN9?j%xqJqb zx?V+_fo6 zy4|uiBU>5U@a3lEnB}VFIXQE=BRLE?f($3st+F;<+xX>rxlY>M29N0Fd^!CL;!$|$ zeTDK4`fC-r4XrQs@Wx^1yaX+*k(1zuu8$l9s37J^us(s44=jtlM%=Dr?DpQ1mo-)`j4^J z>Wt^$l!|y+Y~^o?cohz}C|zgFWh|4Zg7K5Oaz2SV-&DX5=g$u>Xp4=%nj5F;5z*AF zEtlU9!MRZY#JDSNu(PTBCUt^ILGT8T?l1`?Tn)4>iD~CgnD`sj91Y*xNHLjxcU0 zqI>l$s;RO}{w-9`shC~Yw7Ciy7P*rJ4bzCSR({uF{v8(XPLbWIa~OXDh}uO`BQqzN zmaBA1B(XOP%Iujko5s-ppc84+EveDx9cG?)vBCYQC+roQ)Rb%6!8dPQv?-UUWmqw) zU&4>AscZhDm$)w5wuf)+>@q~H+Aa}f-)CqF<5Ad-zOIWsoQMxixnrUDRj1KZW(4{N z74A9CDuZe~=ef(OR&0lE+VwU5^*5W!3}u9N zb?-&G16Hlj-HIbG*;OaSW_}Jixwh?GJ8!!->5_ELIU%jmBZ`Zbifw<+i_EIYT+=7J zHsz8w&Xt>$D&rEc+Qq%br91R|lercY8;=qRYTZ`bSL*Y-LWTp{b;7VpJ0F#i1zmTz zf{KH4^q{?5X&?fA0qH@`dO(=*Dv$wgp#vNBH8tu~24rbZI^1aE(-3j0D+#%<0R)F* zZi|C6DmxfQ4_ecc0HPx?X8`Tj&BC&5eYzuzJLRsNf9@{>;o$}y8H=ZGZG6fjv~|lN z8`pvOaD(=Y+pY#5^vJZg6zxRLZndS9>wjk<_@HL+M_96o7=bE zW0U-KN~G&JKaI5{e~pnsJxz}ENsa)65$d}3KWRPp>gaE?de$EXrInO^6MD|VwM*{k zZzEeSxPr_}%#4L^^nW*c!f_~G6Eziqo%jPZ2lAPPfFJk+WCyo(_Q6zF8XL<=BIg)TDP*^McO^GS2Bu2q~scFQEG@j@?v2ltq z>@-vc%4x5nga{|)42snoIrNoKP6~4(9ci}tP`lJSY}a>+cY5za_X!nz$4Wc`MaoC<)JPG0wGVdMKQ!_>SDJKm~1lyPTFFq z5AC!W3==i2D*zsy5519s))RoAT8?ZW{VA>?QCK4HNT}TmF;aNY>`AGe50R!GBkw4R zO&$hP&=dK5v&euzNm(2Qu}tH`5K~sW0bJ4f@C(UwPlr}0E{S|T3Ao8q*#P7|5w+`~ zc#0qxBhqSDfF?R0oiTN_CqOZk4`z?7xb)sJwFu%i)xixA`1whg0*)8RDjOaygYLx= zPjOfjO>tquHEjhm2dWS0Jo~{GMXD4;_>+bBBn;}uxlvb2L5Db#hdA*r3iSx3M{s|^ zP27{XkN^@CkZzZ9KfF2{V#S3|VUjI7)RP6HQ=IfBT-S$ccH)N#@*b@F9awhs!caf} z5jFs(X%QDeQi>Fl;J9h3Dso&3AsyGSX^aQ9d?K=GwF^5F?@27@jw79*Q8e<7RKsei zs^w%ju5PV~jUK$Vh0nxu9ZV<9lS#wU5X!#wCc;x!dE})o%T#=QfB5uXq`mgbYXhaq z(Y@$UMu?s^^=h|LRAR%!*RvjcuI`&KzYPpjw|+>Z2Jf#|UgBedP$f5NKd%}>vwPtV zZ7`G@UCg9X%s2wh2oF_`({U}QPsccZ2o=3+iuZHAj=fa`3XIuD zTLKDlOoD_$ig;*9>}!fObJg8AZYeH?c>oL508m6^;bXyrzr0r^Am`&d`^QuMkKlLq zhvP(qLI|A*^KqIHeBp}HXhFZXvIffzA!g#clEU-L_&XZnheKE4SD%q&&!0nO)Pdh} zT9%@-NnB}WyQY&Nxp2~Sf14tRJO3t~UI!!L=(rFnd-Z{j!pTIjCFyu>CgKmkwYXdn zx_UIl!6-ySy}G_la3B@??zUPYpOS5*T+O?sN3nNYFJB( zLWAkMf1)W*cPBE>VMDAn1YNyZ?=dvJ zIJ=_89$a9}K|W;m*C?)n?haqlBbT^x%a?Li@f60$9!{dx zW$5R-r!!mfinf|r+eOXF=elmno-9xFi{?DRKQcOzRB$L}ky)H4CH%tFU>T(%vrmil ztdwoVyYbeP0@0^X3O&zpoRw=92COq#NoV~%axl+I>}%(`284xhTPM~Rb_;f zkSe(Ofa@EOIBD^m?#Ag?bCs)PtA@SGi0Tzi69Bu@%7f!|p1F@5cF>24W ztuk^}H$-jliSHjrkxIIi;r7}VUd&{&mLbd7EY#Av_n2}?ldVm$ye6t0_5lplc{4K1 zuuINk9!>f@P_3*mt0QHx*`j`l@`aLq_418mflN1Z7Y{Opx67kt%r55$;i6n|vP_iv zg4in$Ld#oc`7)PXTiw>AtMh^|cN{P~$_wa=3n4zJk%y$9@lhSIj@Un54C8Jg@(Egi zG8CS&OSs7(@-XD{Hh19aXZhc(K@vE6GWr8+0>-{{wa@p~Xa|E#!Lugz*a7?q?8O+W z&!)SrxxI|lKZT;Ecz-;rKC)8W zMa0v5qqLir#+;FTq(#f0m2G1qSt{7=j!{BeI{z+_5+IS~hMrGZqM%f=9w4FZhHm(^ zB%U|+tn~`j@puxJp}|sMcz05Dj*>(+L*YJEWjI0%oq`JU>ix@J7zPdSJ4I16KZ6;? zA!SzUcv34(@Fko-zOJ!Q`W&DoZJ5bUY9Gzv192SZ;8s|AHyBzBS`9k%9^LP!9j$tJ zhn^3yC55F*!LU#7m*5BRpZA(s0dthb-qYMIP_0LWa3td&P<@BmI;25~nunHk7=xk; zuh=~xBCojpUbpSznR?U_&MS(Cn&Q=naV0zLtJTb1ws!XHq18BpYD<5cP;isK#c}hZ%~H2sP~pB~$Czok1#OZn^FHZv)=i3V{;M-^qA&fUizb|$R-VUF zn|MaWXr{Ka)F8hf$KM9O)lu=3wZ5l@^P~(wEA$csdV zoLI5{MFaKaOEAKhFI@k>N1(dLXV0zs|2O~_ywSBW-}gd7zsZJWOQfmf=1M@Q%8Ki? zzr)LlR8vTZaM&ec;JSEZ51Yo!m9Tz@Wij<$R1hqvK6)(O{N?`r_&8w7S7IXG>wCNR zbko1@9XuN@{QmNr`%ApdV=2iGAw<&oa;$;67aQG&;dscbRN@^VK%Ydd>s%cFGGG%( z8m@@aV#MH=@<5urZG;I5nvCx?a&WyP9`y;bXK&6=Hcqa5h`qAnN|CofxC@|b9Y&QA zPVp+QqO;AgndiW)cZ)T3(cHMGD9eG8b(})P&KCV=gORGn1~oZz-uhTZ?$my=O221^rZGRI(Gj5=Z6CQN!Po zlI5k5lcm5cXD7;r*{~h$q!efR)mqM~v_PXA-quWR#ll=O*Dq+f7pl8A zx3jUI`N1pnK~}*^ZibB_5fBZ9hVtx&wjc9zf*egAGy@T9dN5dVK0IG+l<$b6DlrYA zD}jfFmR#%ulo(U5BG$m04`wq8h^G6BrAY52tpn{-6uYQu&SQGBX5&Nex|W`(DBkd6 zqQQcWZ&x^6G#PsE^!S3MsQbiQSC`I`!&6y;h-&Te$UEZxJqzy2!Y*;G$cY9^GEF0| z>9)H#yQLmP-;(nTEO=2`VOx>cN9K&*vgNDQE+gM)iZW`cTS?B;??Ty2qT`oMJ9d17^Mu}!uw24- zW%6nQ&1nwb5}Y1Z_22MVeTN(gQc*N(8nz2}6eSNI#Y>3tA25-`i2YRd+%{KJY{fI0 zc4(vLOc`ft1i6fb8g#r)=7u|JI~O{tYnS(vG=`UkLzr(|D51exM?6UwMGH|JU|?I+ zTaRd4)Z34$Tj8MDCGoc4y$a=}cgeh<<=azc%;`W6u6Xsf0;+4SUAVSnsgwN>$&-Dt zn6AB{ahxamAD&6;Uv?;rLY2GXOb_s-A}k}$1L}?wVCTUz$3)L^zQ(w7Nklq;P;Pw) zB)*9+9wu?P{t}$UP5Ra)$6^ne_BESA33h|As#*&b#%?DRU;0yUOwkRn4HqJ}cM{%( z#^+s;*w^>r@%qJSP#Cg+`bsqsp$`kE`yJEG5x9c<+6E!4_%URrg?FCPc@W&>j@;d# z@KX85xJ3BOSO}Doew^thA_v52anYT^SjC3*{tD~8#Jp4biv%@18WuizYf&8857tfBb&`+kebm_;F?WC7b@jlJGVH_2iyhc>+$!1u(`T@}1(y zf_m!20zSClqAcY{Y{&|(9iOtYYe@tHFv8eqOC<2yRoM?OU@U8#b#R ztFqF;qywJ(cNV-;mXmWOofvoD?)1tBi|@A)>MYvBP_IT+0J0!vs|!oEOnz6mf`bTf zgPE8g-@6F4fmLF|az+hiA$CyO_x>4Swa&+s@ zYA*d@Nbp>2ok(m>9%5L|Ww9v>htjQKd7ysXVP<+CF87@hfELt(Ye^I%gB?A2Z%*QT zG8feL^X{;k-}f%0h2vd6-}*EXp&$^}mD`~&E^xYcxOT4x`{beJzMu_$Kwv3Gdc*gt#vYs%zmha!Xwyiu#5P4^yAKxy{)) z+0RzwdBN$li*w)R`}jp{Z_9DZtDb`J-bWtXuXmu;A|D(69L$(^$+$a6(((6tZcRNB zXI_o$4ZdFO9|oagv9a?&U25Ub`fI&HL4gSZWC~ovTJ??lO$`-Jn&7A- zxDS6XF0eG$TqW2?eCW5)<0p&lieyP0fA0zqGDte+K;yOcM<<-F2<`rAaOna zUSgVJ?bt~}JvDXBoXo}jS5O;WLN+loCh%0i* zd|oNBdc|JiL`1eVNsv7w#VL{-JW~b6sU>q?Q@;28-qEZ7p~ABUHG|W3dy!w?V`^-s zXF@w^-CPgb*?t~+Ps*{59{#nRN|NHp|Lyvk(3`mNhMd>p6-ms=jSG5-uAjcB(~dM> zK#|H{Pil1m!G6yq?D;~!*5>pjyE;@T>ZgHRq}DSmZg&t9iuBJ@?Iixru6UXx<{W zR|}!tEBk#@ZVTZ&0?i3262by$T)gA<>hW(vLi4mv6%f=m#8iVZ+=YG?PE5d8I*N}T zT&I|hZydt|J!2UVg__ysS8wsl0T>NY&le4KzMd&$#m+R6kWz+^RS>#=cceSRK`z>~ zoqkuKedjGREjVr{LJujsM-g7-XQVq7G?S>>HoF1qoh zulEo_Z-S&e`aw4k)=0)ch`y-;CG9aiW8>E1m}&c}JH7$*#QF$xt^!dFl#kpV@J8Il z3K^sQ@!2IrG3Q>**VW$F(AFXWw)F})Wl`%?9BzZO-40v$0;L_!oh1uL7#<;0iQbsNjk<|I zgXSyl$7kT}s4w&{2=YVx_iaRMrK){0T-{-%g54b~7cY-<4&;0M+o~*5-kK%|_r3m* z^);dMiT8R|#Vc{!lAY!@bk<}W&9W0os9~nz+rFh0Mb_|7OE;nUKeRG*eu>O`^;;ze zkjRcs@>n8X7&aGO9wAAQEZV2@L|-dcPWXWd-(*N#wQ0!D*n%;4MyA-g58--72HXSR zi3V)GWlfJ1$6=<(1<_h)(g5q|me0UGLby>w(tgy^^+735ja0{}ifJA=f@A}YTP42)>5-W zXcpS?#g4e57RW=WG7d>h6a~?eT@@#5#wJ;xT@qJ4QXXe(mOxh#PdmES>x12-DTFK* z0jFUa@T<4D>Pz31S+(qoL6U(t1Nz~Y$Ld(V5ua!BF6`2H@@{1`_9{<}@#-r<=lB(x z0XzJQcpS#u!7h-8?yQF7Kz4Z?xT;Js?i0E;l5>yDtcoOShVF}yJ{ILFd<^d^Pk!sd zq#2X2Ts0=eIg>5--EwmQpJDP`B~R07HEO7l?yUAWc(V$2yhbzbilu14k8yO}@5OQD zW_Z7=9G8f7uzrlgV@WqdVgc(I=rmO+Yc!iv=@Vw4%sA*;bjE+wYO0d2tEiX7vGWRT zw5(V=8L9T2U(LD4;XM3(UEZy!!txZS^!w3Y+xBf;Msv5LeRiw{cWrp+LCRz8i^CNx z$U7Tmsrd2{sCe%(ek@VXavUuxNZy$TQ576|BWOr6RsV|Mc^!Zas1Y%2-XN2ycZ+ll zB3wf24nq-!FI-o=(h#D&Pon;*=Xv={r)3=^<=`IuGI8pdoV=eWO)~^n1kLR>;hMNm zYNb#pln;W*{fAgtUI%=KR-`KF_Q0 zR~Uun<;8Mf`fYp~(F8Q3Za*C<9ceI!in{*W02d09!KiN45-`_hLx=B-Biqq?v1=;UUN>I z2)WgRHQf*RZ|>D5-?_*hQiQ(Od;DU%)kSYA;bxz{F>k3FE=s!UsK{uL8F@#@ zzK+ic(3m2zf7HEfHYkWYDH8<-Np!Ulm=HT|TIdd#x zoi2m&Fjsos%&{!R?w?mUR+z$p zMn|Hlg??0;Gj|G7LnN=xM4vN~!!D2}9*>M?t8+cKXzPUbU&BZ+j=wwhSnNV!$DJc& zIz=oxMEqN#$UgF7Vahos7Y1z)eKr!*UyCBkkurvZFq&Spu`*+tA)HP@YouHmt-u!5 zKeC+fWQi&H;P>|Z59q>os=q9ipe>s3XKKc%t{ZS^3pcCnay86HPyT0lxK(r2@^)Jj zw}k=CO0km!HVa$ADpp0m!tA~QYuk-F+yqdPX(3=@vEGR;%Wf2vhu4&3+$Mitx;}BC z9%=_$uA*6J$XAVn{j~g7UiF-4?l$gVFUe0%f@!N))WKxcxHArB12nnovkW4=B2i&x zg}G{Cq?NMHws4vasdL?QTZENp7KD5YdAp5_T<&__iT*CnjoxLFGY$#~o%A~P7_OX- zT!UjcFW+`U*4cZDPI&U6QpjJGMz-y~&<%esPB?$fruf2sD3x^YvbMR(E+U#II{tnM z_an6ADWGnv@)9OyrugNPqIEnpmKf$ztFSe-(h?=fyOrJB z#LK;K2017;$oi{D-yT2v?Y~53F7tkrSSDJ|e~(%~T$!VKX2h)k6N?EJC>QpKs92&n z3x{ZXVSlg2L0*16?RXaF2jyvjx=w;a7aoDM}K$h^9n$)dY7m!t#{qXOzc8o=Pi>ObIz>YtCI1 z^OhDemJXomkdurs?B<*xQma|mF>zR*QML(=gP8&ggwBqfeHwA(^sb6D zOIn_l*^jO>Tj7Og>NV&@A>KD2mLd# zJB)j;tI%bC`lFEv(;PV+q8~241;Stlwt7aXBxMmw-R)h+UU5$xD z*mR_Y)350m)0FMl0jiMmF?3TdFcp&V^8ThdiHoQ$49e-{lh9ow&^l<5RRXY@bE6`U zVx0WHXPg{3uv%&elJt9YiB=RN6BXxNIush-3vkb$7?C_8_Pajd(2DRG2svRtTmag#CE1 z4MYusMLDW;kx>Yj9v1*b>VPN5@`1{$qW9ydc*yhsw9QBb*u4jMcb=g9E`kEAry+zx zTOZW`Smt=;15Memjj|{8?1Cao@*m^2cfer8-Uef}-zy9T`lC=HQW9q%l9?hSAm&HN-@MY8qRR9;x) zPxv~D{$Eq1w@B>-z62G^)i~`rJy9%mm--OI1}rGdexxgcM7T)U$xw(%ar~1Jo7wo8 zX`5!Tbgex~MPq?34GkE%P& zD#v_iuu=Grxf7YEgpu?jy@dizd8KkTYiU<}mBdOzTO9*Os&op0T(4_nu9f8(mQazM z;&DezOa=a5C3|Xts3wd{ii{<}fi7Cy3KhEebIS?3QlhHN9NytqKVgv18*D6wJW`2( zh+CU%%K-SPF}bPX3>G|XQPPGewfplft*mjcKE!t^G!bhonvlVjT$Z}VFmbIUQ8e9P z-mLfFZ%#<=d<7NDg;ENWO<3G(Eu!4Fp^A6F^0N=NXwc>(P29LQsiA8^jvMLh*a4C)87N18({mH1YcHlt$LH;$RkVd|1yhtdVufM$5b(S0 zbqfLHk!}bZ-_kZdBt6KZUMw!;ic@ZNeSOHDmU(veoaD(+G!Q>ME2l z&+);qI4HI+XOq0-|ij>h834u*NFPn(`@!mrrI2fkGbEJKJfppnEJrNbu4PdU?b7#A-? zcA=>?$BMP$SshX7#N~-jGA_pIlSbh0gfMDY?PzFi0ciXHlsnMD6Yj+%{H$1SU6{R1 zc;aWnEH@>>IEPR^a7GDPD-U#ih>hd)Ko+CK!3ldH?3~dM0Z{W5c_4`!9ITdF zj*1n{8T%Pzt{T%Br`9LVFzhdZv`0NZLcA1;62o$Xb80RTfaE`p1afbNAwlm1j2;>V zC=d=!j???-1cXSBu?DCSPLiup30an9aJj^_e#O`;f256nAYCAIEs3eX$IqGO)Wo;^ zZUuRL=;xCxg+ASnzgPKC8eY~Ig<_K~Ci&g)JBHgAY2VEmK88C@MG) z4}ZV7C0*_oQQ!Jr5xEf7fY?1v!J5QC_46ItGjkBrecMhXkp8!o+`g(a``>&8ZO8$| zpMMn>1_dr>gu3L&J_dTG>8Srq{pg7jpGQOJCPSbC-{88-?)%#VYp{dJBBw z;4`^<61%@8AO{-yb0i)DHi<%SH;>kI`eLvVYzgGy%t) z)%Jdb!lBgF?tW;04?JH9_bT09V_k+^4)upNeE5(P0Qj?C*twyYnK{aH% zEJ2e=H5_2u;uw!$rmw*&*lc|n&My;HC;_O1(@V9YxZHGkWTCiGpioUumyo*hI|G+r zY7pv*#|-p#JTS$To*AG%#>Q3TxGld63_wr9N_M@vTn1l$6We+=o64NAJ(YL#av8q@ zj41p-?&g7RtusnW2tcfu;lak7P13c@B_$Wp(^4kc`S@~m&C0h5(%dARS>Wvxw3{O- z^9F+>TgieMy1IX2=ZQE=q*=<_crX!Y{P=H=o&N-{j8dbW(Qa_dvPghB%>y}`IsNu^& zl#Aon9d5{f?d;Hh_-w|16m8!3{Z9IYBut1m!G%KVaSZvppfB*Nbsj_J&6uNeWw7Bg9T#)n?nX+ zLA4=+a3G1HeW(CB013Dd22dHS5CN1G!VLMUKa>UjP7a_4`@jOWhd4t9&;$5~a{ym? za11bZNPSWOO2dX>2*dGE%xHZYE}a0&uq*^28Q^dj3Yq~%efQ+*24Zm zHKO%t0kOhhAdP83bi?6c8*oOi}x6Ln9R4a`!8gf^O?q6gAa zy99r119?xu8FY!E1ULGwga`W)qeLhAu9OG=5|M;A`ZZNg{FzgUf6NVKPx92)EpZRw zB?t-sSYislm^0H7=@?>4zl3)Ir5DJhGzn!iLB&VJrB;arG(qK0LmR3DCpJjz5q(KH z)`;o_Z;4()nA$Jn3`e37?Jf1pv&0y!U-Z%b)3^>2|1_?hWB=2*-bd?~e)KPSihUP( z1Y07B6{2{-Sdx|qrh3UfW0nY}d?8q(mI$W)WUop7VXxEvVXx6X*=y%d_WE7?5o;+p zc7W<7>P)}n_8Ui385kP%atxt_q=XU~PRdt0s?X^Hr5i>DS_TFZ8NLEXgbX#l97lo; z&k}4&ibQFQ6hgtl<`_Q);LN9z=M{x-~Y+jzq*^d6>ij_B?-%OR-^i9XNw z6A@4MqgSiO1)LfL|4RtZ_ZM6i!7kPTUZYJcWls&M)*Oo(bGRlpW4_Pzj>?wAyM_VC zCQ@HK$Xfi1&lQa(83xqxorzI7Jd@E*v}+< z^{j>kn@t00*iYY+xYO8X3TqO+d;1lE$=o!w8Jp#OgI$&ie?dC$a zgXPx#TRISS@(?+qm?Cl=r&BaQrSXkcNWN;z*l-QfK|-`EU_#XwO`5|eJhW;fZl*S7 zFr@|!VHN7aK96?WMzn%6v}lmGttV(unw{KC(bORp&d#TvWW|i$)Uoft#=Xj}d>@DY zOkY9#EnQo-mi8O@yPk>pY86&(UMXmSWOTi196m{d9O8E`FgQ>fLiUi6H)Uojt-6JI=dBZUCFpbz0{C&c+D}3WmXFo9x z&RQdGq@A}*Vu%Kd^C-`A<~ZVtH42uXu~>*1OI`y8<5yOMexTAtdX@-SW>GQVFzJwO ztKQRQVINHqDdpDE>2(pu(lUcOPJiM-V^$2PMUuK9Ng-HCyEl7X|24U}X0WEBew551 z4PlS)mnlq{0DqIOM@D699`QhA?sH#C0&k%eonV@f*Pe*?cM)@`%FW%P4PfpR} zIIvF8?_RX9sNyyJ5yG1+5yEq;r0=72!~+2_(1Yzi7ZGvuNo={*+JF->ES-iNjeoR} zP;HsdBD-@_x{o`H1Zn5%;&V)gZ1hQ;A-tdYq|*tvrA@q~}DK3jgGw+97VhEMgFL`J9`KWTmz zOCMFvnO%H2gyVy2b2GAL;HHIkx$xSCAOSiapP3k{W4 zEfHw!El-9K-|1m0qsu|yyc?l8*X?f0mN9!6s#Tl4CnLS#Vc%EFS|F?D!IVgz!9#^m zH&r-e)nS$etyV2Dv4M4aUCu<*zyWc>zo{UpIpsyg>L(GDr0@UY?nrz#@R3Y(64q(B zbb-fvd$ z4cEdtfqkm_H&LGkkpaj1WKZt_oX={#FXs*~VRKV(f&4>vyWN~}Tzozj9}e>#OFjpo zkuXs&A?t&8N;sG7C3>+)pC0#YrTkZ}4S2+r@t)+M@I|O#*F`9DTI2;ik7~HX`O~W3 z(KU5{X_~miwtL926LU4$l<$x)eEaL4jI3rm`O)~ZLGuc=fp4K8~ zA4ks3igBI<7Mpz15&3(flR_?~KMb3a32miZpg%gxTSZH27Dbr)pX_IegeC4f3I zSyImJYv>3H@j6I&Eq033_R?*%Hil*=?Ag}r(&5h-OQ!k#|A(=Aimoi$)&*Rt*tTuk zPAax-+pMbCww;P?V?`^ru~M<^)XClt=ibND`ty95tOkbr`2M zHd;{QMqST>W??<^c*+u#y1l&Y?xiG?br zS)NTRHt~bjx79L-kU#SHowR~tZz-ixYB=oHe=vlT=-yBE5*`Auc z@zdR?o4$jwyz?hJX0}4sl=#c;K0@PdDPSrYFa@(h>V_NVrSdlH=lj+P(qX7)%!}2# z@%>cO{taK#Z`~=_MVTj~?m5El06|0mowqH)6)pMb`|8U|ZI3g-w-qMZj;6~E<-DL^ znwf3wLWK3hLD9>hj7hGi?v3vVs^DUnN0(_XV^3)c z=XyV3`)4e$G#8E-X$G-T`cuD@uQ9iIlv*vjzTQ0Qm0?BO%+;ozShwMRf}zq%jw-YC zbJ|17pokH7hO-~%RpshruxIN$zSi9r-P3V-eLZ~n;ekp|u-8_p0C9sM@(tyX4KP6& zBA8neULW4h*LhHoaI)S|r`n#m%cP02V5B!8UQwS33@i_y_s{pOLKfS!n)YnP{(aIRS5a94;g(iZoKEv8 zS)!(0!=;4HS-V!vV@?A#)CjBp{k2>*(&HzmP-}{IQeJP7(H9h6qe{3Kkov(+;{=&O zMsM;cZP7xQ*_IZ=cswm%M2|XJzMU0ewyy}p%ou2@p|;5LqPIY%RGSb-Zc|;qgQD)d zWl?F8cAYmr6f7c573gF(K@wL|#hp>ZSMAY*wq-`H{Xu(xTMmj>srL2bN7CfIyb!%w zOR_#;#qMda6mz?n%8|hApkY)H7)c5-GjU3YX%aD}maitFNnox7jsrqS3g>r#8D&HR)}CEaiImimmaT zGN4{d_3K5|9L*4ilq+G)wPCkP$28$|FqFT-0Skqnbz=gtP*;W zUqUzex|BP^T!X|YDxtKyz}$@lHA=3CJK0>M1T|`|gge{ZxI{Thu9!RBT!lnAYOa(! z-`t6W6-utCJJnpKgcWM8q&wH#n#2)GuDCnXT!+LFYOb`q(At!JkVr>25Os%~Ln2{1 zVg=1Wt~uG7dd@>)1=T>wU2qOjf*a+6Y+cfwd@fdk8})1J)8rW~*R@o$Rkjr;yt=hc zxSs3it+Ek&6alu4(%#ZVQ@Qy$EY(M|wZ66P*yb7U$*g!z{Mxblk4(0$32Ap3Z&ZyT z50Wm0+3OHKj`CjBT-nJ;33>WmLhs+!De#XrRbm8Hqug!a!QuDcHaA@B9*Z&JjQHp^ zYm^H&ZPO(B251$A`Wvrqo(rU+b6A@fY6F+~7F~{6~uRqTdsval; zn;;0j5l5s24 z<$GBCr`xI*z#r+*wF8u`&iklE&mPe`GQh9oHp=0DyP}(tyQ;jEI&LCvjd_Xg8$OEl z2`*ee^nGtROUf4u{Rn7cxT>MXD)Qf#a2$rI%WSG6#e-j(O65?R_m_dEAdFEbjCh?4 z0?Ie;WTa&f!2^z|yMeEtGQt6NlYH0*Ley|~=%xj|Y14s^KR*~gQ^VJL{gk(B%|&6h3neTJ>ws6f zmOM^wL+N>J0z8t!^*=e)V6QQ}vayL5wo-^iGdU~GF#YV7_dpO@0L7}5RrqYHa`|1{=l zIlFJA8E)MmOar04F)B{t-@g!$1ji1t9ijTz;_udqkKk2^5z=WKy(uYi_-3|WTpZJz z$FKn4+y*9b$adkg@x3A-ynq^WWsaLp2qPdFG&I|VK^(VT^9*yJ0wSMVh>91xQt{__ zor{VWouLuJ>e0G!Io1Ini(IMs3%ptakR^7C+Mz#i0MrFe8vbOjTmb4q;;Lu!`+bc3 zpuldB+MJTIKi+F(lvY80$+P=?GG_koz$g&=oRWq=)~ihvaY$e%sA+CSxf|_69&l8U zU;3{eL zj=ku%fA#9!NZof~ls}v}0opRXZ?$dz>9EI`Y#L@!O++uo^AV{ zWZ{uTq;I8rU*}zKn&aJ%$*u9urL+enPkaFfVdVJ8BtLa&7WT^?r_blz7d_0lp`o{( z&qZci0hiZSwU-@_dDE%5+y+i)W~(#VB$Ny!h5eYPL`>z7pLdoar-)7Ake#=dF{6l0 zV zr>sfBNKvP*FjW1asy&aIM3z*PWSWFW!6~boTg>U3T+)&hm(r{_uadMZXPee6swyDO z=sMjz=Ceq)Q7IX>fVC#Z*vP5-_iMQLu0~_JO_Ntx_u$<+^{!ZBI#hG*t;SWNdBW3i zVapd}vRumwoOnP2K%L}9AucCJA%69C*;zIQex(;Jm;9BceS4m&eMp|BeaUw5D$R#A zK0$8ysw#2Q&WDu zKCe1aQ!6u?_P+z;Org(?=vtM9l^VqF?=baJv<3@(TDAK`8Yo{wqZpUk=shz66HS5l z(U|=DeG&}^ucc8w4?v8nd1kH2bggvT4>-X4D-yu=o*uJmsZP~CG_b`K>;n&=dAdT^ zD!Wsmt=y;B!1v(`IDNp!fIsQNfIs7=^9%`0Hbwog1QdPsH{f0m({9#Dty-nepke8i zFpBfUi>_63r)D+r)gY>7;Y#!TPj|}MohsK+>1M%Bv9^96x0T;o0FLQc>Usiw3#pcv z_+@aIJ~d)TEw1Z7mcK-{W1MpdeiK9;rk9CT$3z|ZSBYJhL>=UpiToggK4m^2Or z)qjfA2%dcdM61BZ!*kJKLGz6vD8J!WX~f42hj{#R*o{1nRkc<@hk7e}zh&c@wa4y( z$F;|x0mJ4CYAC<))_lBki;Y0bdM*36jse4#3v4LAsa7MrbB~Qci+XPRx0ZqJ<_m5p zKVa()-nqlZHtT9v>&LY5)!O4*cl#6KBlLz4%PO(M+pO`=#tZV`kG0l##7FFnPuu#w zwa3VTPsfdNsJC#3eBAT=)&R%)pKFhy1D_5X=}>R+4o0}=eXRiw^-lJ0%f>r0;FjN3 zM-XT2-Efr6vlqUlJ3QB|wxWT{I=JC0Tk3Uy1>57>_oHmMgNLniP5# zaoE5CA6e&`{snH2@6`Xh)dwNNctZl5YK?2{7j3Hor*W18CX{@eLl_vlL$*b~XzLVL z!F($()MSf89@w3Oo^k&`DU?bq*R(&-PVZ z{Z4wZU@fgREF{Jovf!F)SR4h@t-j!5t)YlKgRK!@DjTLy9IMOL{ilH&@ODIDRK^3D z$V0luT8%a^(%=2ymX}QY$E(BlXc`}2ruvUt_4@qwh3=l{J_p^;Lu|&Ny zj_%RC-|=fr*Svm6y%sZW1CK7bJ^iB%*e~jj=tAK=!`Myvx3-ULbymXrcB}N=p&vP3 z4O%ajkMMzLezEyOf#b{;b$7YvTJKzsP@@`g!Xw*%-&UQTtIioevECT}{py(#Ho3ZH zUhBfM>RZ@64{(5Z3qCXh0&;+gVpTm%E^RB);%?Onqc}t9wL!(|wBxC=QtVidqIE z82ZIe6?B*Zjx@?f;|eiwq7Ba^O${?@N#mIVMHv@exacC-PUt0`xz9@D)eR9$;52AF z8qP9&!+R`A5Qc>qW+J(7;yuTJqtc8cg;n!QMKYG9^AF+(hJ~^HoD56t@pqnrV>}!q zcW46b`>))T$AOTd6%*6BH?&p==F_6 zM0ku#XH8PCMU*GQ_!=-y0kSZWoG4fq&LLxB5;@;h8VF5IsX3wy>ZQ)ZsB-x20BX)9 z-muG&D|<9IOx4)LqD{{TToHAohUX#6pn+LU0Vp&;a$%1*mpcY?&@_nd2Ntx6nG3l+ z-S#&F0DfT?54<3tynha`L8{h`?i=kT-ujGsOdp8Kh200H7bX15EJ`@Ih7zGQHD#!Q za(}ly3D?jl^0mxFdy}^0N`krPuCOX6+KjNeA`~ueEi<}JhMsp2JA{l_`t(uq;s$z(zz>hF#eWk z`*;tQqo>y(id)f-3qQ~>MdWiQdC^A4g{CvouBW%@4DQ?_&4n|S-^2k)ld$X;*b zfN@G}xS&PT?q?(5T4W7wRc{#vIjv5WNqN}@o16tVe0kja}*Syse@&@ySE+p># z>sn_pI3yef8C^(vRq|P24|Nb5#)#sa%0IF`{EJ)%hSZ@Dk^84!^X%D$)S>5*_y=Dr z3{vdrg*c(-Q3yz`%B@PTDtTvJ6MnJkqJv&vsCqc8G|UW29;JY^ci#2)J;_12kSo+) zCGRf*V~{?C7%fnONA|ydyB6$!{dT;)qYxvMK$&OEFP*&(wvV)1^h7T<~^;-FS$`gR}&62J!iLWYFWU1qrIf;qxy?K%WR7={#m)4uhvpB%= z@P!wDzNJjB){^2Ebv|MNmtIMe%lhSTwf((wST(a!7IL;zd$&_+xXgyvAC}$y%cV7$ z_GPnW##$@)blyQ7>bfSr6v+x+O7^(&N6FK>ICgYo9i&#(E8|x8oqz5zYJoBIDe)!n zd*|K*<4C1$LvVJLc0%^32a!SS%^kos-I%`~dc)0s))`GF$Kw{M;a=oDOAh1}6tsUw z#cJ0!2@i=q;`3~FmF?Nn^%#hTO0Fm`rk2&^JCC$)P9(EOAjOr1!!dH=w+D9&%&CcE zax2Mo{>dGTRP6MyuJ$Ikh@AYfOe=p}skd|1-63aVaF!X`>f&!i#+^tk>t*TATqWF( z$*|=3jx*p9h(HQ}_0NERAdfX+{sfI~JXa0MkF(}5maJtG{~Y3fe-jY&5pD(fhU%!= zlH_}N9`Do+4nE0@n-4x6oSYzdJ>Php8!Lt-BkB%|0b5`s)>|S*pqpW&x(wzHvN$@S zV=M&P6{CME>qp0l%%6LNHe1JMf=7DK3a;$tEsXl1p_;Aj?93F^(G-DQl+GXylO59W z$3{>$M?gZw9J9iPy~d{3Dnmy*GZZN#CH|7(M&?7C?1y4wYe9 z#dOn>L^Ynf@;&iN{isd4V>bj50yH)q;(4)8m#3fmG{csktdmikvH~A7C;1dE?DqGN z&}mGvTA0jz31MxLf3$BjbD|zX|2>InpNblZv1nfKj?5ZNniC0u^h3&gMJt26k!YiL zU-kA=D)$4UzpvzWw6#*hiUix|V@*KF(qmo0i3ok5!$LlrTfsbsu`AVET~}`YNHHpT zJIAn8dbq@x=JRO29h*4rKqU-}|2jIrX_t~@DFS2^G_lojQY&+D?F3QcDf-f^JpYZd^zJs zA?>EfU|PNXZ~pP@2zgv_$=VuWTW)>wov?g(0cA3A+d7WTvy^U7o;h= z)>Vy<1aDfTy8h}Wx;Z+za7rI;O=fvsp4sk@y^Zu zD37w}DeQx9G!$!((WQ0LQ?@V<<_XM&sP22TMf$edIg{DKavv6NCVYF^A1TUCB~WRr z@prj^zh1i80h8z7%DpOiqh;L8QYi!!x1lGp&-W(zJ_Rs}7XWe$--oQSg-Bna04kP-{$m##Jisj$OQg zU&dX=%Jt$b6sxrDn%8gx^}DG-XAtB;20>dvDqrBc??Ah;7z^zx`F}9@Rc0QNcF`{i zJ~l`T-jKXq=2{o~!C3Qku1fSiJN$A;Uj0_T>sym@^qMtD<5#&XgxhR*hrr9s9;sk_ z_`LsSn41goOsxSAa{QjZz<4>*9XH5=q2EpbePzGg9bG__z%d%3hdj)y+Az=NtY7W&670 z2&X4X_PL|J9ddtz8cwqtPNS2^L@y!vV*pMI@qp!76)7OIy^ zB+MTiEXd&k8}|?}>EER6!FuRTP7a#M982f)Yx{6`*|uECWj4#LYuQ{f3+D>Stu|=r zKaVz_4yV2an||*6d&_yd^u6q`>VqG56Bc^a`<6i=yd){cQ1HWDH1ZhOL818SGM}Gp zt_bDKri>k|zsu%V>dcmrOsbf8iY5+V31iuWtc&I_h;fceWRk}!ZWqwSHq&2pt7aOx z;ogFzH5H&ZOSF8qmu^!nLI4dG_$WSbacos`I`yOfMv*@7PR?Y%CAt3!E`dr zP4yfj+QX$%Ev22rNPb1K0v=8hm-=9{cbGQqwk;@Gw*1dLfQ?FmlNyM-X_FJ<8j05+ zhD~ntVWn17*~{$C7i_Ox^!K&kwt>}6mkQ{Wy(-y+~Z(Ipgq8e7Zts>osrylFfV6+VloL3Y_Y1b#sJ1ax^D!0)eJ-HbH1@Q5!iR zPsgqy%1aC{UceTUOT6{|U&E14A;n9tDCqW?V8t7h{m*(e0T2d%hb=aBSFWj2&MN&Q z>!N4+G0NM2&<-Mx$Y9XdQTS*Ms7=u&0vMi~aU_vcHrjC?q9!oDQ{KL^(8&V|3NET+ z%5#ad0$lOjEHOA2b8v zgyPwvG{klqR=rUed15r^CZygrk?Lmn9PIGgA2tH)@c1ZUU!8%#4c@mXg)sg(58#7} zd2Sk>L)`LRFWIL9raPEmMglX^bzv{kl#Pb)!xT+1LV^S1P)JC9p@LdQ--F6*DD5l0R}9g-L0WJ$U;=BV9?f zkcu$JFrWmq)5V{&CnS1fHo}rnfF=}1uI*}NH(n6<`3vp76x78TB>^30))2*&mNIjd zK~X`2@0I=`B}pEah?hB1UT)%w7PD6ljv1jSM!R-M5L;6Nwq9mc(1mq)YVPYvMNy#n zqQ=U1v{SPs4a`(bEKD+r%G;#(!9h@CXexj{3I*yxqsd6yJbBzqdfLLpG^ z9;iYJ&cvjr+-oZ;^C?EegaWetXbHV6@DnZW`W;apl<{|M5p?61EifhOMIN-!M0;#g zd$&l+^XKZX3`ZHjKudbF^4`$|s)Y-hi+iQ^;Vr92Z&S3cF0=48OZPobL?rb-swk=G zT^0m4O?{Yp$jnrytzn?9Vv{H`&wwep1Sn)9X~z>7fKw_SB`m--fAz*I$9z8hlb{T8 zcuZ;Gs=0Zt+O)$HWRU9B^)hSOxH@RmsDNDY1&1k?^ZyLX@wi;(t7ATPw7!0JJ5JuO z$<9&J=kXaT8P{;c>V(LuUF?}Ys(XA^$l1sEj^AxLE>rs5?Ir|4Mt0KPsfn9M3$qIK zb@5e~im`rN0upfH3 z?kly-9&OqZ&S?2q&sz#9xvP31>OVu1n%0`;@B|+v%sHe{dAlDL1?hdCK!=EzQgx9k zb7i_p@bK`6u8Y}C=J^;=7yy*LidNp)V2A6r^QHNKxdeSG32)M7M1N*&mgNiKh^c7pIz;bwvV91*}>- z@nu?)7RX<-@!0JI))-IBLS;_3f0zZNnNmIrUUo{}-#xGGLTW!gR{3+d>0W||C`q%6(0KBvELIamUH_kmVpqk!?Lax0oo;TEr)&nJtuL5IzAW= zoNUn;#8D&up&Wqs{V}6!7hDslD=+M1tmB2O80Zihg(P6Ik(Eva@V#GV4-xSZjHSRT z&z~Kuj4Su$l5WzT8%+XJ57yp;MT(_F-#W92xWnfGEn0+~Tw!~EfU)7a`NrF*i(}R0 zC zv7mCPhznxMmeZkbcsylF;~nfmFte2cb@pG`>Eirek0LsZEI3yxjbdtw7&&)?qYj_E zSiRqm4qc0f$&%VndloEd4~(}V2Y#5-!_l;Rylsi*=Wpc!9+nH*SgAJ$&kN>WK6j<^ ze+ERROVU=T8PygWPU{i_AQ!L9$({B&j`{jOBjmYg$F27eJSW#EZ<3^a4hZ0w|P)zWeyOMR!k8(DsPSGX*gf6>+} zQQ}i)reWTfgy3!x_uzQR3bu=E_qd$Wmysi928yn^6ll)P(w%1R%h2QzOz2!>ft7<**1m*tVVvYeLUxF$0}Crop`RzKIb^Bxy75)Qu896pqA zd-(R?o~pzw*@R7CDKU-)de~N4oS?2ZjuC3hwW#m}&Nl(6!nT>=oQu9^1Er#@T$Rod zJJ*UK{QM*X0aq&g|7u^i5d&IrSz#op`Hj?-VP2@Qi6lu;BX`c%rOwO;G*0XuR(!EC zP|JJna{Ap!Vgzo8mil!vOm@-qZFk*sOm^iJZ+SAO5Z!pVv8_lDV)TvfeAh=Z^jZH( z6yma_C(F39=@fo90$S>7=|%@E7XoR+a-yUWs{3WZxp$>*C8$?7!w4Eix*WmVc4rWI z6%?g2yc_jA!MC)clW`TdrWrp|7!Q!K5 zw3Y=GS`JPcXA>k{f0JUfF%3t&S0+>a3``}(-eVHS0s_JWmLSyib=@0(Sx1n{;V9FB z6{Thj&t5l^_%Ms7-9*5uNQJz1E}V9E|0_at zTo0Q?-DzjxCl_$>ftM7T^wRrgy+34{UxrlXv+?(?9F@)n)bM8`=DH;xTEz z>&*p|nPWfbY7ocyS5;pm(T^L&K2D7KzT}O9O|3V#aV_lxkFz1_ssb^;IH4=unzN|1*Ce3ttr8`i#K2U&Jz(l zdeJQYAMF%Y6Xc{I9c|? z=K7)Zu2Fjs0Z`!l1Ap4d%}V)2Q}nrEwKh-+Z1kh)_jlAlrMX@b_|%fl>@yt!;oUPG z$KclnAC8Js6H-b2W~jv=&d7Wkn3!4rmfo_hb04v~z5E3VyaCPfYHv`$1yR!}!7MDt zF#ZiD^rfWZ-@+}&(;sMrb?X`iC*UGRbqO8cctM+vIo#@sG1V0;)yW4JMVr>&imuRt zsV6PzZ>(0XIz@sdvT@CzVI}>+zg`LJHvEj*G%!pr)h(CnByiews3zkcYx0oUY6B9E z-VLBqFJgRGtzmNF_^WVhDZU*fM|-PhM;Jww1rJ{bOlX_fc&-K-0Xqi(8$(Y@^2p-b zqGgiX2Oo~I&XL`t2@bc0;@i|$+<(DuMZt+vk#TQL zULr`nCJfB~4V5)y5J&}gvF_X=a`A<2PK8}^Ky^u9E?Jb3KJ7^vwBk34UvmEi^B+uz zhlA663l(qi@7w9g+*etDVWWaZe8GRgx%iFvqL)OmNrg;`Ab6P<6LL-gT1dV>^Z)wb zhr;~z(H@m^7*~EpI{~3>A)36O&UF(2* z?GuUjMo7%KsJIy47$fJP&-=rDg~od?;aU}<<)-7D0&i2DdpaIG(p29~Ecf9Af9v+G zprLBHSol1~;HrIHMZ&w)c#%fC**@PK&kE%=oRjsePQFN4TXXYxp%(wt>9rhNxrt1U zO|yQo8{_7Q@mK4$7;Dqv*dA~VS?l?RZfc7|z?%X(^d%SA7hSX@X2r%nI~Gr|D@4H1Ib_U z5}&^Pjqvk8Q7W{Zc~eN!0ESCWq8mgHLHEpg6uq%BLW<|MHDbVo(nkdoovFL2Gb43J zw8_>k{uVVt&b*jnBt5L?#OY->Uq_5v71n!-;H9jL<3Fm687Yu+;JL zCeD%kJ%(|IL!4}<%u7fX7so<%2Fg-F-a^Gg1=7JpwTN^o;Q7zs);wtM2OIxsT3@&W znbTFUP*c=m?5|3%?}7^G9}EHJJ#8Jei-gq%a-5}?{jdI>cD8Fv$x8zo{UutlqY4y@ z;CUofJT8AWGU4}T=Vck$i}e3Ub(qF_HcX%=4mY0ML&?67)OL3yuA0v_qe?Ocg!1_n zZEI{(H9e6TRSBb95~{eby%&{I%w;6idd|)2uBmS*ZF54*t4V zJPOf7KI^aInC)jq(j>~?-qX8@b^O_cmJb#qEX*I}uU@h(7K%4GQ~VlUMP{UO^A6}1 zSAcK1gD*k>i{ODgz{He<)S%=F?rw(XB$0x^dGCarNBASGih242P}~v_gF-N?}#6Ht0!2X%i`)7_HIdPXjKU8r6`$zcGj? zjEjt8B1;pnc2FbwT~Yn6JsW0ZcHfhv7b?ILenU9a(4ARfyHda7Mb`93F*S~FfMzw4 zj`k*-pR4ayI2*P2(~HLGZ@H))H_NJ(t4PoBE92Yb*I{X)J+n(UL9-m~GskL&gCh-y z$rJ==;VBwRA6QFg zOqup#iiay=h17`fiX zQt>_zJWT6T3hGaJn+HB&ANmoV-CXTpD*d$3_%)(E>Ze*8$MD{rMN4%+bIXVWxUJrn-B>~g76E)@)tD)^oq53XUI(LuIW?yD<;h^zf`KHW>^dG#gvm0t}0%Ky}!s;gn z*L&P=BTkGJ1u1QRHYKUJpAR7{9qDaqx!|F_9=)NYD0_MyAr17C>29%>yk4ea%WD4rKLsXllLTIDfHu^eMl)kdh5K zlBpOPzis7ga>Z*73e`q`3Y|Me2A$E+G3;Z=gJyoxAQVQ^C49;|khYwb?dAPCe>+&N zSkUZrT+fcKSAqNm3}0V&v)SvhmRasoApE93eB)XSDNq1^ZTO+Ny>>=vwJmiW85#6F zk@5k7^wzmdsX#6ih)-h~0eo-Pi9QJU)mh)HU$!-9JVZ&psQG7Ga9C~M|7!rFZ;gST zd#r82+&nYlH;VkBvAOifNJ%m#Z(e_WxY&#BLV_-<8V7w%x5GV+W+a3|oggo22+VcW zdJ*IcP_|N?WQq9{X-M>R*iUEMSR*-vo;#FfxU;zVzI?(8F29raXho%GZJ{x35#vDX znrmlav!9v86uhQ-@9>f0{a4c+iPczFjyIVe*%~?KtfMM#&EIL4>MdHXduMVKL*wDj zO8;fsC1Pq0=&kL;Uu*=C9yN>@OW}sRjpb)%S~>*y_!r|Yi{T@IO36;a&{E&TV80;* zsS`vNe{{y$*=YRRqWiT$xuqA;*)2!!BrV+4Z2B|&JPYroScwg-PO ztU)KQ^Ymjj!G66?t?Y=yWn}oVN zLQ25p(fSiJ~X6zLPz`7GO{ zqSOQttRi8Z2#i4=9GwUiiiyk!mPAc%OwN{8u*1n#3Pm-%NVq;rV)gqG$XHYY)z+G9H%IXQ#< z*r?YmqgAAt*U@KdR7GI8I7(F);CC#ja1FvaQQ*e7NI?rOEQ@>2)`O_CvWDL9alhT1 z8T7@3cuU$Gv&z9%&|r=`3Ru?-ldfKPwH!x=72G~&eYF8Q(c>*zV__zY35#=W> zP0`rj=z!0bPlM#i)I&Tu-*x_;hNml0 z`E<#OTWf2@rY<3ONv+ab=3VZm%jR936IB$3Fkw=gox?xS=rVwbNY*NLv&?bBzX@~ zo~-CwE%n#MFYX&r;v!c#6(5)zdj>}mqfS_=eXOL1rXR~~NyLKOV&65_-*qCb_SPh} zg_NW8*4`=)D1Q<8VZ0_?NDru}3sASXzh)97-s2uK zX2j7xf5+^>V^DTWJnm~~NBj(P^+&9{L0pY+N~GvT#NOj~=In)ccqS4Exf&vU{}#6! zevK4}aJ5%{4I2pcZ;+V2`jaN)tAdtb5HiG3RHLI#in z&s7JXLkj;E-foP!7%3CiVGMIQfxZ~=<>tpmywW8ZzX4LZ+N5vot7req=^L&7q!EGC zVQ`;Z#WY4$4NJ~*2E2DuVJFwIzU#Zr4pEGyuRxK$f=8(tx%wJX5cn^V`CdlL^y9oA%VD*t-92 zShribdPr{Amon=Cqo|R*2jQpaGx0BiiH{`Ld~qhjIIRR&nc}b6Q$lT-4*Io^K}ifu zLj^Ead=mct@=eY(u+BxaGdCL7&5>*&%4P9^7eR)1D6CU&hv2vsNcZk-B|Wd#4_h?I z%JStqrz~60%0f@5kub1DfOjNEfQp}2YA?My+dAn8hx7s2j$v;YH+&uKEY%fA zz2j*{6V_{PN`#$hCN*vtH?;>NtmK-vUxrlyKAfYyVJ@-a`+H2O1xOzI9UI~ibod3x z`F0^)i+`d)?=pi_o+Su^>V{38H3bxFcV%KwXN+^aHDxp)S+5Lvz}u3Oqkcov#B7W5 zZmSJ%%%jC~-v){v$lKt;8G#h+A;x!mqqymzkHYb9uxveOVDVsBh5JogBLl2Qd60ho z!W(v?twhco(>w9Pm;70VkqFRKO##LouQUtC@KCQ!Tkfbk0)fp#ah~n0N@un2+zq#O zeJwRwBZ2K5gpO-Su(TLpJ9xNT^o2ms=|+)gXAeCEU4n-k`M$>}hjil*!?Hs3iO{{G z?ELy3lbi9=V;8NA=W0TiS9>`Ba7ejgT;UpD0i)8)nEaet^WO|}Xa#4d#{HsjdzozH zNQtqPv4ctZVs16AVTkQP$1KGs2BQElgf}^!ZD1)HGFrv4^r120VO3XPtG7?8lu6t zDAt(SE|>y<>}l>OkY6aWS`BQXglX{R7iK8~M?6en4S(t7868IHoCO(u)Q|h|C@R$b zipN$OWyh=Ul9sH}6KqY${U6`ctmf;XC+&IgRH(H;_&+dr(Byi9$!@@NNCP2|9gLS{ zLX2c#S7f0#Y0P$s*6l;c6S(-l+YCY9kdpngZWlo{=x>?bQ5TZjMWDKdv#Yvwrud2( z!|-wAOMF6oWBKQD#`5zc(3|DNg#Fx)q8QxM)d!o{NocTROFrLob?BwXUa{s~sC7oO zcdI#xFlWapOEGn42?-hoRBQ`15gu=__-I7+i}X#b=o~rNf-NQ$+&GB<#_fPan?bEW z7b%S0oUS@iJkoxMOi^`tgPNA#MJpv5(JDO}k(cTeFygprhL~rTiww{$KgBheb}^S4 zj+CvQD$zbLd%>_^zHCw)p5{=(rpfVz0wE2GqLu9s6xClf;I+E+mF^TG@#HLl#fSGu z5)+YHB@0YbMomWZ9OKx`aH4HAh%*{fIK)WnY#5jp7Cz&P{~;U(51Ax^ zv`PGP9!?DtPA%6Icb%vYEzr_L?}!lrMDpf~$>Xz6q6{&_Eo{Sh1;XJ_R2gRoAiA2z zGWPM7y!Q==!`+O1T^4}5`3!m9e+~)tW`GgTofW`EQ{wqCCLF4yH&&-6_Z`PYpU<;D zv3{HK#+Fita81P9msFuP+IRy7zZjKDDi;=KWH*8m1D+89ty+gwz-V}_@Lrr4HzI?2 zAdh+g4LSB7!|-=s^qY_q_UN>wClUd*Cj2~y@EwnSH!Q0_qpSx6itC_?Yk%nXy@V{m z=;a)XTHeWwf$qKpe4Bx6Qkl=3=3@ra3C*#D#Bhry`w&Z7D3Vxq8RI6h6B>j?o0aN4 zw`V{21=uvP#B%?lDn5OTLZz%4rJ04mu8mdf&bS`7)77sOaNv2q%#Y;m0T0}+J%Fco z#b1(c{bZkShN4lcMvSGK#HbTvpP#TM{LeIZRv|;zx_N0ugkdX79`pDvu@-%`A@C|don8eFEN z06NQTO*C;_G;z=snfX1Ez%Aa;JzQTB>^k9X&)zU_cj353yvLuCwIoV@st@LMQ}H}z z4F-7%_X<5Mo2Pg_*Wi85A`sm0;i0rdJOi1OGI+>%PL;=ehTd+c>*Kp}-UX2UOjn0} zQ_}U-=G8Bh`KQ+a2+!C=r`wm`3^oh@0^UnPPvv-FqR%hxopq7TT~e=Q=%BUq>RhP( z?pVW^4R~k=M7RVGsi$?K@QD@LRs!@f(1Caf!%|+^sRO`mzk;B@Cyd`Mln!AwkClI-1h)s7?oCq)#RBx@)9vAOfchxJj|QvJbs*+ z_P@(d`G1!?pIfPM6&!7Z--GK z19gVikdzuSQ`=+x^6%=`6#p~}iHpyZK3RV$V;Pz?$B;l@eb#RrK-Zaj0iau>^ z$1iO6#(}%o;G@}a!RS~ilsmgTDL~lBIBCNxtIr74Nh~%c<3`cVa5N!3WM&)5b56^a zVveISne_Q(Y{@;7SX_LvdWk8~9)$Uzs7!Iz+^>Y=BEb5&-D`F|kcpM5iHAw>C|w=X z;rkxeG1ol`?*saA&|DC=-H$mJE&D2X&cY2umpLx4J2Z?64peYnly?a-&3uznt1;DCBMw6tt~W-SvkR9_XKWa=4$^+ z_WMxLwQWuDnI3nM*XKE;z=q$@@MrdFG9q>tWq`sOKzyca8QbxZ?)d<_QDt?1im7#5 zyL98ZbW>b-LjxPwAgNM2{XK?nA2VPjB0veJFcX-Z`vQn03}H3PuXA5{=9cJ%4mh3# z#t~7GRKl1IWXuoA2K^1OK57(r$Z>}T>MlrjNM}#l;}Kn%0L7(SFBKCE_WKD|hrPDG z6ISj&-k|f2&UKw|-ip)cQaT7AFJ!SX{7iW^TTO}uwST6$aAU4fpA@$mrZho_TR1by zYr~>6JTR(S`e|yh(9UV)Nb{gf&AiX#ffMCe*FClNhd6BSxi-{MOE$K+L0sy8Rkd)2 zQ@-t*|@Fgrp_#j1?1&f!EKnymcG4`kL7NHsH}1Cg}1{$&XRMe{2VKvIeGL ze+B=dtzWb16vK=w%zA&X!P}GjdIis6?4`^OfvjZFp`&@crR_OjhI)txf!Xp+8 z%+zU)#8ai5xkSYNx+#4?*khURHU6S)5+CLH$J|PdBEe$rx|5@uYQm=EBIsGP=Q!q~ zkyeWV8Bf+a=xv-(>t|_TB7kf3U8d)3kx@?CjQLLcm8GPEs)42FvVCwzh)VHNiUgiIlBq-^nYruEi%fjL&!9q8)UlhSA)xNe}EbSwAW@Y z*$f9Q$LAUzF70^nNOaUCws*$}E01mJ*J_uj9rjgXa8LDmNfi4a-s#@Y|9px59(Day zFo(-Ar?#jv2T@p1h->C*poL`(M^jI0s++M`UsuMN!554cinxy(yqA(uY+ig)(4X7$ z!mwH}hQ~=VfNYDHXDu+=CFm*dggS3jx1QAf z2{C$4IVP908ByBGLbyD);RchX=?D%mY@DIP%o3 zRT&*nhzQ*Ww}lk`#@_K^d|d~||Ef!&_C~K7@Z6x=qg~AU(|HkMc;>xeiUO93M5HWB zIe`)6#mS-_367a?vIbiCicguJZO)N!TX~GnX`BpGYgOLE;ma85;xG@8V}VL`3sfXH z_zDgVH*=3*$Bh2@{y*BA|I3rtIZG8Gi1g!!I_ZxebpKyZ9;-OO)XGH0)cwD8O@+zs zo;s?l!`a7XSr1_Ni^f0wy==#pgYow}v`?;NpQ*bY^*ck{tZ4xZ zsCVr1KoD3yx7eQWJ0NlgYxZ8(RBtkL1|iU)Y5Uh7*bcu-4sdknj=0M&C|dMqIz&A( zphcAn{JbT&JnFM`(=v1hDe!L-2UNzyE1oYIh^@(+u5Teo_wXaRuQHf-_9Y^iJenKJ zx;B_RiW`l##Ez41b8V;Y4xFzmPy-QoC*;e*=T_W9a67LHG7h#i`H1gZ54JV_$nRSZ zzBT>$)7KGDHd1hV0f>?rgjXXYqoP&M(Udn)+gMY?ej)Npadj?*XgCxUxMqZwSs6)M@tP8;E zPyykae2`kCcl1}gzR^@Y-L+ma2L3(GtDm|%*uK|pz%Q^*|K4_xWf;%sO9AjIlxO~R zM6fE1XQK6Ju)pA+;g{XuuVCJ?OFw+Q4GFbH4DuNrR@%TI0(Q;PX=KSiW zj$k(kBkZl@e1!}n%(V&a@)==PwLmy(=aS%{`^{wDYQ!)HtpLM;flQ&7Cca392{nb6 zXr_gojhdLsd_$~;vgU#~l;jbqR)FS#K&Egy>(~IsqnbjmS?UOPt7F&=;s|i7ac~0~wk))FG{=bKar9V9gu{mexWgP!DF0YS%IdE`=VDaUM@a%!{Op zr&Vib2F926Y|e70Dz3{#3!&vmvYN%4I5J@S&;ii>1nc{;n6>Y;}awQ!-IE4d0C1qp?WexpwSdkG2ehpcc^V~@E zMOJ=_l9GR*Qv=76J}PfS3rtUA%CQ_8MXGE@7UM19hCb@{Z{`NIy+RF$MUBUkr$eFO zBl|!M@tK^DE#iz_I3W9&!jLCxB`sMoZHnRyc#k9~p@!DoTY6(SkRk#Aap@q|sF=4w z>Drx>Iur}&u&<^@4uz4*9(2A#Imy_7P*F<9LAuJDoNbIdi2ileI<8!?{#smud8~c_ zDY_LxP-pI=1|ceN2o#sm+3nw6Fm@)V_$kF=UTR|y3RBv2L#?za^FhiGt^7d8r(B)e zn8x5u0LQF!Dwu=IjXkXJ6O_^CJW5r68uH;hc44$?l7UOt}BTN zuUofvvnwbKJ>p<>R#oB7`(q+fXJu)p%s8g)V$w-PGA^#>WO_#qVkm9=Z=N`>7OHdD zYLi+yYbbII+Ll)QIwD|Io>F^IZ_T&Ec0Jus2R#zJ{}wc#sk+hpPx8^_E`ug#t3aSZ z@FQ8YjG8Nj$D`UXB=c!j=e_&g#prLtnsA62ftB90$~ey2=rY>p1VmGH>v)6%mm`~- zAT3bVzA-!rpz|aj{VHF|nS_Rlo;~S<&gT|Aw!R_dW;_hy)wQH4@@SL|G5)H731VN` zZU3jto-<$-4m9gS|iv8Mmwjp+gJ>R z>q{vFIJ1)GASP}uKlJ!)`-m?&g5BDn=WW(MS90*IcxxeOhuKX|B+W+r>Wl4dDb!K5 zm*9f~^>1D!#TVMd*xc=ldq)X(l0nlX-<7BCU6$+IM&1;+Yl9+|#e}0xWmaYbCJw8; z+4pRTHP()x=&hFNm6lMxpzVQ(**``YE@>^0PiZT?^nsc8p}2g2ZG*OUn#5dcw>AJ+ z1UZ|-wepl%_q$QBC%&rEcWsaAP%+JJ z>vi@3vh0=QcVy>#mrM=1x4YPJHT&6Cw4@Z=7oXKw(yeB_!(w<2lScmKS6%n zU!0`gSlfdgkflxh>DkY0FU_8UFPl-OotGd#&$p1qsr%QK^@JmmP{AF-pCk>$HOOGl z!{hN$o$Yn)!~X-c^9^v%(poy3fvnDsUR*nY9lo5(=|QV!yNAmbEx9q!YT~Gszsz&02Q!k5st%V!Tg9@FO zC9kNrRMI@%^g!X51TpziP4)`&O7_*gY20a6{8&e-uhW;HX3hA37CkMt-b%{Vb%L0) z4y%`&B5C|q`jwPRvU@uZ#M5}rUxYO7JbO*{if~h0B~Le~WV+)z&EVugrOi?kpR$Q< zo)wmuTy=YJNO>Im5|K2PPJgeu+Qe+k_z_Z`=vbz5&Y}Y#!ak@I@=SYE+BgNC-V^~p z3Qpar%^pq&Ov?G7WhZmlaymqgfrO-ndv1EsXehUZs%M zrt<_j+~u&Oxp|$y=DP9T>qVVJ2N6o=m;@;KYXah|+O4^lae&_U;=leaGAnDLKplT} zT2KmMqQTn7@Hc+#xRM_w{h?jvdJy8V^=3-8&9-MCXKVhR-1-2%J5;Fm_j%~TXO|v| z2zP|u0Q!ew&Lz&&Yl=^NC{h)EqQQBr&s?17l=x>GR6O=L@qr zB}@?mq>KYlL4&T3?-1|hRf^wcsuJmr^ARAD#y|<$sd-;od{+~W_;8r-Gi79bp6mw; z`@`V;Rf#|Irz8bsVg ztMoBdX0?;=oI@d+G)*GCN}D7gac)q$Jds|pO$87+r&Z`IeV$0K+@^C1Q%I9orPQVc z@SkIoUZ&P9cIs5BR?1fDo)a(pStuu+o@nzMTcu6$l)R9rkWRW^nnXHZnu8{iDw0Ny z(pt4m>{P9AJ)wzev&t!WE>qf-YO}II_f%0jzQOB^OF((UxxMxw7tN`(HL|5o=1)P;Ic0fpzE@%17!p8-#Pl~aE;qV ze4_~}e)*8#vgYd{x>5|N&D>}rY%yNI##k9okFw@j8z|U%hjwsUI%)sk(p7#;$l*S) z6AE_1bcTHK5@_5QW%J?qDdwyySV&Wz;nAvSbzOZyq*mV0S>0pxq&D{-uKg`d{swAz z|887@5y8d9T3CeJ>H-WXwb@ouJotcSUH zKyV|wl{#pKx#Z@_d9#YES*?SznPH^d6}JTGmBS7qwW_u9GlVBW7Oy1sOJ|Fa!fXz^ z48WH!7uBu^eN>BVl3Fm6<3?@N&BI$V@hBE=Ctb5n{GI1=j<80?J4W3Y&s`;wCvO?H zS*R$T$G4>7Q7tYZlh9PO`o_vFo@Zm()~TP5ANscv%OzWUSUREBZ0!RZUXt}s;_5KK zsY8@Pqy7Sgjaw>jTC@H#o{d{9Pq~tdwQ&AEK|UD>XG!17!p1ApH?4gKwpbZPbpe|-8XqgMxsW%_7FU}soq|OnEB>DC)2F{-TdDci?SIzh5z8|2H|$4>+@ zmHP(Wwgf3iKC@UxemLsBNQHVERyJnOod80;0hRSWg|jTkA8T4ZP<%AAwzSnB+HbCH z{>P-ATenD_Lj4$I@12Jf&yeu?almM`{Es@D8?;cpMiA7ev?veVJ^@WRu&;_;9OTbI z3-V`m`0WIs?GnTr-R9mp^2a93+V#rUjQzFrb5>*QjsTmdejj3m9GJiYkOcb6G!W`j zyFVHWebz^f?vY0<1SUUrkV|cao@90OqeSGWUZ^ zYy#(uywaHRm~Xk{iD*Ys z!J6;6R1&8h33O%%N9+Qp9g9>YC<1h5sB6puj~&G*GvpO{uJR3k92x?zWZj%^u;hu3 zXNpN9XmlJaClCxeGeRM*!g&V}=ZwHBB5b~2PpSu*MRLOhBo5v7O_s#Qa|;ZRA6u46 z!*%m7SoP(QIw|l>Cq3zDC&j^Y%l`fpEh&uPDLc29BZTZSBZh20BZBPAm~B$;zrWx7 zbF1un3^R!H1*9hT*O4Fi_=#4FZyy z1##YvTXq;b#dnes#Z?#!AGRK7l@giUkJ|x#wD-Y?m>u-;j7{5vn6rV2h$fDug56j% z^T$t297hFfvu1@8zAO^fFw`E8mhH+9dta)AO)rRh->YPr>Ypi>qk;Prj7ID{2#q7R zf$G#v4fnCmpOIGVr32i5jai`l#DAPB{r}NG$W@`Tw#)m$ zSKSewv_Y`9A@q?i8~<|PL!_%}CcK#P4QU6MBE|F5GM z?5-{!>x8O~_9bT)r<LhoC4Z?X-z znS|;J92S0-|8}_T-#~Q*UkBfSerCb#hcbTOR4^54cLC6~vp2f~qSrG!KuO|Ed4xhz zRyf=R1k0Nav!gx0GW)~^I`pjGxRcJLlPloGk3Ls#fJ~{AWWPVZkkN3JpP7|C<3grD zJU)LPISJPIOLE%4h&B=b8>@kdB~A8ppCFtRGTW6ko8>EN@pcmR4YpogXW?cg&IQy^ zbk2*&SZ9|IN=v0W%*agy21j$P_YcUf&`hjUNNNyG_>B(GQeP;O7^VUZ`BBJ(QB1`z zh@?s!5i#Y@|3a5T(DGmil%UlG9a^+z*bJYdaMbDEnCLI>!sEPITPqbumV5Lt!hbKI zavmE7lLvZe>FUHoIebQ0KGl?s;`RKsu8yhJT4pWpZ~I<_hj^frVi>a7(3n!&>z!7V z6B{6{Z8LotSAxQM-&$^)8#LhAb&LGcdZOLM2VeofiJjJN4H$*1$0us__sRpPkKODAe1PdKJ)MKwUp0gM?5rgP+Jnv+>uYvQ{C>w4L>&XbF!5wKXz2Jg&e{1B#7`#UW1eBNp4AC?r0)Y`>1p5@oX|`7g>oDT{`Rdvt2B?0HD5!>eZ{DjdM`SLrYBsy+7%ReOYDk>|iL z3}9ZEV%B3v7_3`piCPifn(OcB7HayvxG-HzWyJv*YL|Ma)Iu8Ek6+~s_1`5I8o0XM zDH*{&-FiQ_yP~(;{5@)UnLoK`N-#QlT8WK8KpC{^JuRqesg`c)#4N8UOG_;E-!LYq zi{@ueu{!EEH1BCqwnYx_DjiYVzlWT^ZpK67lNaTd?V{%lx292^qqEfe-0 zF~};q#bi?C^jI4_u4zSCvfQ)Dgdsv@T1;c`fGBz zqHzwpJO$ym3tC7a;Lt2NBDZK!r}1^qWFcOSqxQ4ZPWDp!j{DLe3&cRW@1!%<_=fEa z>bQBt8@*3&tLf06ox^F<{B|k*AuY2?<&m4w(kjl~#5PM3@I)TlZc_z|s`1{ZSWIKhQHz@!E#)$YYl&0IM0rt6b3h;z)Gqbir)k z0c5L|isZIjuM?Uzaa#?Q_j75{g(1d#CHBB^IJ^Q|;Av)o>&rb`f$jb2Q_QD#c30B9 z+_Ru&cl7<6*Q?oF^YcBVa}h|Ln<#wCPv30ue%dG&)&}kCV?0&Tu@cZ#& z``=w5!H2~7$@)W7FVt1z%fKQ}JfC>|VSxjV0`eERSmefrK|N{y37@(g8%v6>{8*%d z&Vu37@zAovO+M{!q-xCj8w{!iA7yB^jGmpaNsCw6ccOJf#xG(F8qiR z6|wg_oe+-7-xAJAFbRr~L&LYj~fYl#+^Mt;JzJ?UQfw%UChO?PgsGLFdGC#xSRL zTOqlPyA0Zmo|?9w4OQ*VzELmP3tjfRi#v(*w_hEDl5U_IO*@hOLPgE6c`hoVZf%&4 zC;z_C^-n(81%t9rP!+&s-2?pE@{gs4swj^Po?bG&5nFj?A;LMpvg7Kc^eKTmy||Lj znM}cw#z>dUna-(JP%}KF4nZc7b1m^6TgSq1%obx#Xh*Xz&r z8^x5+_epG2NR!9)NNcjsB%-0;HGewS7Yl*qz3coOu{5(E@iPPzV#J zNYh23xPx&<2c%u->IWG+(pEYsW}5K!FA*y>)0F4J;YgxVLskdmS0Y&MIoXNtn?mTa zf-t!+DazQ`#_i~hQwmqIbg0UL=#r(wu=44O(D!TarQZ!~_)W)518+||O3%u?!ikV= zCduN=|LC)aC3x71FD5ohyGt-R-bNLL#9@JJj*k~nJ3Se;6AsRF0>)hir2!71tW=ff zVXYOTNrm5G3;9_^7itgRI`%ehXQNgd)Jz5rQQL`khn$TJMArwDZGoDao*e{oW zvM4k9IO4qnrW+;_aw@R6{I*LQcvYvU;)BvsnSp_2SX#`J|u&O~O29ZkwRR1t7J=m5V=X0;CqefK;E znQHjxIDc<=tWiDGBtw~V;!kXdK?bdm^IAi(OT|hs2B*%C#ZW7P76aRa(o94P>N!J( zxnj;~O>i|2OhQhpOgS$yqB`=mDu>7v@Rv#s;>0+#V9aSnH^&LnnK)a^1%qW@yx;c- zxc!WVwlX=3P@Q31j4K;Yli>vBm#&4C2S|ryegHFG<>#3frM08j(p@M0z~bqt+bXZh zU{v!2Z~-n-^3BMT4*guq0HM*VFdoXexo|4ISfNEN#Y#Ub^!au@h6Lh%!IoI1fU4Kf zpphtCn(JZX^7EUuXT)D5*Nc)^W|~dbu_udW6Ri27;0*5Y`LRUOZ)u(WZOJ>#WWOW`Ng1nJTFntRD@0EW(WIao=zOw#jzkD27R zkMKj5Euf0+u8W5LHK^vlXDvG1$_|=M|=Rd_V`H^5kal#JdU*-03 zGczbo5i%QRx9~FE;n6eQ{hN}bL{gUUXCUJha{U!ZdZvklry(qlLiUJvB#CJq{q!9C zlSafnErPcoBcnPXFl0O$!lIsj`JWJm$e{8E>G6kqdt(*9WPq~i!R`scyZ;smFMX9(D(HL`Q+~1?jh_BRqXl)?Ol%GJ?Ec&ze8~KYc}+MP?tB;P z0C=;9<;bW-Gie7~4d>tB6+=YlZIckyOK`rS^YiNT%B7ZvDphcbkk%ZO%6;THd**TO zQ53me*rJBmZf;atr&v%!6Y)ee{6tl630m*Ch)J+;qaS4_rdnEW*?D##P8*64`HHH4 z+Tp*v(Es0oH?Wq?&l>;74{C|;>pu*<|6Rwg{0r@=viJbxqKNMp1qvGw3MQE5d>bG| zp>s&Beu9YB6G9sZ21?z=!O5HLO@M)6ROG4XC~D)J1!?UI>;5LEq|b3KZ4xVYE?rz& z>TFc2bnzYg%6Qw7)eDl6?D7VVdp%{kPCHEV9d9^ZWhQrdyi@&1k^Y*s%ZJ_Slbg$^ z-UX+(+X+1V=N223uA7s}fH8i2-QMCF3VRMz!fF)LV{pv%O&;g;rW>lHfB&gRgt=bO zs?=Yu6BC%8;nv7oZNJxe+c6cme)CtTMW`P~ml4K?vft;xkIF3`#phzc1>TkOhJwBY z*>(wtjv?Elo#~by)ZA`>e3jt){Ty7=uH4^#@S+U3LLbA!-XiJSEZ_B_PYHVBu}?TfBP*;@%s|VDSu#k>Se#c&>w0 z+hvh|FAVB-=+%6-ghy;MfbZHHP-lCOggpbY!RxyU`Tz4S-^HQ-)5pQ)IS$VMv$Jyd zT4!h2mG!+776jz)a_BYJ4Wj&e{=~i);FEMRTle{=Hzi7kX2WAF<*PBgfc?sBX zar~}Z{(UM`!tIx@_z9^)Z)60RB-I>eMnailT0ASp1>>%K6Opv}?g&}u&$;=+a zE0%=Q0wH0$8djSZ<^eGgDjB_CETo`^4xM+hkf~ex{)|3eenI%x+-EarfJ18wyCU(^kun+a}{>8(%d3Pp8oe1;MR%p zYOv)jNX*ip54{ljIe^&hbyV@0agd)R4L#TJ!SLRAzwvIw*ZP)*bI&`y_51T;ng=N@ z89|Wr^QWPROp>ebs-Dmr#5_O!VrES;)N2-SLNRj%nfhwP#-*vHmuYEBsWg@Kv|3xt zM$^vfR12Xrh9)q;KzBnperfJLG-FZW2IIo9GL4~YfkLKUhmXmitJB0pkOau0(EqYL zz(i5fYBkWjoJ*@K8)Gv~gdImuSWux0Cn4^mbX?gpRUJ=GQl*#23}9S&?<#08F$7@b zg_ALXJmf}JBIz^!HWW?sho==)rd(OFP#@|cCouw)tTm4cN{*%uC_B?au>)nyS{V#f zni?0dar=Q0G?vokM7~{;Ky9TTntHHzr+9)*ebRos z&T@a{2=aW`?elZE8~wxIzn$a8{ca@&FXK6TG6gw$4}=^C6(u^`JoZY zHHe)#h(k_+h@Cm930e%3fkSwpm4yKWhdr{5z`R?>#)M20k$h#Gp$sNiv zXa=Yza5sEVQ=;)mLFIx~;<5b?_Vkvc*-@bn+OiqB#bMSuK?yv70nWz@lEiGC>5+|igAcBw2$3X*^_p9OF8!n zdKt&SzGiciwQJZ8am4jFdgcC)g~HLD%RC0CM>ez$A#SXN5u{Fqkxg`kVsZ;~?0)Ba zqfU8#t>J2?s3`cAlK5=>(m)VwaA%7`M`zrSRPMkKl11P^VcPc59Y=|n9^rWJFT`T( zF-^Y63`;k+JNh{)Ve5{(4NV3ojuR(*vy+BccA|`pYC5W4HkQ`#L7d)UBgf}XKXpsy z#Tu{-@5B0t*IlvnRM2kO+&$s(^;<%$b4un`e);g^GMvIGtSUMVVVR$B;vC;MsYscq zx;Zh`a&c3am7zakWZIiVZ6Bxfu+&eA7R#I{ZGCrEcd>01adKrg5muj@c4RrVrfg2| zLpeI(GD=w&5)e+DOk1@*@}K7jVi&31W(eAeK>VEpO&eOB5}eD z=5q?q`Wc*yN0)h%@`H(F2{P{OdiLA0%HGgE;B3|G#!mPe?uJmzS-ExO7B!)Zxa1qR z*wNzf1?{7gJL;?z<>Lh7#((#@P8oA1*}nwD#5;Lv3Zg}H%rv!5Ywf_7td{*aRlF~f z<(W0Ulcv$VeFlN=`dipuBXQ`UoI+4s0Hyqz+<(TIRJCAF4DkjyipyhGpw~eXM0HXX zfR;?6c2jq(DxPN>5jxjui?U4Tr-La-aWsM@yAmz49<0hbdH?{yJ>~IF;(FD$2$-19Oj&BD5tJFjqJ zhIdSI>V)k%iDqeQNS2hZT?&7E%DvfF65{6ryID4GJ=dP;a^@7Q6rNTufvghMlQmX` zt&rkhI=gcd#HSZ+(v`)id?1)7dAsFQd~x9lz34<5aHbM@03jXX~xh?&!e!x=Za!-ECP;s5G3T>_PBgsdvM zSRqd|bl*PrWj+Pzlbh0ad;jQ`!!~_(qiOG6E7Y*Pe9cx&L$8({*3s%tIBPw!gd4Gt zf(S3o&A_Rhd|e#u1U<{HeWcFM8ast~?*PTlq)_gq9fwSW85V55^7-jguFS0D$TRRZ z^<-C^5t_7`#AL%pMV9g80V$GuW(*S3Mb&r(F4NbEQ3}AlOs2P3 z_tGihX5~E1UQqR%?ZE?Ere1QvC*g-$F-Hq9hojJ4Cat;fC6o1fhK07oO#=QSYm!#V zdE)Hcp~O_D_039+rs|;z!6%r3?XN!Y#y~e`Ow{RnHvl_{zwW9NKUmzIL66`%k7SpMAI!W9kt~ zFOHhnC&nb-}IFR zvh|kE{~{;l`IHy#c@tfx-aZ85MrIYl1^39S zM(_l^O>mT8$;w(tb|m#68tX87sKe~U_&9r}@2sWCz_?F$|GN^B0vVG*^SH}S98{$- ze!3w{qC;@2dBxM|qa4ff^Nz43>s##pRF)f7 ze73Sn1NwMek6O8#QUZ%W=-k^6B$LYTB!hLzn8hA!A>RWkY&~dxedf1~p5TMYl9a7X zz%Ug1d0Y^L^VIc2GWbf0Rz>}V)5`)nAgR+@qt1N*#4NPCs&WvUAndsh2}Nf=yhKLh zvF-NCl}rZ&kF1cATjzJ#l~|Iaei0h;0#DxnsZHGb-oWabGay!(ebfaHrM*QezJ=bL zPsGy@W#zJ{pqM5@^$6)nk!6FWOO}wnAK@y&VkM#)a&ep;g`G;2~_ezXw^%6|8IKC5g#PAME}U zi|J8p>`MPgi%q-@RjFZjb(R=@*8Kj#M;AIl`JWhuj*X<_u|tjN;`EE!@#ro`tQl~o z0U?j{7exn?l5|k{w|+x0D;y?M89X?p4`t)d`wyrOCL5%&RM`~zZABNxsMHhmOG9c8 z9ugFABeg2v78}4>hQ|=Fj+}C1{CMDXBX$BRPl80n5LaW5? z3P}?ig-UD{@6Mv~(IWL4MB)W;Xk%rzz#wd+7k&|xPWuq-bSS)noXvN`01&cB^wO;q z--J@W;i^Qp*!-sWUB36V(0!|L_pjjJew)%lQ!_yE!d`TV4}R4ImCrHto@R}Ndl9jTZ;MX!)Qh7z%_)n*06%66*Spjj%})c zMy9f=Xd3<-9FyXekC>7H@bD@O&Xz&otb2?8I7G&!WM8pk{Gs(`%`CT;FM5%tVUu2& zy=sq4NWrBh5dV?eZV-jrxNli!PicHss3vn8FMtUPWjl&^^!&BGD{~bYP`zUr^eN)q z0=W%*Ylgo5YUun5-~P%3eh4%@iM)Gr?tXMPJzYOvLv@!EK$jg$+Kpf_6OJLi+`5yF zsaq#w@9(h7385QOH@Cf@&Hq*wkaT+ddDl>oaw=h5L~cYc7j_zEEZ@Ya4AF|Ln7sa5 znN}qs-2=99Mp$n066`N$)P>QD%sEkQtlZ%s$4tdGZO~@!M^29dC zxt40F?N-RScFK04H8V+Y0=OV&Mws`oe#ZE)L7~5(Ov(ZA`Y;+D?-6AAw}Hvy2Z}-s&&kez>{_%274{-@haS=c|B4Uk4inN$c-M4YcIKbZY zdh~We23-W@z7du;p#-%COBe=t?gaCsr*B9YLJ8#A>7Yg(Ba$HYl(=Y&?M0R)E`KnV zp@?7mGV$8U+Mx1=S-GYeTeA+6&0X|Z-+uC1#S>lKD01fFnWYy{h#KbcNC@4g?30G? z2gr{!Iwr`Y-lhN`r7%-$Na;*D+fk9kvufGk~EgcF()qr8Gq0lHMfD8 z^`n>gjT?~ZAXpmESozZ!@aTXe_OaRhsQNB^IRnWzM(j_5FXROJkZM4OdnY-uY8p>>!by&3k&N<`wL_01mprPF%f2&G5FG90DsT*3)48zmN-VSH`PB0X8N4kFGT|~+~%rk9|-#^~_GakazbYpipd$pHo-xirQ6`f|ka?te6jC5$cjr?JpbDo1wd+h1y@9 z0%zP8#`V-p>_9X;i7lj&nGLJTbXfSQNtd;soV44WN>T}y(oW*27Bud$YN@;wu6<`V zVEkjQ*`-4YjKkSzf%T^EX=|wX?M>?|!*`o{Z!2w-3*##gY)dEXk7=H+`CeAasA;AZ z3X!_Y)>gV*Z@6z7KB!tIR)Uf6E;u|S+nW~J0gk3f1sIMOzdUM1NnKZ*%wIlh*0cv_ zT<)UafLPU!`h;Tw7&v z1M^qoi)(m|XZq_?5YFvsB~nW34II+gc3A8NB!ye52GlEd9E2u`0d$J0hXnO4ULWIvS&<+zsFG2H?dQ}Z&)1^ZEa z7dZ%Ybg!|q27Hv+XcydqZrxS-%;Ae&31YTzyqAzhPKKgkZlAL~WH*Xs5*4Nyy|68~ zSVvftJ-L%FNr`Rdl45=vP^FI(XI&X#hRE#A2F~s=k)bFIDXV}ahO#6|2bI1@tjLC; zjvJ{J?@SoWhDuCr@Y+8=Ktp3K0RxiOv1n@8fg%Bn6{(I+^%GhZ~w_iFcs4A9@I(p>pmtF<18J9YP=a( z(qe1cJs}#^o`e-UN?iKN;c+S#c=Tx|j5*x$F2N)>CIS0y`*;L7$gX-KIxZGaeZ>sd zrBPZCt12etF9XWM<{awh^XwX}(1AiOXL>E-&f8JrQ+dObz4f{}5_ppi6jsfSbvKMR z#u+e+xPN~SH-?_=OiUn`H)OkMl4~Q`LbgW}x)#E@3L@b24qg-_*Cpy9thOYchtn7$ zAFG19(a8>9{tn;}#M=U^%(!|_$s`VI?o(d*Ila#ZgxDGm?FR*7T?N_NBjOIpFW50i zoKbKpb@#-+l0`9g4{5sn8V9OY^e)@cbxp;-%JE`s_sTuf+YCJc`QLxI?n^{`FnvOI z_bC9i-$A|tzX*ew56CVgusx$-xg-mij;S=pa>)`+KSTP*moE_WZ{T(MI#H9}xQ-I@ zg=aW!PTnHXAO`9=lYEBf1s4!RvVw~7gK!Z%swzZgTyBx7Iwv}gSclHW0FvIc#)rNb zsceWvM|H|N!!T(3?X42)TU!e2W=1?YZIDLG6v+F5orZ-LkG+whCO()XZzN)B5rhw4 z`4|rDf0dJ&&~6@KGMsn-P$o*~8M6HbT#^4+PB~YE^LJpd;g@GHSHz5WnO^Zb6!v$a z;1hf7PklH|N~UwW`*|s+zUt8gtC?jNg;Jzm{|WGNSRws%oW% z^XLee_@tB1x@m-yfQq-yNSrXeIkDxTk8awFOVz4iZRQI1+1Nj_-C4g*y-{j+2wMTq zeh+Onr?f*|TSh#*H#5~wBaJp$n&rwmIbmhQJp4Js!)uu4mvz`VIVkcVyHBKQ0-f2O z6-kS?_0!W5dg@B3Jlv$Jv8zfm%~=!q@VH)kyLzd`{Dn~as2RL5H)kD{W5Mvg{>jra zhmStl|Hu6>;CF24(4Q>WP*n){a_p6PU6=*mHCgyQZEdj4ieL7{Dn^v4L%FIy|1B!7 z$t>5$TkmOU!`98wcm}HvZMsq*7PN4MoHJ+RI?}Q4!!E_BP)D#R!j*r+E-=BY3 zKybbaH5RqjO&C8YAm3%m=}VI4K25leNC|TU1gPSDmSs4) zpR4FmRC)5}y7QhoZWnF*RzQD#DBx!@ZH#dyT7#c0u168*N`jq|Y(l|sn3Rs5|9Cy3 zd(J%t+q+ky4I<*ECJPRt@U)wl%{cHjxE(T z#MOy*4`M)EAz%u>-v8^zxU}$DpXNUB+Kk6gCb91xH7N4Pby?`=n2={kyMsiu&~yvQ zk7TeI4f81DIxmDTUAJfHjp1^J&RxrB4wNtyz69S8h&i>!ShPUU8{~ffp`L|xQ4`Yj z+aGgE=0owHYId)zH{#acSgC|Xw8Z~%(L1Q~&NmZ1D9BzP^^}iJipSf?f0q@Li9PT0 zz;{ekMzFXKUEnhW=nNP=$1;#qUOG>KmlX}GFPaY9Wc|8G*#HjD3iYYd-A~F#zj*O! zW6!R^J9O@HeBOI31dMIL`#ZcXbd_>;TdZ&gCj48sW z;G!{XEJ7{it+Z9iLCH7%5gh5Zr0+7K4o}nw5Ud>cAq;D16kNIf8z}pLb{&8lI@^g#ucpJ3rS(rB@0FWrX?~E^p`|96 zvKNu?nbd_q+z^{o-R=y6@0SUit;vlJkwI#MwD@1we+JKk21J3YMCt(d?MzvtM+9r{ z(}CTW%*mkf(Ed|(;b%ysy5P2#NPPPp<=b^dy4(N$FVQmt;sT%6chP!Y_{R_0|DQ$c z|IsjdG6jUC|w8guWmC5z79;uZ@I<3mJto+o*W)eWqt;D3~JmW z{WO4oDf{aH@gdXS2KGh2$NO^^eg*=1pkps;k7Gavf)Qhjp&faPxLxIzWk4?|9bTW< zQ*huNUf_?T+HGJE5~}b2c6mcW@h#sQf*@jeffV6~x`zgtPxi7Oq=5MWGf)PjPydn_q=3;aerpw^fb~H&U;*RbyvGVDD1NII zG>hpQw>JhS@C}iL$fsfVOz5d?X_ z^$On>@6kdUkb9=@Z3mS>D8TQKz5s(PAZFq6(7H8lmxJn1d~5bDAPg8^sDtupUaW%h z8D4OL@~L06f*g=PYzJmhK6D2-;r#RVPT~Cn_pspn6Zf#-{UiUTL-eWMPD1qQ-qJ$! zDc@E>^l9JPK=i5KUO?=Uy*vduV17UiIG}$}479=cH|>27ReL&+eR8*(kbU4~$bHG) zhYW8`(*x44+lVK7|Mqkb{w3K{_QZqy0nicd$o!JUDEy+$$si+uo@iGjA@PPtb2>-~ zFc$HQaz*K#1A+xmM&^-tXMu147Lj?R-gzKM09K?viFYOl1CWp0BmJlXSdH)(f8?2; zjokU|oeZLXdw^ePi}aUzM4YdS*dc#opZ5{%BlgY*wTTiTf5w4C0J~^@qL0vk_{cBG zN7(uN2m$gp)_Duj0OGeCP@Sj&@@Fha2GED*C-#U0sEhoPdPJD-i|8eP$SaAn z#MyE|Q~(@N3AAZ4o-j+yd0POt=osoWIZvD=VPbfB+PI9W#1UyFrSl`B>SL8%#uYQ?k_^eRZZlBo*K%cz9hx+4Tr11jKh%x3w>3AnAZ#_A{@9RV z$F)KYx%D#D`>X46oyUttD@zm+-uN2m*^J-Ba)kSdIZeBL8CEgwA+&`6z6^h?fxr() z1a=2k6z7N{THnCk1Z>kLWtH#-t)DnCHZ7YSG@TUJF8;B#o*VT;jXM<@hFI508wGZn zJFrCrk{i6*44I($=5)?fg{u? z2`-x#;2S*$ruZr~mCX~~DSF20Qtld8qL>SNDRHB4H+csX)v>peDQUV-Iv(!>i;6foo2LV~vcB0sbLz%ve;HCVtM2Pa!VZsrE)5vFFV!lVg($uud_8@4i9pm7rrvL|fowWPAC$rhQN zMViq^Id_g=Qac}^sC}e;HeaJ(t&yu6{98V2&=^Mz{T#{AAk;5bKw&sNpE6Yp_A&97 z=UW7*s=`}ziKs+cCs`<;Ao2AJxqcs-ZU>NR7wb?yzqlYd?Zfl14jf8Uyg z_dM5X^f*%hF8m-fXb1ToBL}`}Wn<^!*TcAld&fA$J0>lK>-2*4uI<#wVUkd0FXTcd zjVBko1wC@OYyjtQ&-kH*E%f678yx-by?dzH1+o+TbbzQp65xCo5t1r6E-u(k`a=RK{VU%Q6-- zW?a?lVxC5mt)}W&6Dvk#TJmlNhdbB(Bq$FTD?i;9)mLRX(Pm1@2!F+w7QI@3G9EuA z?#HXfOt|dZxyn$igR39N z9J5^13w^25B;L7?G-_GT8CLwqwAjOhFU}$?V`J?GTzcs_x?pBv4NPsk!r?O zSAlo9$W$+od~GjjxSf1u*^jCEDQP9Rvm2VypOdRRQxrgEvZYk7uC7;Z{&xRTNb{t0 zgrq7@BjS35b2{_iLXu=B=VD&D!U7dS0_6%iE;Cj)oFF8}bzfE#gD2X~pe~}eaeLLr z*!f}X#2tg@&+qP|2ZNPu$h!V$2D1)lu$f-VaSamN9;tEy93zy zM5~7vus3qldzGB8IHRJ);r0+}SP^XNO9DCuR8vfi4X62#-0`Cbm$W?yBGMnQ~%t1Pr5bJ*7%zP-k zgW?l4at@Mc>5&2Ef_`u@j$vQ2zg^J~o2VSrxTaEMfoae7X4^?9iS&o#umc)A7^P@l z6`6l|u0*WPx0u}e(E{Co!*=@Z9oNk()+y6mRl~t2gOJ*G`pFxKL*j8W9pcQjnVwnP zHj-H!TeHppG8|KJWCw>6x`K@rW2GYRNPYE4 zS-Z!AgEm6%oYuvW7Nr5rdPR%6u1leQW#ypY@o!iecr8j}p~0goUDgP;CP~^*R#ns1 z)k)pMlUW{DEm`Mun#8T`{P_gq!I2B>Sj_Y!0k2+ZFJeZC?lQ^LWy!9Zkgr~8p-eoJ zwCF^`fr~8eT6i5#K#6mByZ*)xw1wYK@9*@H1pXu2jBRS|3&%|5O|+h^z5tRhQg7A8 z7TA(BOl&91mpWgY(&TB{tl(;dcU5wrOqy+LhICP9o==lg9GD-pLRE$q!OqnHmY!#obftH`7aw{IRMP%zzO1^W7h zqbomFPm=L!9Bs8M#Lh2AI$-uSW+5qM_#F!6kDoXX*&W;{umx z=;$&5PP3ero&pGQX1r2hibC zs(js`{3K319(cBQ6VSb_ZRRT8WQ^j@c9?Dq=O47wIa!6+%0bd9MlT_L0z)!Ldblz2 z0|M9ik1aH!hjjiwG^7Y>wixMzjnZ@{MLmDR07sAuZ5K(TO(#pAEeHpt?B_MMkjWUf zsVU}pR85i5Fne%_$)BHGdOj-N@oC`;{9NFyYf(WK$=;`8DCeyBpU#T@X1@x#MR>z{Ied6|9FHxMFRVgC z8frU^&O`9ZOdL4nPhKW=Y~wf}{LVTCUuWXaa|L^tQX3%oacm`gSr8RGoaukczquk- zwNON!bvfN1*5m02S#dS+Bw7_cK(+B0iaa1h&ev}4$IagZ`-qRyP012nEPOWai*j~Zz7m1S? z8#-q;o}yaErO#>sA|}GUW%~qe5 zr8(_|sI9OF?NJALYD4@)UV~N2T@g5@qjB-i2IT@qH2p0Tejby%J!pzR2GDZHL`Rm0tF>j>-26|f~^Q6I?Qk02Pvoz+?I&0G>XbakT zBd%&3U2ir`Hlmf2qgHgxEPaDyOIDQ8cvZUjYOIIjloRO6ntBQ`DF1K=|XSiMRHdJ2mwJx>XjH+>*$Wh%3uH zP!tF7ODT;?CWUkYJ}Nt>6kbPc2%8nk(&!J8vag zhL$Vu3N?=-YJr+7<%&74C5jipft)Mn8g~c%qziC~{B%N6xYk*BeEpcZWNE>hw zQA@fZ+8hb;23$mPpxIG$27;gfc#-yGosl340KKSAggr%PCI}PoeM8=vYDqh<4%m#a zC+*AyxdV73u77tXgX95S5!WOe;?1!jdq7v@HF0M+NFU%6*@|XI*%=QK0K7+DQ+ode z{R9w*@>rJmk(6vZ2G>rTL^D8rG zZ7YN3{43g>5cv_T%a$y;N6py<3gst)k&PU=tH!3Yz_-=Ow49yJYyagkDo2qxanPzd zzAkp!Rc!a7nyjUvD8WJ~cPhyDO#4M0;r~tp*Wc*l-2lbFVY8#Z3XFn*x@5(Xt5nYh5Ah(SlX~*Jh*MJyP>p8}z4s z^m3Cxz45AN7T;vh&rglJg+V>DZ*P{CJSIQz;k@~PT1RhwB?XiELiWEm`|b}-<@LRu zX;`1n(V>z=0*P2AAriCeoA{AX*`-;kCJSuIrP;3N%DI9E%kT`Vz&HE-C4StP1qB56 z!wagO?9~f524H{%`rD~kz~7zc*t)+M&|hFRpuQ-Wi|m4W0iRUNUbGaD!3$^==`(xh z_b08c-P$1%-K0nB7q>j(%7sK>(eYex@3>Nw(tp&DaDSMcXBST%FL|AUM`IN!!n9RiQ!1n%h~pYj;HiS?=6 zAKh$9n7iQ>rGhHoXk<4%ie=&392M(L5?Q_VF#eQb+S>-9GiUHxvuy#xgP$r=s+o(&T(ai3Acu?C3#y_msW^_UPNg4(DbY6mwF-M>CO-V?9W~FKY|D*+w z{aTKK=T;>Ju>ER|Qb8AFL_xj!_l2M`Nr7LVs=)A~e2Q0?$3=3YNdK^-@Pd5mSE|P* zGNRaCA!p9F^(3Mw|F|QQx!KeYrpMT%crihRdneGTi~!*$7?85SfXWNwO)N=4v`_P1 z3Y0GC&-GT4q#)iWdrvyYnC=VrhLNOEWMIXu8|vSJ9zgcSo}?hwr+$z7ctMsQ)+=>? z23nQzM}IR1S`_U5ew_z#N(-QUQUK$Hc1d389<#~wWBsF#T;?27KQtd}l4iyF&GWCFc`#3j#MZ}_e%1pmlQtlAwwt>AbL;rMhMKF|0msx{iy^@ zFA$`7RetnKYAd)&_r-ZTOj`W<7jiT?pP%vp@mNMCi1KL#Gy%;@?u30+A5j(xdi4AH z^_KV9J~kkIlKb)Z#C$~^2^z`2T}RlOAbKMBhcVX`5k&u62nc3_nr*t5z;RfgP6@{@ zxS6~8;Qp#Hg!}3VNo|~TEb9gPR?TBSj)6G$=}D^sMVM@4)tT)V?9H=!C}~ynx-?%=b7^GHEtCV2p)!iI*yf6bC=fU*7K(`}5ZJ9Uq=w{hjTR)6 z5t*%0q>AL6vt7%jOk{bciW?|mS*^OI&}1uFtN>EUvOHVGKnen*1@z=fIi7{$3X0_n zw&~(C3Iel*U&(PCR;5y78Eliq>lD+>XPU_;S*|%!53=_esy0ch#XQNr6wBF5h6}#Q z-(+Yet3s(*3ieENCTdIN@nSKGP`RiKboPq%;t>jZW~&M*dJ1~hGtcC-Y}X(u%99E; zeqeEil%1C~=c;U12Vi5mwI$o7aobj@E7PT`!~5H!F*^H#-o7@py#w>$L^~q;LBKxF za0`FAecc9jxy1d_C>M^kT3C-*OOTyfE5NP96nsf7slqzl6nxnp2vtE1gsQRv(kv4K z!^$aTI8>)4Ib^4$IdrF`IE1fKZHqg#8%37blVX)ur8%_qC^L2R7}pEWsgq)r6jCpl zp4fn+m1Qy<^86x=cjuW&a*DG_)zaI)*F~RfffN;|lJ4!^wWi6-u}K7ld6etuPrks) zWq2}Pg;5X{EZ1S{ppr%D)eLz6h7xqqF262rK`42rvvOz zYN_@ZG@3vC1Y%b4lIZ{hsMeL$lB>o1Bpc1n<$-Y;L}|7ioidGROWR4g1(?rjr|;GjAwtAm=u^_%cpy9rn;WReV=OVv%GYf z{HknVqO)($46&#n}T zHCtrMuwPfgovOdIL@?KOkAZ5U%dQ!~pNv~JtTh|6Vwz=%hiXalVlQu+Dii84L%^MC zo2nZCo5Zx9v(!q4`Z*bd8$zd3EVR}b0i`sV#ja_)j*5_`y#g3unT%UC>@cIWbOe~y z;O3ZW$p*IuT?IY!BSWuvz7R_O=*pA(1N!j{;mTpu?Q&13DU>FvX(fB#)f;dja?k#`gNU(@F; zj1PX^AV<$&-tg*f*`D7so9|#=Ame(|ErCxQ{4<}%I=nBLPhz|U;~nYxq%WpV=xRg$ z?GK++Ml-=7;MmT7U4y}$ z$6D8i$g|BCj!%5Rw11J~bMJw1pBl|NbX4}IeCDu#YH8Cht;@Q^gzqyn`ILZCT9Y6( z!KF$`_@|iGtboRhQGgnQnE_Sy+HOkCrHmQxdskz$Uk%^DS4H=5uhNd;f66;1yEH^i z0kj77Hz^M5|5}v|Tfh44ivBdnL1o)vrmUTaRM;`E**PJ%{^GK=2wHTfPFc5yNWUVa zYU2mPXgw{+zd`^xy#Ih&6M$ZRCiq3?G*FPV&(vNFM4JrVA6EVjHAH?lA~T%H3n|fIxy*ik(5UZ%?&5p0tiBXz%{Wojjld0wrBSZfU5nt_%d5Y>2 zF0OUcuv9P9wcdY&Yd_4cbOm$6BHE;DM9AO;cD(@ zfJ;g6SG$H7rkdcmav#iHNeXQ^(L8c7gd`JW|2}L-YmCcHaN&dO`CdFNhy0p{FX$^g zy@77>KQD4q9iv?6a?Yy*7jqu=TrGagI5LE@=F;xdoocV`ZNXUZ)`hv`=~Zv4hp+Frq;D_06lrg`gl`9q7)Dot*}KPv=;$WzeIL=T zomYl$>MFHwFGG2>d+*7wo;jvp7_Xgd{PO5(9pJCkbF90-S-bWoxOVA5`qw2846VC6 z80SpMrzwEme1CVV`0Bc*r4Nsk9&V`d8d=}f4NpjIfaEhV8{TugI#_hvHe}*Sc1;@q z_MF}a7oXk-uaFV|rl7{PpBW{xzaG_ai~j-UQ7S!3n_~;pjnD_!ouC;V=z8SE{lGn} zzkhB2hrJqrp@Q>Y?*~!L=02zU7N+BB=F|^=c%q{KhwN~#IYxVi4IZRj$f`U;#0!sB zWvGmYs!(U@T%|1ezF;I~!o7dDN<u z3l=MBNlR*o4PmQ=V!4Oka#Aq4vJ^(3ZXS<&no#HD%n(?hY^E&DZwzGQBeRwu;h*p% zQR0R4t*ys35$a051yllx=tNZKg0;umdMhq71dZ>;K<(=4sjr#d_si7|i&^}Sn=gwW zZ2S54zEi>I_SAv!ZJl>c@hRR;I@I=K1om52`W`R0Mo7|5>3I2y@!t=nkR}}A_f;k= z@%9%(x?uky3y8eX?duQvgWW>0S7vdN483G`yQ zyGzn7`NFYJKIj3nOO8+G8-MFJI2l5O>@VpVdP_PO4=YIgk#bA3ZxND@rce42bSpD> z5n_PiFZY75-xk6N(?|M|cT2I46e5VaL-GNP73{jh`Z+7C-_^hJ4nc-T}V&PT(XH#jbLI3eAg$melp(_POW*)x$G3xVe z$dYPEBk8kfU#?7*o6y;WL0%pz)%RYNm7qBwb@?QsqcSrV>uBy;`Zcjrm-y zS^#SpFqk957MUL1V(Qk*&p&+Io_n(4Om!$G*BF2p96Ne{w3(=e_i z$OCbuxx^^Fp9UaRrF%6MsZH(*aHEX^+N{%NtrQ%7Z@4Y#fOMq-C(yQ~0=XsP^|)si ztV=~Dc1<$I70E*b)5i%-T!#O$UYVjsAGKM-ffX_BDS0URbNVdtCpBuGA1$XSP##xm zNfVpRH}){OOEV?RkA{6r$#7;TrXIP))Jt{I45W@@;OErQ2TtfQ83?ccY!7<|SaQmC z_#3b6;%D4H;NpB}PmM@0k!w&4>z;|~F9cPAFSJWewCYjSZbG*O&RCm3N6||2l$7e* zXzQslRJdrQGGCQnYxF_q;Q)a+SE`}B5~VP&GK0aqig8_vfi>l$966y~4e0-j zxmzbEh~`RKxR~Kfs5fGe&YU+LQ^}SGFxs^#9HfcL_J@*mJO3(Ygewvw7AmJqAgmh8 z6ecVySJt90^CPWJ*`h_YtcJTSso)2%my0!0uL8qfOa*Hh+qK9^D_c|Pt9%ekp6&yX zy2m;n2%QAXAU#6xcKG)I;-|h-Wk?0Gc~d#tRB6-IRJ-9FP*CW3!Cp` z57?)yc@yn_@7P8cajI};4f&Fth!06dM`A3P^QPNF?!FIaV%TF^C?D%%8sZxAoVX9+ zMxjPiV`5|EVy0v0V@_FGS!#`KO?0O{2~BuSpbuYTa$~TVYK#u&v5kMRieneWFps*$IEhCy53G%?&2sf~jdKmR=iM2PBE+OK=})vL-m!>h zJ7qY9FrO9RP6_LIGsg%4kDV#h0McLdDapl%4|7qkxBIFg^*_L!r4bHYy*{gsA$Y+# z4`jK)u_ij&VB!s#3DaF11!qR1HG?#cs(tllhT9Z_0}3(2>t)-OC}|WKD;so|3_~r& zgF(a6D56D@1yZ)6P1q9A8KWHs-px^)4boe|9Cyg-(KtDj&j7vdzw&o149Imxv7TrG zcZi+C0ehUfAdU$XCd`5{%^-afat5{y6gF?i#0Es0SOgdx6Bs;h(HQy&+%^((+aaDq zq2bsuLmUMXBfe;X!{2YQ8q9{>fkKCNzi|E=^;X$4UW`UK;nOu{7%e$*wq@IN%sdOX z6KAqTG#ZvAu`*9&sT(NwVqG{?tTsUzXJEn z_G}5`j~}x(KYmdCe+O<=Ba8nhJh%8l8>Xn;zfAe;raLsf!Vn|>UMdMk7sdi7A%+CA zA}fSY(o7o>Qf>;P0~F=G$Da&n2-2GZs>4$m{WGU3{2%peqZvNaI{f7SVnL!iIkGtk2)5MVaS}GgyiU7PRvMN zkutgyhaWS@=^cfVbdo_G2hJk8`=}Z$qzE}5JLIi62Q=v~!FUtH%VF(dIK63AwXDNW zk&5(RoU%ipb|H72K%*3 z;ZpkHT#iWvw8^G}>pK7DBsfY7K1QBFI36AXGNt3^kx7gvZh5EZ#HE@1%G^&f*=A8O zPgFH)l{slY;tF%obLI=6Y6(p0ahfk28DUb#>gG~?IwK^@tW=0`I5)=O*clIk|Kh-N<_`$g#Xlg6Nl;bM(Q58) z2LMXT;fPyYV?Ba7+vYcy5_AX<-?DK_Ngt_T*g^+)N^eOVOrnvD>d%#x(*(=P%exBz z^~JvOYD#W$YEnXSQexb~-qpRGrdCQ_ojaAa6n%d2{)r3nSI}DQVlvhTi0oY2db-N0 z+G`a)jgOSe**QT2dH>8UpUnj*tQ?;eLx!hNNS{H)ONPS~fOI0kp z*rS{Rx5#aXXNlW0rWFUZOpq1Fj_D0qa)bR*6gQ2LE?W-4Vs!;wt<8a@fUeK`>s}0v zk~g$o6;>!ITL7alpjk{b>A783Fq-VRJYFiFmcJNjURs7ZT?4gY>2H;aWF%l&wt`#& z)v%duqH}v%Ym6U1M zM%2l9fCudIP2%wD|@s@#}}kZ#{dR7y2aU(#~RaoJaFJ0?F4C5L=v z$B_1bSg-Ch)GOq?q_=Js*wIj+?Jl8i?x?VL zW12hKJwSK|mxBr0CL%Uc`;GhziGr$=b4}5+|-r_-vN&Ryo&nl9etChim3!F06wf2 zUI@)zA80Dm7-=dSO>Zh`v{jYu;PH{S5PBU`>*h}pP{cEt(=37F=WCv;Y7 z9wBYIY4QAQU%}mWM#Xjt@{PI_;p?8mk;T)Xf)F}vy6K<3elRcZ!JjNpt{MnZw-q}s zgheJx*&b1PFF2a*um|pu7%-XM6~nCUwH1Wmd{G2=mXesEM0PODb$29DOcOmj+|Dx{ zvUCzs29Qhj>tLxL-Z{n$Ok>li*WN9MdMVTYAijW^OF*s~+UaaD+cD3!z>*Vjn(K;d zJnWK5u&$GIW`E__=#e0jw^nCF4G+LzpN-q?F18A8n|DxBZLXMEos#~O`>3`;#VsL9 za-}t1*iekFyMT^}dDYdEsMY*;R=DQqJXp0Avc0W7evO+=V& zT|juav*^5nV4t)Z4XJC8Qnr3YI%qktd*5h7XZmS$+O!3^(@=LgjN&*=dlv!C>)AIO znFXl>9j48Nxc$Slzi0mk&YeIUkiJ1?S=oqp<5>AjG>oNd>Z;Q`dQ+s@^mLdQeVDia z9^t}Rb%7~UNXKDg61Oqby^0LM$ByF_yrYRT+^8#5A!W6xR=K{g=~hV(n@kDLCREu1Ij8>%eVqoG$b!iNtvY;o}ZPpvAM)jf>X6Y+bD8RQWb4XPb#<_ z0qt8tIP*tAn0<8~m|#lkDuyzh$=|>xQ1$reWpauFUG-smnY^i?WI_(<{4&7A3&R^y zgb1`%wBUWD&TMHeuBc@ZZgs&}sd?sLf5jE)h>nDMrrm1lr%}BauGgt|cCEv5(vpzI zc%JXHs(^2+_qx79qQAuNUZByg6gITC;~nbey7sa47>b9XnUrMUtrk>4IDO|BYx;Bd zp5zp>p*kqy2gGyt!Oprs@VzyZJU=0^QJymTG041K##U=|UdU(Vuj1!6DgB(vAGJAT z4m&MdUoejccgG^w`L1+4?w(;;Zfbp8AR%@VvT0EExA2ZxqJr}XGpocK?x?6K#SfyJ z@!NBZV8<9nW>LzSb+?u35hxfow=ll6|n|Wofow{{7ntY zuUR!%U=l_h0w{nEvBK_iWmpg}OhD~`U$uW$u=6@_JNn1bt^$rjWwWJaNKQk~Fql#D zDvqsqx{gkXxMmd>%t#e$+iMehqJ=thr-XznExy9i_@M+Of6vpAG1s%k5oJ$7%vYIx z=jfx%jo3TL^OOBZ%5=Eu6G2XY(wbmfDs6itQgJI)yUoGdla*8l%o-ZA;XhLeovdtd zAvj%9Bvsak+a_{?n#k65JgwA{tEI5|?_^Gk$+SZ_C z(6u9ed?3@u?Ykt}>=?Z4#v4a=`}Y=`l30F_YjzlO#%|A)lrr0~DN=`vJ25$#i#v1E zPHZ8`U*3qLrlfooPh0QAj^h~UTt%(0f28V#OCKBb=fT`~dl8?%n)&Fg^dlDA_8`;~ zW!lL@7y->-FkP-2s?Lmqp)8^D9hxwVZz#oLqKQP6m%`LNx=$(e@H>zk|99+TOr`|D(3@B>#xe*jX0Wo8#X zow^NJ)&9Lj8BYn=tE}oc$F1#5s~R09NS@ZnxKy_{^(hc9VcJSrWlp*{CIY(QN223H zt)*~|%@4wKq--dkbV`99TufB`8?flNRPuh^1a=yuc zI)x72nYKlf^H6RDTw@tOr6K$U{X}) zpHrrsyGEm2PKW-CoJ#0WUlgNKPOmxL}`}k86g+Gj?@V0l2!dXuE z#9^xmiD}`4;)@--ApbS1Po7<`m>Yg~Y$Cp4KlZ!#->@{VC$|~4oRk44X_pB(y}BdGFO5!JlqaNcDC=&$r2$6#zQy}@;hJc9OveJu zYYBKjw0)drybDnl3An^bkNXaVtb1yy;1X9pCe~xtdo2}g+m-xeh3tFA9KKl~d`|Z` z&ok?wJwJ z#58+v@Z6C`Ib7^09!q5Ket`ctpC+HWL1RAQv8MT7YDe~m4dNH_!WCv-+`07lu9}73 z6)tiEw}k5-NoIkLI>Y)BZhZ1L{?}e=!G5ImmH^8Ghr3@hpVPw+T>lb3)=~n>C^UgK zg+Xe!Xs<~2_X;BZ))N6vkBi~)BP8C!7jZ2iiUAb=*^ST2y@q})q!c&(xCOWq}-k#xg9NG2##7Wp!qAUakk<@<{@cWvI{ z7nNhINAcjKEBWfG@uP~h|P!HHDT7n%3cs5BQlB>&@#_KHe-Fk)5-JL@f|JL z*oCBvrQ%v=SJ_k+TOgb{vW%=5=;zUU*xD+{tx7AN=8}M3T(uEYKdf#!PBt6FQ}9(T zfaXUy;@N;FmLp6RnUQpanzo9k`32dUI!VqJe?b56s-@dP`6mh#k@LHENNvQd>aSQR zoB{;479qA)KHw5mlV$i^#D-!`UxnBBm(|dbS}8{kHNij&sgy&r(uSqVFBB2EM5>5? z%!6Xds%ILf)zy2YX~cao7+N~+8aQIp>KqkwSe5W^R~1g_sv1YK*&N599N1D0^+~ej z^BHb%t^ADQDs4-()+TTkN{iA$vrKJ{9UE(Ix;ZE9+KO082GOJpDRZ5oJBq0Jt8Zr* zSe6#4CH1LN9Axq!OfT!x={n%>o~2F z=X|}dibwd5(lAYc$oIddIo1K(0G>=0i=L+PKtkqjbdSTg{J_rsxgmKv(&yLwhf!Hlt3!N>_O&$>&k5^XJS5Gfe%sdN))TJhqN)x zrSI#X@?|mQ5gPN#ZJ@!Wo#>1aTj!y6^v&Y(GQ>KjK`jqdOT6MzY)90|1v(119(}0i z_OePi2ycrpkyT##Pj9vKBh|6M1>fP&HRL~*4R6xI zsal&R`fl-4$?odhP7UjZ#Is)L&NF5@WJa6>n=vR}vm0Q@giQAkDttta9G0Y@rLWve z)z@6?=q0v%AA0;SNsF1z$jESPQ6R?d?~ zgC{{_tdQ_N9F@bEnoK&9c)AHIJs=4h`nG`|(z*C)B_}p=f8O|^d@jIr*uJi3uxCS@ z?_jrDCzM8bev~3!SIX6~(KUgk=fhu}PR;&PC%8*kSJ-<8ALjLH8^rogSzESW&0$TeM3EBeCGQ-4wn zqj**pE-QQql>)=@Vi($|6c>~r$C3Y)xU;SoQCd}oIirD?MntPoy5-$ss}Dmk@6jK^<;{kVpg&ka}6TqVxE;#rdrwi z0jyO+ldwr$(CZQHh;6WczqZQIF-ZN1#?+vD}^@kYPy{bB!tnzh!Pt7g@qfNQ_Q zg`@Ei*M~+v-{R)qE$mAUp6!w@tj|#-F!K25dIzp)JIQbU zoY~Jqu1PUs^s-@T;62A@E*A#6l)`cC@Z>UHHifq@i z8}Gk$9|JgCu@mH6CAK_LzdZ$p;RMVZAeS~$R*k1#9*u4u;Bu9eb(K@}Fdw&%proYI zPSmC})JuFX=j6JivyGuPUUQ47GTcshq)N>sGEwMf*rnqJI+YwiLw-R*n&Id+!bT+Q zfFLW+UL^txHi#?3l~hf5&xi#H!&s3O|EO35LeE8v$|-%lqPEX`tZn)jyAkBKEhap>qe%e20Ej zQUj^Z)H(JM-^;m`^=;u2rvkE;3;1j9g_EH{0DK74C0Yfkj>6x-UmgNLYyf|9;MAWz z$j<~Q55YSc=!>n73Fqbn81LM_2j4vv=qqv88|(uw(2Q%h7M#|;R}V@1uRk9_+vu4~jk~?3*6&+;e|EP!|*+ZxXhhub;>~#&<1SKdKA6;+W^2;O|5_aj($kUm|o&ct0#Fm1WI+JTo!&Rwg& z^j~MNm!CLiE9|??z-+GQemOw4fH8PwWjl4%tvv$oSPeY}BxW%?m1WnU?;Uerw*6CQ z9YbHa=6-SwJ!Bi7t(5FIa`|@FAI{uMznFYVId&HeppX25%;Y^uQ;d_oh*ti(RlGI6 zsJUnd2HjdOLsp{B^f|qXsd%@~)tAoIpOm%n%$#p3xn5)-wVu4X2W;Jg#8*sbt$`9M zZNnuZ#USM*0n0+mYG)HW?jI9JASET?W)nNjCnY6M^2}DYz$jjaZP#1pc@+dt1t}L8 zK$_dr5%<%Ihlc%T;|BfQlR$^|3)s71jCg=CJo8ECpRlL=Kr0!Tp@#xNHlUmwD6fN$ z3q)~m3gW1p${wZ*w?5X*H<{qm(fWflulU{~*fUwh`Zw>9e3vyns~N41n(3X_p264hC40fU+#cfK{@qfyfU;1gyO*1`+FD|Hn|n7gHa*II?WAey)yDfH?WoXkYs z;$AgKg{WD|Y+DKFRwm%A)l zEE`Z69-b{Z65?{^A=zXC9bzVmPFe;Ztl|LsNUa0fm8OXm82U@nwjmU%ww6@b z%{Zc(HYMe(pH-QKS_CuWGIk*tr=Dk%&Rr<6HX#}t`F*79epuD$SyXRXUG7}Toap3# zd-?ZVN7sNvl-06Jk!)?)CK2k`b!J)^5tO;%4u6B#fPiu0ptj9cyk_}wbNry1Q;@6Q``xd=P9iSwzx6qf~uKMPUft?b4{O3J3+5X zPQBr4!%A;K-9hYv-EK`^knIBe4s334wgW)7g9__Woa$qiZ)hD4IxI*o2wGq0+y98! zlkiH?o;WbxzbD($5ZPE1CDagQb2jm#e~Y&RPm+w=;(u@|up!$O%&}CF;2bi>kmp6Q zEtDlLQ4|CvZ%oVT9M$~B1+**P?|x{m+XDR)bHLg^oS6xAEU*e08qkX69v0w+`9hYm zE%KevioW;yD-jI(6=66Mk3b`RynEZGcDB_V;)am@>wCJpfq_b4xC-UifsxNtYho-B z@axF0u6jlYr5hmXRzy9Nj^gyW89lsa{~#qtaOfB|O6C*Ok*&#kXym)qI+ZcYVM}6} zw|ML8`2rPd-O zWTn52r>;zuaTPS`p1CEboOyo!4qG>C5OTsh}#qu0z$bIGL?bje~LS6zon>9gFbtqf*)9S5u9s;veM zd-DyC+J2w6*?1Z!+kM{hk2CdAaT&2Hfg#Rk3$T(+VV zx|~Ij(nL#8c`qw_bu{(X=@CcA9vk?EKBmbu|08R(2{mv&qRR{S8N4Zw|VE z=3DHRcCb8rJc=vC+VGV<>j~Y&Qa%1tt?z*fuPoIquBL`B$jV!uhH5-Pa6ZDQXNtLJ z4DBE9B&u7dwqHGg8#h>OP(2|!FFY3mc)KDW2)d=cyF?!tydyz3NdSu=hKca2dgkof z#JlbW`nmRd)Cu7xgb-*^xPOtx(BXONMT&M$34c-%d~P%oLR%xd-P8Vtc?olNQ-bb? z8OGa35fs#-Q*u9Cn=?pDBN7ScqLY{+Fsm7d7aLZUp=B7xj3QzUvDb@4qm@RC?PD{j zXiL!4qA?9l?W-qh2CULR4jmMPAF|1H(jJGiiA22k-{D0#wy>rH0PTuIGPB3V*TI1% zRriD)R*6mcMy4K#jN5xRQNz>Ri%i(Yr0QVNyvGxFBVB{&v{A&i$9W3|-UzQpbSJnL z@M^X&YqCPc_P^Jsd`#=SFu&I6;18Mv`>^ryx3f`zZU(_2cAw|>(sp2&?hC#AWFN|? z0m{qZ zad&9J*Efup&kxNBKnwJY12EM~mIdQ|23E&Czi>#nN_0tv;5ga#^zAk{<6wsJUg~7@ zRSx+k?>bhiM^S)^Ixk%XKhaAT8^*F9Yz{0#E#kAN=?$8vQh%Z89eb=AFIV(86!^9i z5!A*jnch@^@5#1ivTBjV=4J!E*p?Q}su$i0M|Tzlr_Uq?en1LW2?YJ45_seFWOaiv z!*e_K>75b5*;>cgS?>w5+tSTvp0tW}h$rYGp&MoxZWH39Rv+I1ix|;90I&!|y9}Te zM7zmwm_KtXN^R0UI4&*T0CyEKtzz}o4d^=hN}CiB17DVOYZKDefwCxk;dkB(3^b}) zzqkYIkHe^bAUj+vB3i$+0|GTF8W*vm6%w5RLU&2aWmPF{Jec^LjB3})Eld;zw(<3d ztl5kY%HKO#Dn5r5oHvM7MDPKGD|icYR5fQZiG zj@)Na8~Zg@`lid@W9ZM8Y?Ni%AHNWXSde>lpiY|{!6LEro7x~42WjXfHX)S;FX^Q= zAsUB%LRwt;LslWAKwf?4AYlyAUWR~RWw?1N$Vv~gkb?*J|hknsVsp=*IyqgUdSf)(BA0 z0)|yi?WDX3-MnjNtU+#6ST!S~c|4w}wnchx;0IyCL@kWkH_dgJ7jmte>om<7+LRr_ zH3cZf)GQmuDBJK!9aOJd?Jrp-tXmx{{UK~#ajBw-wpmR}1PpSI#O_^~RpS;)`lOad znGvXW4;!s_c;5YW`>T_JH}rXk?56q!*%vj>0PhwA7Flmk z_!b72=Ev0y>4hQrywE zlf`g20ukr}A1oL7i$hbj-HFn}^u|>{k==^i(mZnm3tRsvkG<=q?2A!{gml!TA=c&% zc;$(qY{^-Mg(p|B^dVrWswAy_Me#<132n$Aqsb6u50b6-tV(VQ5yb)|8;vTigshBs zA^pWL7I|-N7hE**3h9$l_LPKFdQ+f36QcclpBoLAdNsWTDz1#dSVEHGldX)zsv|@P zeJHn<4m2^z6| zgk=3(j)>lrWCN{^kdhoIUgL%K{!OqQ6{AhMK!vwJjLi`CxY9&y4+IwLRP-a$bHt)9 zw!f>LvW*U?%@?vm{R*=|J#Gkmg+0rtc(~ybeM@p^LE=C02`Zu)e4JA$LMqtzBM*b< z`?p1Uq|Et5EBu4#D|DnHuTVvtllQF-^MutoB@up$egkUvF$_(q-R_OhG`F}JZ4rN` z{>ecc-x+`1sLBz?+WZoqgyF<0*+$@yQ~(QdGrbJt!&wkn=pe^HzRhj%k(`{wTm*Gf zT8HE^JWG(M2O1T$A2UoRKM`!E4j^ejj!iSM|5N4fbOhKYPD`kwesP1YCd@O8@>GNa zC#IEDLOKe-a0_rbh6AO3fXAv{lfo=Zbg){Sz)Mi$7+N+J5hDoPzvgXqK@HA(Rd-j)5&*e?4`{klN z+&b4nSOJ)cH8HNNLsEphJJ;sC$w-&$h?tS301n&(@iaVKrh#pc(<*7I!lF0ng0ZphZzJH^Ew9c-A`q8kOY!j9A)gx0kznG9e%Afqvk zbmAku5-WeeLlTB25ZRb%n?y~RmofahF*t6jT7RJwCxb@9Wpj$ z?cm-WGd6`^kjWjiHuX$@@tw9d>C6Dr(W`qxCp=wB+P=vh<0c8+$jBkeOYjE|FG(wf zkFLnuw;7{?*A3p_fEj&;<2NxA6Jp7J=?mRBO(Aw3?72IJbnlG0Tcr?I+tOI}up~B% zzML4$>O#w}4lu9j7=I-BLF&Cofs%Oi_J`PDy zL+T(1(+;Im1&$V@JBh%zBOB57@9z7mlDT;XHW8dL1d@o8U$QorJR9Ek0b zx2L7{8qtgK!X7!|Q76hJK=^`s-*K2H&nz^!BgiJ#_N%^PdYrKB0=|-JlkS989_j6g zzT$2Y@cHN5+1>bmfN_(2gUpQ2?3%oSbQ1IgKOg#;uXzLIO?=kr`GSER!j+BX(M#a= zZr`C{OM|W#62#6CA6s(D7EirM(;!4O5mPUC?h00u(Jpuzf4P^i z!q2RL9-yqtcZy;Ku$dR$sM;`ZSH}#!H%SWiOZxT(Dp}IP$ zP9N8pFa^+!*_l^Nv`5Yj+);poY1wD~$hCBFN97&BD`OR)sbH8rH%lMD<>26W1&Gd{ znTa>)1H(_6Z!+NH@6lCIdm#G!3&+~0Ysld*fU7`N&q%k$n+Iv)W z7vcb5oy&F7+?y)*%(M-7R6=50KqTJ*wL8Md&^Q(SlbRY|;-$HF$^1FVC*rnrmMNJ9 zOl!j!y%-yaO#@eAHNs!-N=-d$+UH24Ct*h$)-I3c(&F;M^i|-x=i(mk_R(aKM;T8@ z0aLPYEJyx|yrApa6WNB!Uy)cim+L`bb38);;S`@Z1r~Zeh)z9`yfz6eQrNLq3y5lF zavkVaZGACo0Pt>agX^FGNui1HutM2es3Mr!g6}yd+E%z|1|{=X*as3?ks0bQoKKa9 z>pU4E;d58I-Oe*_2h_IIXD?(5@1%8555tGT8D=2+GlN!#>I>HiU;Xk0AN#i)tCQ<% zskP6=M-TbVg6%!V25-m5PVC)`2buciko$ISwr&sI!_nu8x&UfZz)Yey_ z>Psm3SM9$49gb{T6N$d1l!W)l0Kg?MdNoa0#5!bpxrae+3nHq8OPyk680i$4R+EZ- z>M}r@Wu*ntY1l?H%WOq;NLVxJ-O$ucbj!Ab^u6_AdZ-_o72d+(IvKZhITGh)mlYWo z=lR@pM8Az2?=bIyL{qJ0nkzf;{Io-MBe5tM&s=w(U;?qU*5$I+2?#y+xrF#S(7Q#w z&pY^#%g)jr;YaS5uXzw&)d8kfO>fkGn~G#=pwL;beD<+^v8VZSQj+&M%gMt|D zLT@COY{~Afi0`g`A{AjZ;kXRIPxWe+QFY+j^~1LdY6-n9lW)ok@(4TO5VrM-HiF3l z>0ehxpu?{io{(;VhVZjqSRzUM4Z@O*umq_$wWYWXKbXLT#!YKO7D{9}Y;4VkAPEBIA#Av(u~~t1K7$l_W_cMVHik2ifO1gFCgA9U8GDiHEoUq%ilpcN`Qir*0 zSkgsqngj>R1L1i_`mo^TFLn*V;R%Ud_#Eir`6E{8GRV(`t$ZY?Q^f;6f9PWt654D1 z14g?L*2nT@&mxo*@#!)vgiTUXzSc(jC%Q(-DP$IjR&~Z4_#w#YhBH&biYgiK&P;t2 z4ry>OB$S<#!%#ojXBuhYQpFL>f-{P}rz_k8uf{nYIde$Z+R^kycCxvVsPXd0J}P?^ zQK>`|Pi|7q|LaW{y+kh1+J{kkuC%xQZIRrF**rPNn;{4gRhh#Vl`_0OB9cKuU{ZZ3 zy~Nq5#3t+2o+_ZLbAi?Da`3jb_u)d;HRgf^mblc=VMM!JjF-lHD7y=atZ9GH*+$G1 zb?UV!-3Cic5|Z;$@X@Gu(M-V3hgHUmAbLKEKq^lNdx|7hQon{5?)dy@P9y~c*P+T$ zQ0aH=zF?41A9AB`_kIWExLb-13ZBy|Zy)xNi{gC3InXf6#_csSGl8;iMi_>Ll#|dalSo^w3~h(gG#kA5W99 z#CZD>Cz;nD^-75sfMnrAtTpjrP$LM(>#x=EQkFfXG!+I4*OT_@H=+!+Uc~~r!9$i$ z3((;i_?wW;vF?d`pXu+yR&{V9RvLJmBt}ULbF1~htUop9HG1w+dMBKo`VO(RW;Hl; zpgiMMf|Mi*xD;0|cAW&dIZ35l1k3WIHC-Vs)=rB|%;KHckwnkU282Jc)ARG7j@~@# z_A}f)J>%d7_|_W>V7tIIQg2c6RV$yd8AB9Pd9&!l1Y4` zci@G5QoJG;q^=Jec7A$O1c1=D1u2DShbhT~x4|f&`eQhJ=u&`j*CSq%bEV zaI%~`NH-f*W{o;OGIgoe@YL`&NoK=nXy)-9bqVXB=_2siu&HJ&lFIeMZ>MT)Ljn)o zYjhI56{+5=Qp+rU3su;rCl9cp!KF=h_0WRs*}wO3=%v@X|48i~0h)LswrdWqT_{m1 z)75!r(?)0su5u-pQP?q(vv-u-Zu?NykLD|v(^%f^hQ9O8wgPl{1NDdd~h`|7%V>0WM(oWhodn!P%3;5^M*OTN_o#^_pbJ8Nq-z+y0f*AN53`Rx@(vfe6Q; znrM#5>FHzMIAePAL2l&@SZzM+q(YJcgTJTrE>#$90Tls&$Iy%NY<00&&{E&DHu^-c z9U+`TL7s-6Ye-SaBwaFA>u6Sv{ub z`8}ltI8J_uY1*|*ahau(1-MqS*A^RBjLLF31!3b!zn+u&7D&-)yhheMx6hiMFN8wd zfq5-#an|39A#L*^mGO2g_(CU)xLgd7KqIVw5j2UyDM=wa^ ziPCcfa(<`w!X@X9aA*sonpDmIZY-OB+abys21Kxe@IfF+M7c|m$m=5}3GE`s4eW08ccA_;^f{^H80Rix9qvS;h&`@ku3h9K0x4g0`u z6vC~@XlM)*qMc8sH#ttaO^;Wu@%Vmmi!Kc!-c6_v+aP7N85u%>Ah{)-;zEL218sm_ zF{w|{BU{q#4&O(H4QXe&0qi=up~R)HpuG9OKm$9*;6lb-*3z>C=A7h0xXApBsvXP zpk~FmL$lxdiAv%r(lVQC)?N|lK3HHM*A{5cw-DpIdGV zdTp>0>t@zX?+LU&>NN8BR-ezXY&{2#@d>sJiPhoqUOOw$xNb-3v%eDX}p5z*~^^~sGH_3v9<6<9=iwfrCz@D_N*~+X5j%4`YmH@ zwl6WN#3RL(Wj^}B@RVy6O_N$b#x#lfFWUKPFK2ZX1h|H_B81Eoe)>k)s5EE^&N5KnDjoK1%e4wpm zW*M{KKLRKWo6^iC4GGh&tYQDU8h1n719rY`f|!U)m?LKA2VFzzZopWven@XE>)=Kw70qz<+hM$jm zFp2EY9ByS|%ur~cI^{I3KE60Hs^1+9S%X$De=Pk56CijvsJjbE?b<)u?3Qh?17$Sg zVq)yn(DhY;Gd9AQC?L0f8ME{b;TOY&rMo-S3euq3MHSzH^;F#JJ_2>vwRc5?VZ#;Y z?McdMFmu}>dsyyrHaV2%2^4Vj?eh1DK0fHcsnpY;j;_%C&|GBCc48wJ_FT59EXCvtPI2714>=kHk8Dilxv z)Qp6d!yx#%(9HFOxIWR6Q7j?c*Oi31+fi+?Uy`aoFv$VeM(*vW&zz|r?K?6!DQM&XB&4P@82cp#S+eK=z@ z1Zu7Fp9g3s!laY5z3a3%s~av3O3|pd?!Z)&To|ER9~c_3HtWBr2D$djvsl3(f&;T` z5K+N@@}D7C`a4|}w=fIYy?>F^jX;`0eEWOa67CQsI+>x@(6`wi(7<0P| z=$!vN)vBZs9JK$TjGU22FnNSfb&6!cwy+{)`&IVoe^-mnB^VM@{T0r*vV*si#xzEO z$1ox1-kwctiYgd34E)t?m6jwm*aBtim$^yQ+#26DVo^(cTk;L~uT={P(uT46Q?=Va zRm=ZBt6CWoV+#WrJ6kIg4|!_?4-?1#T);U>R&v-X=)TjsW^}#OflJeYO6CTwG}JVY zh_tvPEhOB=1%ryagcq}J1JZ6W@tjO`-Tsl`Zl%sHZPl9_f7Fws3|Jh9+ zC=az*Dx$I{O)g<$sy$0HPrZU#^a=6AS758~tx(~qqdJ5>%`N1s-iT#O9Kx6UqE8-T zz<#E}nl3=G0VMkV#s-Pyjf}JAHZl=eX9)-pJQClXk zi!gTn+6r}I@7-AJ_Zl^N+`^B%Z@67Ww>Ys(Z@eiCYbCgX7rsFk`xXV{3C~Bv5ndyO z$Z_WuZ-J8whVUgK8(&+t6`V_^o9hZ1{eUgF-w1CWX^o$4iQf!th*^xAbGW2(oGEx6 ze8t_@+U0^r28zDP*$l?T+6gYnJzUKgaFMO%_!y+f7{EJttsRR5O_2pIcuNpO0CNEL znN;qB*EMWWvj=Q+M@75A)*T?<9z=)chKopQi(aU+r8qP9=$pxwUH;&y{P z0y&W@8fa=_o*Idvc|%E}_nYKC`I{5QC+PW;pEsX1Xuq9vN{7ld$w=fDMRJ$9_ zpFmzSGsrJrGIN*j9bx!o4qWiN#}9~qWsN~jjwItB)LRrfWO9c6A zc;%4eAg)jP_`Wo%*}b^o zcs~bC>7(kL7E2tksU!KWH)^AYWabQnu^>jfub6%}MljAv{zc0ceqv56Bo5?=%}TcX zmRkOu*0@F0@)i2K$#zvoHFecHVP-D*NZ%u1X%+ymBc`KvKPPzA*F#ns!Q9S6+ZQqK7fMAttX<8d{9+lpKXSTBHNdg#?+ z1U%Z8e{{7%04o_NI!-)Rx@Q>IGBc~&*Fv*twAPnuY#>oKs8<#AdyL)%oa@6q*gdt# z_id=pCM`uCjQDr^zfW^|FU}WZjY!>GlXpc*E_)7ga$&*8_afr>)s-$#?56Sl%!{5NaIQtsTEx?;EK zrd(1h`&rBqf6+SXcmQ)X-+>?XO>Bxuz9bg(1d}1JA%1CNyyvP)B%P87St4_oI)j$l z!y1|I({zSOc>7aW%R8YhyudTP0G|+W;6TFS-o%X#BpR4KqYqv%dnV-q+imk_kPGDL zzdE)n&Ct^zmOGOs9X{U{QpPvlDv%A-8jxiCHRO1Np_VBW#0|FSzhxYQHw%{*t(-KAdELe@%t|L&z_dNk*)-T<)!kR*+gFThCpNzg zl=_unMjo!+Ee}t<1q`)J)L@7S2mKxXq4a=L(94VJCzyMJ7du?I1H5MFh{sSL7bAsg z43B!ihga>u#B|ZH`#551{je3S0B6r<^C9yE@~^e4PhxOT`O_WhfB*on{&%&j{ByJ` z8yh$an3*}6m>D?#)7t7kF6vhQ7@YAe*mg*1;Hm;AyrELi)O8|*2un#Nk%Ayv&=Zpy z|Ex;am)xca&M!VN!$WGfVRQIVcDA9U9f)EY*|%)?ADp7ho~V|9PNTJA6;R* zPa29Y`e(9t5UO*r-r5kPl2bQBeZVU8kOe%WErNb-vJ1kQzbyQN|Y(_+bt*`SeSbN-?6>h6oIdU zYUXC(4A!za1d}&NZ>o-eU<+e&-M)XD&|t)n6LVA~&=jrAZM1#GfeP6)!QL~WK(L0B zz~?u|mBGl<1%)f<9XMwe=cblbQX^~-&pZq3BWN<^*LkhL8u!@?Ovg}hz9XZ!drH3fc@yC#NUoU-RZZ_c|%Uq^`D<7C$#{nb-BWL z!!XiC=6TWtQ4-bC#r7Zzq&2X+n2w}(q>!Yh(vz9#ObmAYto6T*P+_PU)MbO-yKg9G zG7E<4)FF+xwoeSEV32E9LYgcZx7HhcM!V#h+o>*Na^qP-ops7+dWzew!*h5-kF>w| z8V1<{GxgCa+q>Q2ag{@=ZYsni|5UZz8)va`WvjdSsBIa9AKi68uPN@@+oegVWpVL3 zEZLW5DszAr6S3-4!#wla`{v;}LY30@>wg~@&}5IKhnQ5Mt2f)@u%W-XDGP}Mi9oSA zM8S4VX-SUW4)j97{oMn~V!T;ub3TU=Ik8M4dt%-!yo;q7178QNygUNelgJ@t#8GO% zR?P$L%Z*1}rXQC7utH&}X)6%gaI2&tX%`AoG$GOH>8`Z$5^q+ZZB>OJT>f0isTVr( zWPQvAWx|HQeLiOeff}FG7tWa*z@4%=k|N`N(7F}F%~WM7%8YEsJ;^!iwqIPAAn{Wy z;N?)XCn48>LVEZzJ!QgInTfx8iyyRzPIL_Y%Ua(px*g~v^ak~Yi%0MT8~x&P=##oE zFle5`52!S%k9iVqsE@(85X@EXYaa2W7D6-#bv=jo9xlB60?ZUDmU)nwq;s{BedZ{5 z&z}Y}rJ5!)bxLbi;NOQ!5Q%<z1{(M*2mihkzHMC-b2&%#{^t4w<)Ve0{;=biL+vo$>m4@-7E(t}bT; z-l~{BGy5mL4;_`+(6lamqfi}l0Eaqmzh=8TEpUjQ%(Gv~Wi3HBs|psIoBVNxi||jQP%_o81`}epk5v8iGI2TXI8GUaMUMp% zVlAaj53QrEZoUQzp7IuSMAff&gFpLRn>>dBiyNQmMV>?!tQnbjAhD|{m{~nH*F#9# z2cXc#7_4*)p#fIuEb(FlAt*r4_2crJwxQiv6b6)$EQRq6lV<`JGv39QR`=|?g9dlA z(Pg#Bk)YO94C*H&u0`kL^6cF!oKg%o0FBUb)770rC~C@CGS-y4uwx~bl=wC3GeBoy z1T35jh|~#lO(x^h0J4f~5L@Jq%)^(x_mIc>&7jG8 z42?M-VG1ESXTR#67JR;;81bfG%;=?EK_oaaIjZJ)S`7?hEWun5lJ-3}VFqH@&yV%~ zm5%jaYV0O|aBB|<0KoCT$L@ckm@7IzJ03I)n|WwX_;gJ^pap*JTrM025tFEgXUO zg1Dq+-(M#e89v7!ZjR^MW_duXQEZs{yBXx5Mh`xOqKCjq`RKBS>V`!KrS_VJ%KOoS z>4R;9!GlGE$%9RU8W9)~8WGWhjfhT&C&al)>~szS`yLT!#I%x~9}hP^6R=Rkca-QZQUOP%OUkml`izh98D~GTQ3&QZ zu9{40x+y9?qbam-VpAY0FN=Q4n&C$=>=lSu2;szXj(`>iIxCc8>Ky|Q7g?RUU3ryy zjoJ&drSO5OgRiV7YRw5%Y@b!K*=Kk-oDl--*ur4^NJs36HtITy^#+?veNwcl#8c1X z#0Kq1C52AR5lCI6zu2xe3lkaIAx0>Zh&(u#x%>xZSTDH}S*Ku42uP_1nIf3A3B%N9#qC6g@@D$%E13ubu8RNJlEZ`PQ{F=9AQA#gAp}4ITjp)wSU<*t2VH&4=s@6n+CF8L&zq1G)k(T<(2oq ztlMH0EX>N4wb4k;>y?_#-Imo>ODZXrBulqV*GJ~9K`7&Oyfv0NNxJ%|J|>mgN5jP^ zY#sVfp%7mE!CeM|dg*m^(yMr+*x*R8p%9-2{ru_l=%m@;NTL0~Ne2D)>GXtk9`V(~ z*Td4PusB?XOAy}X6^^k0GX#}guxALL-{*=OkX8QB8MxVWAkJ@P1R#w8ay3~-*Rn}& zr}pfw!;c&Td;agvB1awC@>XoR^gq3;0G+^kLm z2nRZMmY*z$%<4DF4&z!u(sg<|=WFhmYR*Tmah9yF@m;d4uVI4@86T5}CRq>tT7HsV z#>L{8opd7SYmS5@nIHY>{1^^thw~j-l5Nh%ka4T*m+5?AQit?BXZuKzTZ(re4_-~y zF6N)pOko^Fb1}3veKd@Utgn?GZN7PoMsG2qkaIOt5S zhMVZU!3?1i2ZSZia0|m(>{gvI7za9&7%L9bFNh~G8*TnX4}-TARAXoFlrg*N#RUid zbwoS2*?XJtbG#@0G;I9;Gm89qD^_I`ad$ScH8wF8GqH6v`7ek2f;_q}?D=v{B@h*K zySvy{s656l2&q0OjdQ9ld7x{tLxFF~>U5(7N*Y^2+ z=QYR4%C#NeufzB_q5if=u=MzZM27MLv`}?i$eH9oUJ#CymIc8)h2K=^C>uXj;?w2HPKHawtVQk0c zqWOdIWw)YBt!{uDP8bjSE$vpAv8S4%95*&A1?(PGcbzY$#gjJ|I&R_h^ksc@KbeFY zl9cW&)3aJlI^D}vb`E|6n~tM|VQc5t7`mn3SELI#6}k@)OBr8=(;YT(r zu&C(sIQD8>^5ycDH+>}zgA*-BnF0%?j6gZ+O6K$XeU9%MkEKjGvQlGeIj9NZn#48D zBGqkEo@%Y80q~0rD-V?)AvBqIpJIna088}vv~H3ENZcmr?|%9)MCl9mK=+t6zw-z* z_g%c?)NL*Q4wy6`cj{bO&4wg$?=X2(#-7|oDQWGjA20cPX4>R=_Ay|^yvnAXc&m&{ zxp1CKn^;8ZTGDknTUdzK0g0ap7Kq(|y@d{0i^mbh3TT52z+1FRM9T31zX#?b2|q~~ zp_j0rzU@E6={KS92|Wg@EEQj<3CrPMhM`~Hu9z>$7TW9RC*=)`R+imBBJ4{dtliET z4K^U<5#VJni6^2Ba*19b4Qek+CdeswqC63~78HUzplP^)TR^*MeLyDya%6r2zY;e0 zv0Bcla)3PB_oQeOR=zmy5ZIha3di9I@dy$svqenTXms+88+h zhptCe%lc=m$de^=5z{DfIR&)d6oRUW*g6<5xG*2zVvFk%p(G@Yj|`qQ=)mS;eNZI@ z)zpc1RQ!cHD1`qjP!jmXA0ToU4T9k3yB%N?1Sbdv_;obt*|qJW^DBbcX(lJbYkD)I z{e0&8%N&HCE*EB(QJS>?p_OG1-uC$b_SY43T?XQmPQlz~x+;C4zN&yE`!RBnh@W}@ z!J7w&*vBaFY@`GT6rr-JfUJOS-xee!Bq~ZeWTfGtInq^MJt_7`S3$d6-=}YO{4C?# z2A2yy10##~P07o45wMN3E?h|IEK1^=Gbsry9b2Ip z=|dnv-DMRU999%!4ek`me1b<8yVapIPmU}K;RWIFMa!syLxsl{xv*i)rJ|e`r%CG4 ztX67c`?>e)R`XSi-Lx(NV2WyEwXuSR{p6DcQ6*X|+*t{(mbCGLNlj>t(A?EVTa-qu zco`S+5k*Ya+av<%@^-%2Wk6@+@&O*hvE^GK)NAI~U=>r(z@;3f(=`9Ay7VDriM)bq z^?eDoWwo8RL->ZzAV(j@HQjhy+Byt#HIYRdb$z< zTD{H4gP`tE`b0wBQFKthK`mQ`;#K9H>C<^sm`CR%uwH&-*e$rs`Pjs=P+Ii~4H?ab z=NRKoEpRjP^=gWT(XjF@Iqv;|1B%?PM2W%>1$Xhj1@{4Y#!M+s1}8gDUgjQwB?<)t zlgjLrc0lX&eTl?aQjI56@ndeQeg`{`-r)ldOUd^L0Pl9Bg8;_and=hTA6Jh-4JYJ* zxvjkn-EFv)7r65%qjIAX71cqc3C-Wtm7qMVH&IR)e0l^`!$+&YSJ`E-mxF3;HzI>N zwB8I3tx&bceybrX@OBP+visGvovAO9Xtsn`4toF&gCQ#WmD+6~FP3P_;a)oI;+<0= zD+qcA{a9nYVIrGmdpLt!JnF?$&m%2)x!_(AK0+@*;@6r=HD>3H**fU@m8qoqY)^G| zgSx_(Lq6Fw!EJ6HPb7Wy_CYqSpkn>J8&4}e0iLhaLZhfQP+q^q z-@Ja`poxe0vON(EfBBQhs@ALxJX1&}(;NwCNj4E4WfK*X1>0fMU=50ENNa)btXt}K z_-BrcJrgf+pC}?#D=wIoW4J6H+OTx(q2v{ZdZp%Q4`S0)_Zf&u+B`8ue*>=RIo3a` z*6SJ6kKjCMWcfI`7v~S+x~ysiIfQkw9%w~-q()!2p|hzmxN1fl!5)0F9`JL#_sO8O zfd$og(SOiA?;<%?%a57Sk^relwrEJga!O9GOEShLrWYDFQr%kx8i+|mSwneXbV0J{hOD%x5Yrk=kWg zG1#X>dj^R;j9>Nal$G{7Muyh=z^qLsD7f)k=28c(&R?x#qbn8}r329|0jJ(KmaF}` zqAdenv(N%_z8r+spssWF)vPAHAx4HY#$Ic*6q&#nBNjfXBH2lPU7J3OBLb$YwdFq6 z#Q?<$r}ZbY|C-bqkb2|Jkm`+DR@ieX?kR?Kh|Z2f>4ABfQPvOIF%7q@_CqoJoowEo zcCPP4?aUL$t4`vuW9%Eys!G2wt{MqYzCFrN9-vpJ?7jZS?Qu@0%Wbd4>DU~@9+2*s zJsMe#n`52$l{LIu4fd%oJceUqkc?Z6QEw1@bMJ*=bRm@r-7=?4N1E1V03SL^n9h#u z$Uwwd;xuc#Ng;?f2-Xf%oM%!rQ#$qeH14*E<*=~FV&th6<(E8`?T0rMn~nG;Nk&>% zGwQtK`Y_=iFN{QG3roDdopWO)EAU0UPGz#5CT3NE(q!i%P@`f1gQ zylG)NnRMMehZ5VN(GWv3C~UWfsM_@OM^VAm^t{iiZ$t_tkaieb>xKR^qPm?OVdz6Q zpJ|aDr&&)ykVBE`yrdd#3N)Fcpek=vXciTd75QlE>!#WW&UDFNYluG6V2BT_bX%k* z;p7*(Iy24ck31}xr_nx&Matq_9bMf_a^Qap~ zOLYN<6=v^r% zgv9%aYD!z)np6>#1xd=u8c>X7JRb$ILnIOdZ! z7W_cmBRTiI@00QKVXPkTrjDJ;G4wKI4|KC;AFbeydd%rd5`|U;>ku%UCi=}lHQ?4E z>aa7I6F3;{48^x}WsK5{Tw66M(^jLWaAZ-ZcZ6O78PA=!MACF-8g>Q_V!myBdQHg^}p=;%Rx-0D|&z3QRW zqTYFoPoRfv$$tmLC4ujup=xS*ANnuXL>b0v;0!-$pnBx(9@VnnY9-{Uwqqh^UULsQ zZg_Z_+x?f<-}P3Qu07HI4M3#CBbLpk=(#+pGFMT@^^} zP7-~TDDnJ0zwDvb9mARY^1E|ZiS`Wc=&w{!2TUK@n*S-ewV)?0D@U@+dbMskB$-gc}zP^k&tvkj}wXb`W_linEm3dgX`V zPw@F$%4;L3nbSARc$Ich;j(?ppSUfzjKQUDM?R(5Jqc04OpbS=i`bPNZ zS{XcC%7t!BR^i6+76E?|UjL~sTv}f5X91q{2H+gU|2t1o@v=9ubat?}axpWN^>Vf{ zaS?F<(!PcU1WyG@-_%M2^nxGi4SRrXFT1+kGn@Cx= z3D5d1`<7KI&OQ2DA;y8maQyH$a{V|AL*C{}^x%j1whP%ki?f`ZUpX7~djkFtjIpJZ z-i-JIm6$guOeKtk6Bn4waefsFD-CEx8H0`)cEWN&(v3W#9yb_Q zQ#%lAKpZ2kcy*kKCkB<~RkAv9D!1}#DlEA|tm(E>Dt9#x_MyJH?{dH01BQXtQd?_= zrc`JnE8lXuvoFk4w|{M<Ri|fmmTxE+m;ugm|{ji)ljiRaA>QS;+CPJUlK%;6` zd4LQEhhq^f)pPc%Eic(JYfGugWW{RY*bm0`peFy*RYH8&D!m(5B+sY2<`FWA-1|N+ zi$f=-X8sdbpTPlEX6BA!<2^#$-YbYkXd;VK%0VHD-VVXoyW#1M@ryAOT(~c{>^I6r z645whEz(+n;QE0+!Ut%+>~5$YV3PO6cusK}0+0`E@uWT~TnaQGnMIQaBzZCZeyIJvRiWBqJ-kKk)fJ;!pKk6Vx1MVFS`@w9C(zfQKmtVp2=^jM zc=umG>;1K|#B)}Sz$&qVm*bqiGs-BakLyP2ZX8#KvgRqvtFUqa{- zW-w9GEp>s(NH$2#nFI;3$P!>obnPo3#B(A9;pL?B2hyErj+9So)%a6RE&@X$J&P4b z?sNJ5UY`O!US6)QJb;?lpNbHoaN7NzVqOsiRmIKyGKP8}VL>&A@eqvhX}ugZ$mzNp z2N|=rqwY>sw1sBQU>es4m5HPWruhZ-rBm0arS&t!Yn!GKC0A|a25gMuHFUU#_7`Tu zwYw1YOfmVfBukF*btp#}{g_J=q|lT%OzlNx?9mrHcWydP2do{mizs3TEF3b(a7#ci zb#L&JFoVx3P$vA~-qmrCap6$3FB{FPtIL>iLVI3QHqEJ9>7O)+)o50xT;It>SXDS^ zCixvwW4rcKqwJ}l6l1>UI1_?fIS#3^ZsAjDiD6WcX-m!VnPk9*eH2HrXfY)3ieMF& zS?DlCcU3+ZrxFMD?3ZF}^(+{zMJcfiV+WI9ZYHbLqXNT$D9&?Vk1lu1?t?8Ic zDc~@(8w)s!$L+>Xbqp4~nKb){ApSIg|Fy08izH6eM;?i*Tyiq1TG(KEiA`FL~QSHG5b%X{H6z>hm2SSl=#oY00@*ZUa7ri zc76%p-BFB)a$DcTXJognnO{;KE(} zNwhcN){#))jRQ5wfohwPHldiS>|h#^XZ?&gdoS_C!#~7!`2i9S8c)hY=F`2+u(4*A zejNBEAn0@F;YFo{p#hviRr!Yh$0yL^xFUsC)a`y58`72Ic9Z=CVx#-q8^pgm%(qnW z=3Ico(ERrfqt5)FByFzhKL^vw=xX%ZbY;ZEz(p;EG_6Kp>99eqC96nNmZ!E_cxZ#K z?3;Ix{q6;b$iHSiTOY6q*GaELbfkt9j+67x!^)wc3MOq^B*wml1JTk~AVRrKp?cvc0=G#cL?d%NdQl77FP z&NDfdiZ+)^HV?eg(IUsxOjZNw+`Lvo9UMM0U?V?ZVbnx3n23T>*P+;vp4jtM&*8j$ zz(Tci`Lti<;i@_9ddhHigIL4iD(J2H$R&gbeeMeaS)_7*wL|`+Hmq-iA^}gUoIX+@ zTxVqiaUhg&CK|EWZ~4)Ee@tQPcP$w#Wf5iYo*d^m*BV7W$7W2AjYq-LT{QI=oxt6TBNz zK2UotxZsP!2iPf#-Gr7_ji*Mv=3}leek2f!c-21qL~teXa|UHGO5SS_y&hRGD^A~w zA}W9ja`~g2O|drOD*YN1jz#Acs^!s-M-qmCyu?`|iNTS|ktADz(1&CRJEO-DNc)Ih zy$KrUA{2WbG3v7|g;sN&!Pqh4|=a|rG z;u&G1M5Dr{b>l>MB1k&XRdyY(HW*v94eCZUbDQwmxsAmQ=5^+cO*5PLTEDh0Z=6p@ zHf3?PBqTHXT(q*$)iBOG8NPu8m z9!{g04izvCsL|;pVF?z@dGTjT%gH7tJ1Emwou&vX9OH_*>h<%e%+9}mDXO5qLtm=O zOIiY_X>KCMST)l-YVEyXbIBrdG-<4{INJJdFHV!~%wB!zr0hh)Lc*WRE~}?LZMCz_ zaPt}T# z^+U1W##s!bI0Kq!(3B^9YUQWU(;oyG%cE*4>fdF)$MNw47pvpZUrAkX+mM~AuHn-u zvw3vN7WzO&S-TD0AISiFF|+Z1+>uz$-K**?X)JD48OyV}#T(b9dANz?E@e2zo0Ldk zsR`rGfe{)Z*2`cTJHfA!!8QMYAVwCyFAJ&0Oh7y`Lq!tElkp@_LB2f%g=W$0skq}xaZfl+Ca1FiBaA!3-dhdAd+Z>~gQP`;@=#cZ3nCqr7dk%M z`by}uxJ_O+TGc; zOCT78?>?ZQ%OkUYybEIhb^_mUfq2sbT$IqLVUwF#{} zf*uf8=fAC={M1=Q@w)26{A)9ZWJ_V`mXt@#ExUwyxGN_|B=)NxXrJB;=)^jv=NxCCsI zYQ64t{Mfl8{T*`4YbThtr|Ho|6QV8lxg@SIDo&k1ZE3QjF9dlt3qzl9`3mgUb6r)C z?WO?UD?mJLZUByhF=CFL)%UoKB*QPFHQZi#uZ;yBT-YG_u4RIM6z}->z&683#`6L8yyDros)x6(VUP;OOkpxL2G=$4q0*Ug#J@ zn*A(DywNgm&$!WNT0Q-TV(1J^Z&S4T(1&V)<0Y93*P;9~3t+w|yxne5`|O<{t1 zzT(+S%PDD6RYP%h=1F=WYS1L*Tjr}wwQyG1ogJB(Y{(#oxB_LZB}~@kk_F2 zZXH`VEZoUva|OnAm{F`?(d9GJNyw1H>y!$m@;X~9kQ?ck7mc}}()pyV*H2*00)4w` zuWi9$3q*O8wjydEs_SI8UR-TjD$7&xk)xWb=@g)dl+X6?Gsc zFA^3vj$S~oTC{5XQOHIIeYD`f64%&aa?!#oIefdA(oiCuWW19*ba?cL~U6!w{>J4h{7KBbLmC?XMKK@@~v$>shy+y4@Nm zYef9LL+ZP$y)GICRSnr58iYST^{AKm3{buXQEs9RYqk`N2vN+ri>S?mUMgN`R49Vi zAHjncW2!i2S{xNjFQ-?kgF77764p_A;@m;8)~Yftx7(Wks0;da-xq{%UlJ_A*r$BY)(3s41HQ);e3v=J&wdU#1B znmuAmQfUQO%BnNx8g|>V2UO@L#@mjw(-ptUYFB6Z^nHQd{%I=>_zaKbhXJ#Mm;4N; z(fM+!4@O77t({N-8TZ1LdpddNd)%#3*<_?6p_yqC{tk+0q;y7Ig7nWBj?la&=alzL zT`HHCyqcBoTr$@hXDzC`9M+C;0BrrW_cH1U8 zY{jsQ0(XOjMKS31oo|nJuRFDSu1!teJgoOx#ha{46JYY3yHJ7=xEo{4`06e@$9R#X zw&C*hT2MQ3-9C)=Iv*>bQ4=OXo=+6GT_UdISEFzoM6alAe>Iq##Ekr!17XsK1NBaw zyRG2N5~K{#5a%re>c`7w%=fN6A7Zy21li9g(KRB(D_Ptx;<+B&BdqVs+BOOU^%*M3 zyQ(j!1`HFw0>1nfBiM7;_1X0_A7Z{-R0PE#E@e4}4bv7WY+c64p%jr#MLB9mwu9Jv zBh0bkKwKi>DCuqeqk~ualh7{<+$qDP{EMVCyN14DB%& zk8prM?ebzichcDfcI}JRbysXx^NrgNjz;^2;;&&-0U`2kuITfe@(NcbtTs_@yMtjM z?8-&3mT~W4a^Nkf4PI1RJXTYJq}5P0d4lYSvaoSVW$`NX5R^YrQnr$lbf-gqj6c-m zvsRujv*=+_M>pPLj-ci05=3-| z9%dAmCIs92ns+3UcO+Qz0@21`rz~1GTa1hm?F)|1K}=Yk;1`?z%WW^Wk3O;fO#Qx9 zs*$Jn^zcdv7q!A5N&TKRQ1&R*+{~~q%Esgv`WFcu}Z)$7yuY2aXYIZ6B z-0p8Lx!zzaEL+Hc-blAfeqd(TxSobVX4kj?WH%JOu8@9=O;6gLxf6>T5YICEEah7E zWLEY%gB1|?P2A`9)?G-OF>Cs^^VhaZ-eXRB_S?hSV>(csQ7-EN)K z*3pkHM_J@D+wWbDGhEfD>rLv)-9Fn@Y#}To301K5sKm5>LyU=2p9m?>cHQD&uak?& z(Kn}Ij%hFA!K{^0W7S)*J!rSx<)vi3T48m%{;5PdZPh)ElX#VJBH117RC>;CqP2Qx z2%9}by?SB3x2DE%?It{1DrBMAuDMkTi3hrwkSQ}=Lps?_msw&LY+lip&3N9@a9L#T z)ZclURy~1+96O6Gj~9;PK@Hw-kE$%a7Ta{;4Va(UU)m~Iy@IVpwL1HhdPezX5q(ri zLDQ2kfN{b)`8dJFPEJHMlUre(w1ugpZ9Nmlcxer822!^x=; z>^2nmxvx##by$%)vft!E0I#3fl27(o-i}$Mj3QRPKu~9YvD>)ygqu{5*=m<_z~>OM#~~TWy#?xi-W-5FAU@jgNrfJ6&dMgR)?!G zmb2JDLz}W|*KRwC+*Fp~)cqlV4JQ5658%vYRQae+q_z=~%{fneWVUGO@CI>j z3s44T=%u51x;@?!qtCuupC?@oLh{{|cl)R8sv0(u+w7JF$Xs~qdXwmHCC9FvXe(Xy zS9e@NYxkw|xC0j8QT@uFM(&glW8++l|HWf;>6GYC#$xChj;|LB`967hE+haU>5}En zVp_=mE)e`4w+uVH`fK3_EapuBu^*hpd9HYRlMu&?sbg9nA^g-l6TAWxn^01sEb33B zy=Y%IfkDDU%t0@0tUx3yR2*vP3lskS_>c`bXV+saWH<)MZ)1#f-B|v?ZJa;BCMKQ* zc^5KdQN zyE`0TXTfB;#;ZJmubPs(oTAIuAi9qtwkRIg;#Ns?Bc+N~`py@DtKz{Jqf1`txTG`y zkx%S4KVVN_HyZCw)DTltT5Ng2xOs3b>x;_nnI*5vkj#)!Ms@M~2bA}MgaF>U=(&_` zX@EN$Hp(-n>2C+g=rKZYUWDfEU8Ym-v5e#eNdpoacM$U*^P&{Rksl={pQk$S4$tZw z2LHhgO!_06^#fYrN`O{4)&B-p|H=utDNV`aFro65fkGcB;TI}sTY@e(SCX~qAt`N2 z3K0U=g3+)zQOJ|Cj32d}taY6Oc8{Q~#fiu$S}w>P|pM<>%e5A!Cawr>>a z2bvV_mcp7Gr+mbRbPmEjI8TBWqV(aZ=fa$W^(G{gUs6-?qL!wkO75J&dBPNW^fFYR zjvI<$X_i#64!(`F%aR)-Vl(I!Kj+7OYP9xjRm1Y?d*75`W{Jj{=j^fklrVa|+bMyI zh5Sa2xM^2}DkPoG+-VoK;61RCJyZhv zzaPQ|IBYi3c;@z@CEPK4Xym0CT}SA2Y>%6zh}ylFMJRfm#`ZJu=;>M+2)uXZ)Z>hJ zZzWas&R$YZI<{Fum#r3RX*tB?4U%pXNtUX&9r0e=!YJhq>?26R792|wWu-4>7W@Mt|!mp&F`ufrj!t&@S0O#QS(WYgK zrMKYD6eTxVhCd(~L<00`tJ5wAR5|dxdS4X7`{8msk z%;K7#-krIP0kM;yc!E-6m&cYrdZ@f?XK#-Vio9GI;8m#=tCK=un`B3v(CCa_Fe7zi<2RMjjeUYA(m*))~J)>aQ3dbv& z@IiQK1+HQu)|T$hT`QX_9zW2RycC3}W$@5|;%C~b4D`w*Xv1TF;LhchS+v698I(qF z?<+D!)zdv@NtZJyQT@#k0y8AsmY@^?@fRN4;ws3-2zGr+IR~_ z)Weyik#tN_y+H!zpx(BMv-G+U4A!V0vLl(hppnP2@to2j$V(&jHRSRT?0Wq8!(#Oq zDsK?QTBBuDX>*!cG;;gIUahfL)WVb&W@=3q*2`ZUy-u*?` zVxwAK)_?@xN?~IczHNxk@?IKln(&R$|J3X4Lo0bBhnS+ExwR#+c;dF08U!q*zrJAF zQqkORdU6ehXCTl8q?|Sb-TE811*AOQZ2Lx7{WY5xgU}Vu|3sueA6zx_=kP7yW6JLtiwMSs6=RumH`mAJQpc6|L!;$fQ zw{~mCR*%wj>q*~eKG2{dkqLa+9^#p2>tX>DQpZUfnH#w;=4aWx4toLtzzx8+10!+> z?Ti+~b{HCpzZ@YS#dYohjSAdtkA`u^tvONTDAw&wj6`2CZ(5bG*fe>PU6f$O3t7=b zSuQ%=OcB4`iAb+WMIySD%X-!LkIc)F7sN?b?=s|6J_}0LtZulGbnX0G+_opr6ZiKHZK+uolI#&M}(vO)JVcN72gD z6ubGJpsYi7^T{=t=F*!>z6u}|1ZiDWA8s;ow(tl(!kG{#dB#sdM;RRC8NH#3EygP- zHnq7#AzzGr1G;pSlvnA3Sy3*%eL% zLI8P<^1pG}e@WA0l_sP?g%JJFl4Wy->27H{gboKF9?+36P(ucAQSWl4SS~VT!)Ha` zY55}Yhnoq=R%Jy+6_@6Jbm{kct1dX)%`pJEHyjcNU+|hUUK!2~^aO(oyDNlqZ&JXe zPHKcaHCECLW|RX?s@klj^rp0;vxv<-H@T73#yu)9HymK$M3h~xv__gDQqo|C z*iQ+%jc9?O3DYYoB_V#14rs&OJYQYElHN!*+QHVt2u#fl``LXcDPgx^#3AuhEMz9I z2kLerx1KwZ-Dquq_za`W!q2VhNbUPOQ+xJzarA`HBg4wCNVF*C0a!r|KR|a8OYoT%6`LlQHC`cmdGr4{a5q-`Kj9`vpQ9PGrQhm>reNy?0 zk^TS=*Th}ZA%KC9A^-Q@l!_~$xHWSA5583OUwaN#+h|Yp6z_!|Hk6If1|&R5p^Ou# z#Y>?5vv29$3U}}~UdZMVHJxUm4++k?*Kn*j4 zl;iEbbB3$FD7(3lG~yYls~l8QQl?k}9!|Je-?5Q#PWFE9ImQmJx^S=)Q3tj36grEg#sEyf%4Dn-W~d6!q$$=(oh_1RODqxk$vE#o zzqq$MPNP;;mx#`#+ZejeRTG0$qzj(#q=Q*)PO?)zYH+YsF0`jWmN<|GQ(?a`i+^A# z0JTH=zGOd4_noFO@tg9_wtW@JMon!i@-N;`@|ZmGPTw2uRZ(q?GgHUfS@fByXe2p& zl_#3Tf;>#GW#lG5Rvp0zUhQ0b^D!ttGL8`cChXXLpdw6CSOFn21mg(tE(A#k=@+F(@D1uvG_LgOqhr|B zerSeN4j>v-yMi|ZY`O@F?Uql!oj}?=Vl3%--r*as)45#*7OLz=rA+-w8X-o$BEUrr zTjGe=p(ab_N+8`8Xc8BgNo!gaW(>}-PyqmrqjI_OldGaF@;r_7x^-bka5o*QtJ!n}NTq$a; zl@g`cVM(lXX|R9SwSGG6g#GF5=s&5SiA!0m8`&!ki&xk;w#&|L9vN}q0n?v-IX<%h z?#KDAS|Gp=*bqM-jwm!60$n!CA#?m_l@a|R4}X`#aVsPc;Yn+zKUZj*&Bz!qGXTMF zjG0nL;JAhi_Xw}RwW7D%T8iN~hEyf3qSn?)@^%SfwV}J=)~i?UCR2eevWq0d7iQ@{ z)1X-QMv(EuH%AUb0)G(|zVow9G5*;-n$(NA;V1sRe9zo&VjWx>Cd6c_T-ZXG#ltGO zhBCnz_l2Rvt7%opPV2CR-fq$WzeuSsakClP6K|_VwavDWffkWi*aJkPYFIg6%KEZk>?qJ_br;q7i~Lzr${>oTXgXQoq`*(>!V=b z>=ENCs(4ehQhh}*)#2T|ix`uJP#PX_Hc1Z{s;0Z;PBA9aD_4I>8nhg%;#T=wB#h?^ zLUbxPSvrv@w>X}+-}qd1lRUih?41K|U*lal1up$oK$cY`DS8^Vrk19eob~vuRO_gh zJZ%I99)@FaQ;bW$Ulf>%duzlN{#(Aser- zgI-)2Ev&P6J585?lFXcJj&6jXjleo?kjU4?M?(|1^tELEwGnGJe08yUHQP_LOkSz- z+__FNz4~1Z-_g3z`J@`{62{M>I4gd^?VX}myW~N0b3op6?sANEot*qaZ6f#p*RQM& zn@>{YDFD8hluMzzyQDC{L?G}z?#-p7?F-{Q3xK#G^@1^B%^L!W1vj0j6HFq$f#`>E zl_iTUv|pUIoRuXYd}nQB6G5maiRG{ab52Aa6=9DlK`AK&_9vXCooQzIMmThTxag5l zWR`Zofr)UIXXMDFCu^Y{oq3UI3=lx}eO|?v6QSIkG4mDoZ(){|Q5|9zrcr&s#4cqN ze*4)g`YiU{4cZ}T1?=RMxel>es)=ray0~|2`pFvEA=K7_Nvyn*@s@RF=~$xv9If!q z8hL=b@KQE&&d5IY3jyIT<_QsYQEe!%6yn<9HBI%e8&G%*nf5P7q*Mk|7=< zwJ-mv%jog8sPqH?6jXq>v-}-Ek+KIYg|IReHF7ojBWD%!G%<7hGlTHYx;r&dMqyA8 zHFQp}P#Xyi$sple9BKJg(|G+^QZfPu>Nju}GlaG>%;B7~*x?|-emwK84z>xRtZlN( z-E_|5jO_1+m!DtuVYon@Y@4qeuA8ne*4GlzBK9aHUd#e5KT3!ScDn3j3~Q@!ubkFx zwDtAayIGT~y686SBo!VwbC%!Yu%R*la?TkFE?b(l^fo&$aKLY#$d%3j)s?*Z|LAK zF2t}L9M-q{zwP<{%aH$AZvG!uj7{8=22nyB{dV+?u9;Sag@%%n z5e?(AjIpN?OsGq#N8qvve_=;cB?m0K*3hp?uYvxy25PPz@OMfoBlkCO&E zyb+rKmgAo*ng#0(cq#zPV8*7^pNgdbL<7CWH&x=<)@a zkOpAFzg?L3R})H^0tDt(=2m9T|6$DBL_HahKT`7to2lu(C`vd7YM})C zq+5yHHt3yLE4EK{4PlJ;ul}m8vt5!I$StsUTr7`y7PHg7e=2^?QFUbKnxfuULMD|YQmie>aTc3E0=UUD0K>Ee%^IWaHsuVVW( zr&weDNjqsjeJ?mC*HN#lwvz33sxUW{R??jP-V0JYFF013>-pMA6ZWe4Ch}Ug7TvC2 ziy!nebq>Xes~8e;J7gaPu5Nvc^(ZK#-1Twof23ud%9$JrcnN`6pM%GETSQ~ZwnkfaO#SXthwN{%GF3;){xeS z+{8>&9Yy*6RgISumyrEScTv$5P#a%Mtf4y8QH)NEVjg^z%ih1+v}_J4*a2YE4?unK zx17ztY^rKx@gH`KP27?n6hsXBJW&+`6BFbma~>O52cs9VkAXx!gb(=*p49}Vtpf91 zTR+kB;16w+xriA=)|maq(*1jmqxoX(*BHfD>bk>-gA}qk=TYan1L2`k!J0za6L#>y z5oHBJX9ooMKvf;B(J9|ej-0w{g>%xKHc02iVt+>kg6WnOo z&~ldKvEMFIF5oHGw)l7JE*6Ho)c%_MhCg-cWCe%tWs(5#f<*D{?l(A0;Hn$~OvEC= zAp^+3yW}q`jbchl@hO@J4{70u}^Lvas`$so7}6TMZP{-aif3Y_=F= zAB}PzB8VoN_1$j&qG|sFf`=48et7{*_X;o_!{4Pw88a_=2Ul?iH+$2+vt6h#8X7N9 zQ26jrEP83AzHtXr7G@-db&r9O%BtYn^6HR@m)Kz_!oCQWg>*0kQ={BR=1%Ts_Qubn z#~ZwU;8mA#pJa+I!o^B41)y50TKw+8Rm&BKQRr}hzKP@d9 z%{H4nNI++A`>L_UdNbFN^x09e38=irBq{37VC= zQ4o}FCHI}_dw@O;H$ZqOR9XZs4x4O#UUb8N-uN_9?F8I=_8EkO%z{nj&$wui!)#uv zKF(Anht)T`p|h81ey4?{6${)62mlUDy@RGF5m@$P;~pkwe)4#3ByAJF(08E9HW)A3y=B7nyR4;q!{R>%Uvi@_cTm z`QJXg5DXDofzVWQy>5==z9LugtNZn!RroUMB@@7;T*kTp-xbHU_UoErU2|I~iZQJ68zZg8GXQQ?Wlc=RtD4i@8`p`FQ z2V5&Jr&auUdfT$HKwW;RNx@wnwBo&-*v`z#{zl#1*vqdhZL!fP<+^a9hfUGKjYY<2 zcX)b3e+Fy&rh@@|FhLPCYnlx|aCRrXcRcFOLSQrfZ9~86$%*OmCF2>7!wa3iELRJo z;@u;pzk3WfzW-Eo5~;;d4;ycA;$jaT3>$^sq$YRlVny*(;5ZLCL?`kmbTfHx0fWO2 zB7epVVL_aEP@MaQNG$PYP{el?Z;5+bNk_?&A@#Pl-x=5z70u;JjI;=fA`loeOwL1R zjr|UBG(`;Ey9ShcPX~CON4`G8HyFNGy2EM`zQE{>s+Nahhv2CU&6i9*6CS1eUO)cB zjkAz}-(3K!BGTdhAB)fa<^i}fi(8r5n*IYX2|JkntI<@duIGX)fyP&xyQ5Vr-bn0Y z=eJRl{8b~VwDp8A!VHIWYcP7vxgi8kY}m4eryJX%mBd`4Y0Z}uEIA||=pa@Qd{Qjc zz|#q>2EOns1^zPz@BOfVq|k6DUvVm~Oo?)$^wLhd!yf{q5Y-cVrO z6a}JCnG7Z;E^yGf@_RI0DI;{3?=Mx6)l#}Lg?J1l^YLDp{z|wQ$B%4UugWlM4?o;z z>B|gFDnZ3kk{nCuvMWj)fu_D^0#=eAhDD~MA(wAw;p8Yqm_gQ4V_Nhk6*rXcujXX7 zrjm{2H>X#%xMK7a>GfLwu8SclMxyO@3uOVHt3S41w;@}Dy_Oz%aItk>3A;nTqHs=@ z`O)7VEkuM{A1~J}-^zNkMKhbCVJ%B3Yc8M#CX`3*T^&0m!;xd$A9%N33j5~b8ydVZ z2=B8q+o^vWrAOmMlRQ$SQm@dhW?{^zfNrKS{&aIImfz)*%^!6eS=#EXb=XEHOXWHX z;r?(U^Rp^#co>R9AfWoZ2BJ=*I=h0}b^B?je?!#e{Ig&J7U_f;>zF3XX0A%F`q&(F zuU0LB^dNQ0jbi>q$EXuAJ3;L{5@Ze2s|txz1-lHOMiJ}6-O@Ts!dn+IS+Roliwonz z?l7>fM3W)vJwk_(LVmjGFP`d~H=}c`?({V+9s7{D3U4gN&e|RLTpkPcG9MJ32`NWh zGY$}4EY&sdW&3t6d$la^hy>0~T}X>NO!QKt>DokK0Gvv@wLl9J({FLM|Vey{dk6x4c_zBVq0C;oRvqKY9SE{GK0P%2XuaThT9;e zbLTTHKc2<-jO0L!*~z50{WuTJl}fcBGxw;eHUTMMIPbiZi&8^mmeCBDUgph{QK?W3 z?SWdzS{o?}hs9qvVHp(cEbkRs1655MlTHTij$7Xc+qlFTz3$C(bb=bnvi&x0Vg`SO z`R6)A!V2~xL`t28PN2NB*$jNvA<)=W%hUj-Z*S_$dFSpB}u5WJp z9=hmDIKP-!?{PtMiLaM%0|Iem4>@P82t^Li=?EzjMhF9+3e#PNLW~I|=1F2WCSTku zJ`X#Xt$53v+811NyhjUsbLhUo?@**G~JS3rR+4&jjHq zE^TqQ-cfc-m=PWV7z<-@8&TvRG7PAuVZuN4u=yt^ zJKG=T00O4R2bs|~G?$i|6=&!FFz2SV7#jO#UHe^%-w_qfpP zg+p}h*#+Wl?)jgfIFL1qvDo;d=fwZA@zh^KZ zHPwHinv{Rcj*Wea$S_PfH-d{kgkeyMX&xWKgTX{4v3?f}J&%^}7Qs?>pKzC{$(Kd} zjU*qn5J-8LcGr^bPMj|Rs3m4!a&3N}-NhRKnKzUbLYi1lkTTX4;%K$XR-72&CPT}T zNwFSgtQH(3inBL6O^-0mA?l>0xu#gzfgU3~y};DRF}9*UZaNJEVJ> zW%DTKzE4$jQ&ht(d2LbQ{O&QA-a0vHa)jHAk={uxy{u`Z7aP&_cn;KTo$=DbeJ2hVPawZ3J+WQwObF+ z4=?hTTXK(19Rbw7k+e5rm_e=tbdS)=H@dOLB9d^mu*xa7IHQMe5S_*=Zk%X^PW)M1 z3Wnn$Sq_>KJ;XC043K_C<9dwh7|-9s3d6CNET`D(mn+arh>liWm*(xJ%Sk$W-^)hcD$8yH!ZXFl&CRKuqSI!ijf=y}{~u@X7+qQ8W&KuIv2ELSQn78@wr$(C zZQHhW;#BOUl6v#>`|s}2J?C1g5W;rsq2oX`KJ zDP;!q+aKSW+WVhtO5~UHziaB_pHBZ+pA|H3EWp4c{16(I;@CkP2%lh{NLadv5dr3_ z^@`SI!a=N7&G55|g)!dT@XrSSB!?GooFW}krn8%?*$Fc<_tMwb!zZ~vXZ7XTXuBp8 z7MZg%VO6R`i*yM?jX`OUFms3oE*IYAQIeDaUkF&}v&p%*UkG7B#=41kZC9%P8KtCH zcLi>0aNCd++fH$mZN^sDcG3loF4<>X<0ONYb5Ep4zg4QUk8TCTT=7ivWiE}H(@7~x zYs>kakb-^9yJ&CwaQu|^3i)`g@Xycy={tXXr==6wk?m*Rb7f!`>^7+up_EH7)*<<` zBk?twWgms|s~c$g+a;-mjQs{vhmQLjI(*u_ziI*&$W%73e}c5m>IwW1;ea%i8XZZ zhkIXAdE?+2H2UU#%@aU~eA#=9mVD?AU{E(1W2HJC|j&3NI_Ra-NDWTMMkZ!B?9W#V0a zW1-w`)b!Q)3-!kz@g4d+^xa(F62YQJwhZSg`nmNt<+>VDEul=6EH^_W$>@Su;sS#p zKe)M?{{TY0VCrNmFSkdeRZXzOeFhXn5NuU^ela#lgFh=uqb?z$Iwn*1)|cJ%{JkoPGVB? zUeV1b#c2zJ*_B{#4EnktR9#lP=I~0Pw%9E}@k|mdw4)5U?EDvW1wCRN?|iq_MHt=_ zz(6=14m(ras;1UUrZ!@pH9~BG=BPqLaxLvMG!}pUWf9V|aTXclMyu+OBrVh4M}e#; z;CNl{KdrBSC{+bkZ1|6&{uh)I`K9>piu$+Cdgxw5Nty|zI$fc=5SS!1jpG9_Fc@KB z44DAKz0D@>Mf~>x0WHH%l}rqA7DnG^G0ZvZwUTCRNEt3C)06HwPUh3*zQ5joA@#v8 zu@o_sgvbIMV0FeT3CltwILMIGB@-=%8EbwG8O5;tJEju9F@^b!Dc;bt&TmXz2mXU8 z1qF_-ZuNp3=K;FANj$e=&5taFm!fJWX>{u{Yn=N`N}IH_sX<0_CMp-P)XJvOQWR9D zr2{d;8MaI8w=0p*jcFBDT~`rJhDS4~us^}rsJ1CFxN8Zj8{DxDV<{?Xq+71D3};m| z7T8uUYSk-naKQk`7Q=cn&vI-|8*i!zBehLc)>yDmW0iIfe*H#o+ZU73p+UEVsZ>fD zH9T?D(yXHvfZK?Wf+KXU{8odNtc11XQ!|JS{XdZETqp`9cis^d#+AF19&>^@S06?a zlCyHAqC5YF)QSh$s((Vy8j=4JjR6xQoH~zTz6Xh+|fvNT?->DZFn;p%@Wftu`;++C2UT zq^b?J5SM{nmH1y{{tZ&x-;lC#^u$b+J8LQN@HO!)k9zqHTcA{CzhwOu^4Yb|7kX|- z0`?@~Um;t3$5mr$VanoWJlEfw=m2Yh#hMv_D9jkD+xQrY{5~(&1Pt@)Z*s5P+hBbS zv!)5jxhU-(91xl&C%+2Ym_CN}s8NS-*X^7l&4xRXL*ywdy+Fwz#yL}j3@xL~n}5+B zq4j3z?X-@v3eE7GyNi70%9LZ`{x@P~fJ+@o8d)jY`nU^y!{&A0$InIStI{=t2 zaV)#cws5};Xa^i1KrV|I|KvC`Hk;@f`i>rm{v^kmeMJcR;*Nnp`W-B$7`bNglgwf` zP4tf9EQAMDD(A_xkMIp-Gt4`mwk0a?vHKz5y zWt8%N)O~ONq_&Us8A0o$9@j%0`Vf^6RQa<*iIB##;1vu2$jf#NaQ~_LB&+>W$iR_h zqWM3>F!z4bNm2eIsGFH-uRNc%>%2aGU!e2>CFD6iFs zr*@OUVVfjxQ>XN)1300V?#E)!!FWpPYG&iS_gH-l3Msj6b6XV=`GXa%oTDkB_jq0sE@oKWlp?vSJ@m-E@koffnRx$UK9} zu@V=Z=2;qQN$go2*{2oEp<1pW<|bk*e&kR|7xS)~L#RXyGHnav<}aN*PhFIjS2S8v z4A#BPID0Vf5$gUMtiRP7M0+)ZZeUmIoM{9w44zf^&m3++r*PGL|#B zwH;PA(HgEY|IknottaBC4KBoKjThG!6*^isFu1 z53X*SY)F@c5{9H$^fKZc6nR13JCch@&RW)T#9gw26?cSn(FP2tTll^!f^9MEr2(jn z{~jCM9SU1Y^;QYNKCO?m=-lF=gv@vOL#b2%cfy%0SO$3*yL9JzMf!@Tc80tN|H<6{ zNU-Rc=-NbrIZ=D)R$o_~Es(34M8XhCGs-BOiHdoE5-MTYFAn1_n7Y~8#qowq&IOrt z#Egn0N>r7e-?CKP5YLL$q#6%dLxU^Ln3u6F;+nTE*Vd0S;{3CxeM__jsWOC_16yfs zA*YmX3^9{1C0!?H8qAQcFl;x$r!<2>CVLEwNca0f^gYriz0$9ubh}Zo>7%YblJ)Cb z^O73pjACcCBxiJhbBs`h=!jPcj&56sF$p22MCMwez{z-Mh{XwW*Z61X0_NOStNZif z)S)L6G^u53FE*90(41WQ%{?ZS#tmIHdrpB5K~CF2XyW6j;1u@XAOESSe;9Q*6dq~? z{o}_h+W+`VN5k ztQ#7Zl)>--4ygkD{fD!qs|j4uEG~g=*=PFIK-Uu0vSPWjsd=erId_hK#d&r2IR0yK zujl62#6X^t+-c8e@8kNj_vYpMx69*qct;L2J;o2L9+<=T8!GH~OI9BCNg8e+Ur|=KEt;fNm94;D{*vQ9$`?yPgymR2hNk}9=x@G3iO-}6c zahL43dbDuhB}TB^D7IO+Xev!8*GrYP0-+Th)h3c(HyBRJ%#gVRo_aWEX)Rv7dzaB< zGcA^;#aml?@?IWeQDXl2{`8(2(7ceOfso>w%HkkqSCqgqO$MaqGNTFfa<3fih2DlC z(L=knR#UcSz5^*Ksj0}TX;_oWcGN}doP`bR$<5xk5NuNAn^Hh-Shc8`x0@XaE38Fd zx&gLQ)+OqBDoJVx+){>IB#r0DE+&!pi!{IQB4K|jmjNr?6ipJX?Dgnh&T8uE@zksU?aXlt zLjWw7H#=Iz?b=~gkUTID)@CiF=d#4;3ej;jb&}<^@m0EDY&oYqoH1OU#Kg=1M{Zuj zsQ9>Nwnj^fwQ?6_UG)Iw8&j-Sr%+t%kZ#QyKRq)mflG`cgjlS{-6U9dw5v!PokyBR zJl_Ga<8>p33eaSAy_{8~7=`R6A&I8i0O@k?nOTTGh0Glkh$mPuk2ED3Q6Y7(AbC7+`M(g=w(mF-tZ_($FMR6o5u3>#>P8zLylaarnw6_x`OT8Xd zCN0k;R#?S45r-9NkkhlvYCsplp^sn8g4&_517E>>DG|ON1twdnf?iS0k3E}zCJbT? ziZ1;knHTc~yR+g!AGW*oM!0PFr9XSl8cyI#&3=4m)8(3+yYcZP@iIEp~__TP-Z#WM^T17|&0n_>Y*6giSxTgnm zSdZk@?x2oD1VQVz5NG%H;EG^(z~onVR9cWbydNHer9(B64AoAZ35yd+IwNoMA_8_b)=WmJ)jn4YalOO=sZl&RD%<)^v<8TEO|yNQJhOWzZ! z2k;bpBO>+zH4whkBGI#v280AuNlOxY%&IVB(AorP{E7y_7Hyu4H+8>A`ZT8(^O&h* z=D{IMItE@a1pcpIrv%z@gFfOG^r!CNtp1$#MOY){V^Flh_OnCoDf6tKaDt$quEp#)H4itm=@yGfZNq4B+Iv5^P@LB2gTG6}%sf&7 z=8LlzbONY3vjPOc(xUBhujGLseNiin7L0+RWC{8O$5!wS$wImj)_3{jRL*Ubjxdvd z2aLH8+_OlYxm~)SPKD;w(H40(F7EIEaH;k}Y=i7wAQbA60f)~($C3;45?vSo%n#UC z7Hzna#FydFnBft~e~5A-+h;>^nAA^5tkYeLha%u5F{IRJrZg<>P^A8n+knmU;>TWv zsH@)O=s)5S&k9>d!dG>zs>a3bGT;U?%LiVQHwDrKRXcEyHY(Df(m8}(shxgf(Eh?Ht>q4El$HJIuxgM@?-;i2CGUxW z%Bg%k5KNrDs=?%gpduHtZ7BoCT#Xu(zJXQSqGTt6PnNr%vos^s(yf&C;HVvhE=8ZxMcoo$Hnk3-P5CqmxV zK4Tn7T*az@XX5k`K37+cuno>^B}ck2oJuWg5-qE%!>U@9ku}q*B(YP5RjdvYYx)iT zN6n*rWa|pYFIwq=t)rVR9po(?+APx{Pe1lGSjnp;9 z6@<2ZO=_h>J}!E>CZAfelga@Zd?IvJ98sH~v6gY{`}Zjx&gGG3L&FU2qZ|&m8CiPx zAwSj4`&zP+65VIR%H@jRR1d-3oYNgMi@cf@y{@bxliP_9PpB^k-Wq**-|L=BDys{OQXDZw ztih(k^hwbmApV-`+UwI^4kb;V>~sA<^C*@l*n@LgkLBGG`F?xIiD1|a4tn!Qr}T(N zu(!S?Ra>i=EBdz{VVtJcn#mOs(RdWP$1^-HcH(DDM>=XkAzNhgKiB zS+X8G0(-h*2_q>qGe;UsAbX^Sq29UnSDUQLJ%YwpU^BEc!uC*gbX_pd)LNvQsLGBV z*Ro{26Cw?(OG!F&Oh40ET(AAOO5MZx{xHEsx;=Cf&s-mh*!E?bQ5qZ^mBkBl)Tjs* z5Jt;kX$Qgvi$SJ_Z4xFhYpEtL<+1M3Pj~J8>kv6$J$&k`ZP)JgT zWtdY#Z23cUUxJa8i^~FEWfk=4{zu_r=iT4`TD%(|ny>kM8%$N-Q|kZ2Hi(3*@V|<8 zWgEFIRTN)32_ry;{B~-}(`N`935eT#ja@Pu(BfjrJfv`oxt{G|)?=YQ@z}4azRluD z)hw2)2jAsoCmTSpev4({w$t^KQ?ApsQ|!auU%yWfeZ)SD^ua()Yup!@KmH;hW(~!F z-bVh5SBZ_ESa=uiEV9=|uyQcc`WyX9)#mP{2b@B-8l6n)2ID9vu9%Hgxx^S`R*R@v zJ)fbsZtg`w6XS?BYn4?`p6fc2pxseea+}k!= zTLJVtuHxAM#(u8PY>Z8i(1(x?mT}NuY&eyAt;JNfiHXl}tyo@#n9Ig#wI=Vb=W^ckLSRXv3L4U zNmQEowRtA`<;7w5?BPAcxVXD>9>i;J)@<9br-l4I=Txl#|yKl6$6#X#MB;5sei@PCbgrH zc8{r+RF8>b9}F%bHV=Y%i?>K&sy4v66iQ=2at*rQAsEd%GMm^f+_RY;UGtEIfvQ8N z?Qt%A7th9G>Bc);LDtPF?!%5$$_E#=ei_zVkEqlW==HNX{)(!<49siX8gZ zzJ__3wJ^UID#+|$j#gqUy{m}7(zJ2tmF{PBs75W6cpS&@#>P2;n-^_)7JnG%YynG} zA#?G;Cp_o(->%GewbbDve9M{OeXk$U2qOc`{QhZc>PTvkvYbz6aGvr!%w{iry?A^;*Z))e1w04mdmH;X4c+x{j>hYg?#!zYws?oJ)+ItakRC zw*SkL~=UNr2YG}=jNEq5(JT9~%qGBmT;OW`G=@pSe|TXvEv@~e^yCdaE56KrK6ijS42 zG+qg)NCwK8XFv&ej-k*9Q3}SV#JE2;oCtaDCMRnZCEE2|I!ujPhVq0;?47C9&rX%{}5t!Lq z&5}@vWwJ$>7Aw_^uy7sQ6^kME%oUU^Qo*7iM%=~o1B4}HSp|P!YmLVulVk1FrDay2 zuJCz8cPooroix15bM7ai^99N~Q0pI_zq+@yqi6i(KQEF%m2xBisG26<_Hmn;Y=3Y3 zLMTcM)=WR|Fk`H5+=9fE%zTU-ilqSbOG9nKkk5)k zzejXBZZRcYnu^UO`jxUFtXt9^=izKn5LpGjf~)qxQvjDRuMiD5BvX#m)Qj3FBc1we z*b-R@Is?mgpA6A10k`ap%|}dVrYhj%h_fdK-8}?!=Q249rei|>65|@Q*(1`RcUAc} z1}=ZXE6zQa_nfH`Z*x7Ko6w-M{Jc8VMrP+$G8VKVK>4VzC%(v#QqS*%nyXL9D=Bgz z$pu$v&!%UEyK#^G;9ZFH<#YUw|Gxrrmrk>R|2u%Q6z_iwOlggOb!2ihpuM$LJpSTe zI+(nj1O#Psv<4={>ub3tbHEEC;T*;zfN@(Gk!KXh5NoZ)B55&sV&F((Yj!fJVl*4s z02fT<%^a9Yng+8GhhUc_fiBCmqP4MZhS1^@d<*N%XEv%?>#;-m7WJGH+8Fm znVWEs4L>*eU?q5~4b~fbYU2J2uE%_zRO3si;{n_E4`MF!Z6p55;C+_w@_rm__u)|9 zE8=j~{Z}S}kCbj7ZQUN?CV$Go+)?kE&#RM1FV&FV_^r;yhZO%8l;8JLWLrCkHuj^Z z58ppO_*rh*eVg~ieE-mX&BpbOWikB;3TX3w72~fRjSKmm7kokv?t3wY#zThn*);8Y zGSoNzp!fO8jtT6paQ)_1@CA?gwG{Vv&~NJY!SN5gFQJv)l)Y}~-;{$u_?vJJJ!X4_ z0cHd_b&C*zkA*XPmh73~pMzV9-;q*YJUJWH^1GNfa>C3T$tCluk)~2!Oe^?&STm!C z6VlCndy*k<5MzZI=BCEuP;GI=hdt*lSH?{pDd?VU!^n5iRe@E#2mXOxUQDA^rxRbf zzxCr%E+U^{>`NMXH?VOz5M)M}G>3 z2>Z1&Cq+t0yiP$p6-%f$GMrsJ~3CDC9-p&Co7x3ymCSDek1 zDlXIiZM{Ic!|L$8vXAN=g4?*4_MSHkhJ%|)*BTkvRpB6XjWVlNW=TSsk_`+G?~#NO zsvbF0Q)h_KS7Y%Bj@s_)9d3{Ul1e}er2Qz>>ow^tG6Pcw4;h=PhNppzwzy2ScJ@a+ zmf4K3!HX#EBC8(T&lid*NKPr`h5+@hq7v3>P-#uuPN&W9R8mbQI7UZ4Wi58+b@fc% z**4ur?4(GVzG?Ww;BF_gU;_1vn;?VdqcB3<(O%20E=Bex8eZLF{VWRlf-W~hl4fCT zET1)*Nf~nl!2-(AooT{IHE=GS6#?Hk-Lf}i$Ac#ock(nq842%N+El4$Rd%Mu5{sk` ziBbCZPZ2HoLX-@5`ez5d4r!dRno>vVIKiPVwlbWj%*lRSvfl9Yh`4;c&>}L~fWt0| zpa^0~r&Uq$CXGCbzxSe$xQ41FBrAy)J9QqnFVmCVbEO0-H-GA^We%H{MGG9-*R zxZz`+g`aTq)HF8u5oP6@_EI^mF1Sfevi0qB8)|OblB8-9kHf-|sDq9rgM)?&n~iq? z=^`6;h&gqNPmf+ZrCi8)B9rp4-j$+CA;T;(l^F(hhfY)!Lz3UMlM04Usbr?%iuorWyU#M2;D74j#b3K9XTx)St>umCDNb{kp@eN6rZI|$a zGvvfWjdGuItAI~&f%1qpD@a&kd0CwiCdvHbfLHaFdjod?z7lnpQ_uIguyJ9)B6M{J zN?Bni(R3~SLgmc%GD`KpdbTBS5?Q(?wd+zv61p3iQjkIg)j4Hy?)#37V*m@Gj^KR+OSEgGGzP%j`1Boc8aQ^RUKbeIv-+8^uVCkm|>vkoN4&W6I^_y=^o~ z(B)>d`SBY(iXT;IM2X|-pN^~SC?-v)62_)y!y5n{6-C)jm%7;~*+p1&Oo@0X3kKwK zX_kd45-3K9y<>$)%;+*3<~?%_A#U(6CSoohBA*XugSt{I=8Cff-t(3sAtBYk;h7TU zj8G)R=7AAR zhCTsBJm(3%vu5G?aeL_JwE<^)TDsj5p?XNOmi{k2}7PUNiC2lZVdH zc?_N;I_DN}A-RE^pcfd`ahmj?J05S`nC!fux-JWtW6oFj-DAZfz#i%s-Hab3wv0Y8 z&k=v#-s`XCLLe;%*i)?rnW-i5Tv&Dg7XU&@Ey?jud-W-w9NMDk!feV%dtc7UQHc|_ z`6+&d6B`x_Uc*+r50B31Ie`S7Z}SlnploSE-0I-^aERR^pz<~Z_wa+}@s|bKXPR+B zkj8Z3lIem7+J~9G1E@pR$b#E|p)6z6%N7k>!pKikeFqp2wy0m%I*}vWhG?H`Q5+gL zSpg!z5=6IZ$wSAvLt$;vv46`?s*@0+CLr3wq;EuEeS<1|`H}a5uuhd^nU?3r z+YEx6N+`^J<1T83*f>mzdu2l=%7t=LbV2la&+UA%r8*?|w9#Htlb~v73DFbSL*cD$ z%s)WLU&Iw)LB`UmWls^^WFyaJEll6L-~TYZ2w zB<}rPJ|7MR#a9R@U2zbj<{M^BrK`L(IMl?HU0_G~D+(4s6O*ie-{#b&>RabRB$}6*qm$MoN_iv!T_OS|&?i?!;%XcM zTMOU)Pb?cw^cTh-emMc|gR&WacFD7QygJBz*TL2}(qLkmUl!1{nJG|5BiNHvVYlt} zfxOIAAU&`8fNLRRAv%AOTW>B1>oFK)j)ck>4jJBh1OYwyphe*4qwz0;S4`<0QeZXT z)dZ5?a~2&@&zQb5_Cosrl8xsx=8KyQRwSmA{NeM05AaMTvc@;MLG2V$@Rxx2OGJFx zBmzan0!6vIPZdYy9BA>UQSDRo`jIw|xPb6{nKy}c=E}5j9P5jV5QbLXFm{)wF{TZk zB;2=$6WGfR#^)vg=-GK=Dee9#?cv}=YQI`Xq-iAt6PS+j#Xx+cuIci_E^!OTgj087 z=GIFJMnWa>XtfX(srE>UA2-rYyONW%xsQ|6*D!UE5^#IXe7po_=q{R0_BorKow!0< z5!~qa`3kF`>a;bm_1qOzi?U;lId)v3t7QwQP%FL{gtdp3* zS{2vWvOJytcomG{@>U7ku0)6YL4&ViT`$nAm#T5{#w8OOSnIO6LQ~xK{zQH|E&PqE z{p+^0ZLTP{DsL#GJ89VhTM^%-Wl<(;JK6iAr9}?#E`zrQZr6W_T)&0L9rU(x?eF$= zQQOu1`@t8fc@4hJlIqhDJSv#Xy?qn;_N4wHfafafSC3aatMXMUMti|C3!5Yu8q0UU zW{$T+iZ;_zWSd}MOBb29pFiwR6fck#)KJT!zimtP-1W*k{+@hl6+6)ZuA7$dov+;z z-}C5}__39AB+Ed?%fGe@IvwIVG4oCy5M3bh)WTY1_I|#}>9p92^sGly|K5N+l=c<1 z;#7E~m^vtGE}wWz2v4v*hM6jAZU8ruIGm8dc`JSn6ZDKHi zX|!f*Mon9v0=_vF)|z`{J$CkLC4KKZ&kVP zuittN9 zB%P#!5WVkVuZMmD5U)GjL-VPsNQu`y|LpF$&ArWXy1l;)@!tTiM^8Ca4-3E=VxTO3 zaqJEN!Bzp5VMZ9L5As8W9G3U%F?LZ!#SSqB%Hv~4@9<(HVqO3oa5^+iSkWA*`T_z+ z!N#KuWGCJAoP^c1jL~BbNMNwYP=#erf*Z>6teaK&ol}jpc4>j)S|5a97kK1jHJiRu zY(FQFHI{H!o4_nDK5&KTaTax?szFLFa_S|aT3@(r`FLy7oKgYjZ{6pmoF&jnwI<1} z#UC_H@t00dkWFh7GI-5W$A$|Iyv%DA`At_Ib5M4GP^D~~>Da8$vHDF>uMkHMt-tNQ znsQsIN!K}#)4TWU>F4jy8}>E%2C~dpSG-o~B6E(v6T!6x2D{Hq980e>j8Zw;nrn9W zHRi9pJ;$ABx#?pyN(vlXjXi^mhHbM<54qPj_yiMkez))6SICeJLLQdWNu+0(932H%9mJPmlfRscWWe^hx^MHStU^ymUSxX4Dot>WDN|zFngq=oZrT#~7v+E9R)u6S+o+meWZacX|3sAdIY~J<%yWYQe>X5{`vsI?lp2?NZvY z@f{~?4W1?XRUS+|irOgyRI4TQQB|SOlgUicOF%mlj(CZQNnE!cR1yL^H*li3zh6l5 zvim01tM*(0blHd?=w`_2!<+^W0ip27uMqgqGag_uO#z-$s)S~pki`v@0dlvLJ~lfW znF4X@FZ+VPc?X8TX}6pnlKJRYP@P}wvAHx7D-#8Md_5kf`cRuEJh=@UcdEAPb73Vj zY#HdVm@=L{H1!_b&d(0X)6A^rrl)Et zFRXd!%%0rlv#x&Elih*OfaunsN0rVbUZ!8(DplrtbB&l}aO!1W1X`T-Am5*(?byVZ z;Bl2L`ogc?2Gu9(;r2chx=_&OPs<*@0;}mPQ)dGvC@Cb4;gxreDxv5dwSytXP?W0y zWkn!X9g?rB%iSajS`B;xT!Ts~*;$Ddl)@y+Oi$dERPr~3Tp;ba-(HajB=YG`2hLXU zTN6HkA9TfRl9An|yzQn8?WJta92uD)-ORV0Q3}p-Aa$?S9zn3B*x$I81|2BEef+;ihhL8 zu!RZO6<*<2T``%&5{bMaum17uulKSo5?AH=1E`|I)g-k7N_9dp+wo`LcZhbW9m@=o zfpCok#wwOFRD?VmSNdpStkIQPQhI3&8S3QKL@ry_L)9YM@M6|wB}U*h=|qc93fyVj zEYFViY!RK*FvdyoP>)lxF~cDQIsBlZLCVm1ubT5hAi1vQEz)M)7dKS#8J*cMxweov zx`fySicf%47Z}eK-O@j&qE&vB8M+yQRK$u`2W}1p%0w!acZH1XOr&x%s)|riLU(=L zCQaT(@W}Z?BglC&6Ke<2LwuDy(w+;2^_B!eS&%7o-C`*yBeiFdVrD3?@*1qbNaEIC zv!&u>3@#dj!J^Vs*&Q*^{?%5g_jc9sVXdiM4RKkC;`RM4Nj)I)L$o++;YJy3eMie2 zE8IGYP1uO0@MN2HnY99Tp;KlEy=d}D>~HJq1z=}UbbM`|f<`mejYXJR{jSCCRjyK^ zCZCj`=GZiS%tn3u4oc@Wwc`(*OZ#N$pWJI5Qf__*H~z$gJcfP`4E_iHeZBaRI;LcH z4?{@3*tH3rWRW(ecnrbuh5^~DB)Pm+IX zi4`9fzJB0iKIk(C#ofbK*H_%0sk`qKivukFTG;+5`pGzYi`T}`%RlSL!SHKV zuaXEr+xuf`#~-5vwu3WRy=cQMzhM_G@?d-o+5~MreJu(}s7n@5FH*eaODG zONsVQ#dVd8wXytu0c`zRK6oeS4f0~yrjCIdA9Fhfc>UTA`{=3v(&l1<7(WlXzw@zp z0^#)R*R2lz<7q$a92u&JFl8UJZLc1ScMk}=2N=9LjK_%`eTX@pC}93(Jon`YAG`Z* zZ9=#&3B4%`5-hjy_EPU=$C`m>dQE#%G1n{hyIE2tF{wefUt+gHxN|j12q^1wP<83g$jDn)%X^0a&>3Ol)?%C0TJ!Zs55P`G0<>I zd)jRY-V!0Vp&j-IYn48rWuPISrg3L`~l`8b#(dyvrt1o_Hcpt`Lyv zNvW2m+S=wb#=08$@+GdDB@_SCeaEgp?}APiot-ghdgSqrBNtHV0AlH$SXfp8P@BI+ z34p~gHCr4{ulP!StgW`gkmLOdG;r0psI2ts3y>V~H!5^kPwE_(H@rM5tq_!Jh$Ccs zj=O7f>}@=-&NTgK#jn!wO7OX<9+9HC+zl67`RTtOwgfjI*w&~ zZZNc1vd3xZg7hhqhth=Y^dyf$7+hYcX4iV?U~UQ-W<60(1j$C{SIK>_$Wy8k&RLM)a#7WE5JDS|3+wR!BgHvD`{2KH#@xb4| zhc$qm_?s17x(O_n#U^yR)raVv{~+}hB4N}u6_xqygwERH_JK>0>dVwz>Q({R-4({* ztO0~Zp&hhYFmcHOK0${T;|xO;1KOMM-ti2$8b|9g7D2`Z+xCP>0?H3T;*oA#G@afQ$zkIiE!Jsw)}f9@Z*v?b zy&Bz*D2owL0Rw`ocfHduWba}tW0L1{o1=_ z9qgy;5g@35l%MJ5;&b|n;K4mfUG(LQn$%#ib{@^aEh0XbPtTe4J6lgc$9&W!p&}bLRyB4rU zH4FWQ&Bg?S2-$%b{6WC4qds@a(*C9m15fm4qze?Apbp6-Hm*o1gQqMJTOj2z!{g$EZlZNUnhP zouk`}@d?4ZhtLM&Ym5VNJ&JN+2x9nIh(B0>o)F9^rht<4j8vL8+F~a`gjBk%paZp; z3>aAR3Q&7=x0WASog)AN4Ur$=uZckHwiE0e8rYNlGh&f{loMU8>i2@?YeNECVt=|* zIR;;Z439MYSj#PriFsP+4Av~khS>gE{V{H?cJ3Puc!F7PtQ}^t>Em>QIV9@GK^$u; z0+;wDL21$&<}>4o0N}y;1LM@8Cax-vY{_9-P;dZl$(4+jFGP35D+Z(?H1~8J!EDea zxfX5MiI64xbl^?@b(}$hyfW#|(YsJHvu?xi}4|CZE--z~gxcz_)KcAL(hc z@#~c1XHF1GMYAFx#Om4NKAJnbrnWf+DM9NhXw65!7A;AOwergH#jvw_2C&;#qmsg| z$jSb|zxzS)sfClnPzXY3D3l($A?`F=(k~srZ4c^1fedDWfQh~6*g5q8s$zpjZ{-Bz z_mX^v?)(aXC*U50TIo0g;7xf~L=&fh%$rQ9jqka-Lhi`49^Gl0Djy>HNvF>J_G#2x zehNK-0R)c~(iGongfXWf*l|G$|wueX|DB`80kcH^9?61UyxT0IW9Pc5$UIc?rsm;|J3F*4~Rqh zGe*_WUoPCEU|5U2gBpNTh~^m^wy<6^&%DJIgWlr)0x;gXB5s%GTiKOl!KB?aZ&B+= zsb43oSW&u6IA*j9Q7!4PRkEylR<%$YrEVaRb($-0Z>^^WrcVq^ORr1Yc+@qR^G>;N z&v}{4BDtV-9ch#3-_zjyYkd7zr1EQq>l2=C#LofsD~y*Tu*V&~jp?Zkn*ADCSLCH5 z*^2t5;|F?T`7bl!!E6+qVFaTIlx?drg30te18Us$g6K4}K)ty%dMx$YILGktiJ6A3VrqwX0?QLdY``^iG;tK8AY2}rV31|sDl z@Ue1q2g&l(W2Du;8)XU|C044laj*0$Q6nqT$xG8J{-S&oKfL;M>_EL?Z=uaY2a}j^ z(`fc6zL!zaG6=aERi!t!5Y;~+`cXe%I@R5(yrrLAaLcP)9@I~&4OU*V>m49}#PyP* zt4gs~Nu_DcC9b+?#Wna9$=2HF;AXOFOqth=>8K4}Xx=D6EPFya&zL{u%xysz!r3|i z{~?Noav(a1d`qWC({CsrtMG1%qF@UbStrSK=v5D7+4E??5i$g$Ln8-RE<|R%_KH*w z<`}|WquR9VIp>qCayn{;161C9x>GKHFW8z16X6=bZVhI}VWZs9jgBh_ry<;FZx;`r z9J~TOpHxxMP?jy_;~t~M`nn2PoINbhadXJ(wiQVgT3b9Lo(0xz8Y#QBB#xqg!T;Av z7Eqz-H~c*-Bl!PkR^~q{SqWzoM}zN!3ID2SRdkfLL{WIHAg5G8fh4m7mqu-nZ^i0` z91htWEcl=*u(z672?H`_mDjNesYpZ+q-1_`8_gubz-!?>hBGVdHmFGF8p=BD%rFf0pL}H~J zChQO*j7bVfV{dg|L!ZE1s(0zTQ5>upfL18J$x=NQ*Yt@W0!CHjmfgF$CshicfMF@7 zNn|l*tRf7G!rC1v4yBZ)axX84z&xxi2x$#9@vb?*_NJB&BYepe+&X{k%8EkUJ8A7} zUpwaRJzs}OBSz6YEuZ4tny}%fo4Y$JR6}d0hC!D@>RV&4!ERb z$2e$GX+~_mu)PYEA4u9c2{Ni+>?~p}9|`bd$$(fp(vXkbFvgqV9XkmyOiX2SJTQsh zV6ghg!H>x~`6Hk4MS5o~sJkQsQ{LglLMq19m0RUbq8&u@$4$fLK1wB`K3}97x?7=$ zqg(^J515SC*l=Tz@7-Mtel)0fThylI3?G=j;7&H*>mQqWYq@=f>@vJSXpEshi~kTZ zS|wbVEYA-hsVU*7s7y{33GiwOQt2WtsV`t)7275{^Axx{Qz`5Edxv9j z4~GXX^2@^|l!EDWg>I-fi-91OSkg0gyZR@n2bJ}T^ zbx6KLVK>0Za-cQUAe%8c92LDu{F0Q;N1DyX(`4*_eNa0tywl-g>n&)P23`~57WJ`tDb` zr!Nz(FX%ez484lHK2^3)%^2UJqrY0bUt|4$J@5SZURM~u>-^-$Ez4tEkiT`t^sn}a zH>LewH$r#6GBb1ch4zEwhNeLp$^Li`r z`RaOo1f+7I1sR-H3MU( zNH2a@^a`|>HS(gthIm78YCwTuhpN_?VBFy4YWN z;w5OJLxmY$f?YR~a)aiMipPhUu!aq)UhW6bQU4#tz9~wuc1yC-wr$(CZQHhO+qP}n zwkvJhm6?^3|JgV$u-`*!;N5pT0vx`G%S*K#I`8FbWn2O!mVzN~%O!#D- z!wT+MznR9#%xH1FdJ6LpBLYGc6;W+h1IUn?p$S2Y&+XNgxr+kRVl5 zmtCNS3;b@?MDs-o4;Pos&meUhNK+oQY4qn-P}-{q129W=#{^li&RSm$^2F7H$NYXQ zWgt=v!TDk(SuO{U4o( zPJy2mA}|`_9m6G{&>aEh(CQ3eF_l&@3S8#P6BJ(8H9NV%sec-$wtJ2|ix`rTS1}y6 zV-g1JrBAJrc(SlRJxruZrx1b+uM1u)l5ytgEIMiDv?KVdgMtEh8~J@7Vy>|(bsWK9 zVw|tLm|b#2ZeoU&YS`%aex>o@*eff+_iZc_Z!upFKI;uL>1%wL!O~~$MQ8$OrkAFy z+o#I;Nh`g{=hGo)Cvu;A3HhwHij!k2)h5$!OhSqhQsqI6%`a=}PU~U&sLV z2Wg2Stmx>dDnCCRe|Rb+aI!2wC^fRF$17tmaxuu5Pez~VF6RJ$gl7uH3&W8}s@oLI zs_*(PV=(Cb$SMw6w5w+3H&8|dxK`W!B%y}2ct%9fn-nU5 zQmS|dg|CJrbtxzi)w#=X8wE75@ku`m5)spNE8`dFAX>S`Yv9?XtlmppCluw z3t=Y+OAK{RNeuC_x^sONhB{{Ku%rg=NA+IgqK%KLem`YQgRrA5zAENrizLuO?f{T; zb>r1?3ucRU{na1AndD>kT6|rD1N2xZRNaL~D%Hj3$zmd=0B)ZgMKWb5RPC1N%s0Rr z1{0D%QrtlxKqp4k%1Y^XAPtjoOC-1h0Hh&ygGo$Yd&E4pdqQ19C;BCXnuK*z)iC`; ztrOx)+7fAs5Xlx~r~(SB6@u+%Fub9$4SsE^oD4;xsdT*3Wl5ZvB$w{gYBhXod=bQ# z($N=`3r;qP9D?UkW^tnPAzkxzXD6j9{g>r>TXg7WkeYG|EEA-qc4Zh=r#&WyO72rz z%kA+p*Nd6P5n~LhzFzlyK$FAO4D6Kb@6xS6r*3?LL{kff`)q4^2hcM1K@K5J8H*&F z(yhoj%*Gs2$u9kKl$eOHm_wA+ktwOPy-}<4nzsdd7^D$1j*aD1WUvq>gi`%?70g@; zR;y5%Z9AA2D$yJliRa^FOAERT{SnJ7v{gRjFyU6KXlcCY1JktG+TrN~z} zMeiBrgSB#g7MnkoofciV#MrJf!>OXCr7sSlC#p6R7iL#uPj38RX(|JTy)c?Um0QF^ zo9F~tu3X!~JI;^O^*7?|sNf-Bwhij3Jzog{@jdaDZ0Oie8vD8GbuXZg{YtGW7zWAL zmgbgi^tjaF6D}3;~98(7e)H{~?k#5rNN>(`@?z78pfVdGTMwPr9g?;3uHt4R?k$$Ec> zr}Dk*iuo|A^{}k<>Pu~zj7mGg$HLgAGExo@wgJFH>(`R=~-){!6HiVX( zyP~AGYr;x5M-w)+PIMIk%d-)9pKpLd54?mwzzv^Fy?FfuF(0VtTWXRSuLw<|#(QuS z`=!u#zBdo{Byw{VK&ZQEIC75D+|IOcpp$;vD|y%RIu zla2@1bTsu1Zrsjlu&;!VCAM}VY2is@f0-QH_NH}RUJco?M`0zUo4ICtENY!Hmh3c@ z*%}{^ZJay3W=q0PW6K!J$uA^1U!rfjp+em=rygkdunR@^!Ne3sW**04&?-0Pd_&=o zLY2XX^E}oI;Xlob7%xnPMHNJI?xXu9UrHKv5Jn)0JLC~k8MmAXucm1*M^lT`M}--< zi|#q(Ez*-$IX$)XiFD}_3iL|T^(BJyn>cOh9X}nGx$BY&JuPK7(MX1IT?3vl{Iyk_ z_XEvyk=8r~7R^LLH&OC=H&s+FCXtnp5(eor$)VP|c4r~lU{Lz{C?ftgWxu$BeBqeA zM;dRiN~yKac9UZ{OOpWYKm_f`wnlos{t0;%2_CJtS|v}7Pey4zt^%h%-`LG)a)w5k zJ8#MHrsmSjlRnNKe>E-xlQXQX)iWwLUQm3lv@|~Ombn-o){10cjn`;n61FC*Imq$f zWjxz09ilB%e`BDeO^yItNeqQa3?Q8l&N?#eGA;_b%}LDLTc*D72qriY2s2%z`^~~u z5xCJtP4p4Fr?At6?lK!odh?e`=Mj|Uqxh)1in2l)o+=Cf_8Gpf3)*|)1a~Ci@$K7) zJ;faJO8<^ypx%)3Qk)^Fig*H`H`t2gCs?zAyAUC+)lD4d#z z4J|9T^7XrTWqYV*Xc6v6QdcyVX4;;{2Q86x+LIHFP#BF^Di6BVDZemFpa2>Wv$w)K zGLuxcT)4`O^}|dJeN!6((3jMQIW}~?)+q)s?0cdpR|w$!DP?mdg1_e6+b5e?{bZYB zi)k({IB1NAo^Mog6Ah9_$&|O1w*@abj#i4vS*W?#k~=<^`*G*$GL?;YXo2sw7_;H}sjEq275 zn@o1s%pFoUiQY?Kb|0Dj!-%?ks^^Z;z5R{xMnXFlxu0k&3BP@Rz|o+ti`3IiVtLT% z$hbv)&)p)mo3wooaGroGQQKKmkbvIkNZGTZW+Uy2et+XMnkF7QI<&)x!g%9-RIh8C zopuwQIv_$ZzkfR#KVeLJ+ViOGyn{i#2^&|n-RW5{pr_N|XUGwtW<9%lc_=a#Y~sh{ z!}qOq+7&x;wf}~SesaIrw1RVzG3keABsK4>sM=$*$R0Zpkbi7@d&K!6V|W+KYBzV$ zlL0I@`sV`Y67IBV?E_YOg9@RF>)q&Y0U1}UWD&#uT-ja@#{3nyDkwmUz|ED0l>L)>m;eV>B|0`DeU&KR+8k9TokFZYGwXp$RwHF%h-%qHS zXe|hhA4$kcAgq>zPs~qbW75b45j17Hz6~5y^V`y@W#tbg>SdKC)}|(u2-~uHgXM~4 zjf&OvM}g0VYE6r3gX-s8&ISntL_OYn?=+9o$=}o5F~7NuCtc*pOjYLU@<#HxBJ!d*yM@O|XR7j?q&O~hK(K0i;;b-%+ z88Ip|XYcLC_kS}HPTKaF;#}2Qhz{)p+Pmaj%t*$Vfo@w$XJk`0$YJiE>>Hn=a) zz~n;ZYDL4bfG_sXE@4`I$Cx>PLFMZWzj1as>?|X&bbUQ;DNv4EqeS}SV{$Q{QMGqC-YWN=?e-b zKB^yD|Lr}PZF~^E1MW@rAF*y>IL*zh-;lvj!h3X5L|Us`+W6Y|0G|>Ebi^m(QbcQ3 zM4bM7hjf^zIFr3J*4LdW&~HCIQ(zaF7f?WSHCBjQ8&XzKBQ@~a#WuD9?X0NIC*}UE zO;o!Q%+%V3q=*yJ#>yncQ2*Kz-)sH?L~r*~w6G|+?Eb1Cq8FNYOH>@nSng?V*a6z6*8apg8G0enN- z(N}}mIFBDT2t{6ZaGw3lu0kU~>OZybi1h=zBmIliuk~j4%kJV;geT9i#hMK_KzRjgzO$%40s-x8`H$-;u%S&W$+{Wat#gc}6JUyXE;XM1}>dDKt| z4h_CHG!iJ+sXEWAGuGDQi78>mDcLkzme5j(>iLU)* zui+-ZpqR;&GD+9QZ1vt4_c*(f-3zp24cv+h zM^|$?zNM*k6>-oXj8B%uTzcp4$Xq zHQCs0j0b<&JBmrfGli917t~F5(I!<$kA3V|ylP6YI+=WKW=&FwR~B4MD`ji(rWX)( z$;UeN4M_cHY63rFf=JWQc{kr#G9InxqLt!rFtSUOvw9ZDI!@wmONabV%{ z$`*@8$OkNhtT8>ZK&74AS&KeJvqV@CMw~fFS%);-6V^@>(GnPD zMy1!nV@0Glz!}QmHe`p#N2OQ5mmxSz^M*%q8-gM4h%b5ZfLL;~xtw&tc_Y zV`Br6n7v1G#4gfr8|F_Wkt6ahuBa!wj6(c;I)?u&T5Qf>rsGQO=h&`Qy0P6SP;hj3 z2lBNkJXvU{)r&q$xwg1*X<;)J4};^Z#vwPe0!`@w<19m0NaV4kq5Nk})l}fSthR>> z&tGn)-2^!)Q=57l`RW9AnIo5L;MKn`gR~MAISs{b`!UwO`Zv~;;p~Nd%2=An%!L5< zuB^ka7P1f04_CvRm~@74kL#fHU0#1AQm4hhy$Ek(hs9s0Hj4_=X)-iXNDWEE-Fe1X%C%Big8rD1cthx7gSMj} z%ggm7zJbAa71c6g3toa@ayJGP&LUAz@1t)hETJmbg+OZ8$q6c6=@DMZ3*4>Wl{(RK z9UZ=t=WgcqRjy2cTn*$=N^OR@#(I|P2O4`ckE%_{ZAOMDC5(2cQFRtw%T>>}9w905 zavIsKYz1TXd;oL#$a98>xkC%?xW`*EkLO?FJy8=~4Q^sOqDbAZTm+VGi_vL%uE9Yrl`1i6 zIgY=cX};Q7u(cDFWRXmOQq+Qjq?{(>$+0S~Ai(72D9j=rpeffvgA%eIq!n^Sjy3l6 zm1H-lCs8TUf`g_UClwWPWsaxq?LA~Gq8vd|0tA{Pw^kK<+Pcjeqxa|*5dRKR9?I36 zyQeh!9B3*e9t*cQqqguZ>nr+mUhv zHv53c@xwLcB%vOc9D7tS(dope)y_(}osg8W>s8@IK4m5vJ0Uwrp>#YJ`y$CJvM#)P z!TILQSd%~Z<#Udv;Qji4_r-I-98im&K5Yo_|3M$m|52|0wJ-ihH*$)K)<3%SUt=sH ztgNUXt0Ihogp`e>gQTYf5WyR$LVUpQ1JvJ&1W--*Q_*ZC(e83keLwEv`2nO43jhO5yAmRm@L-LAjYCSvit36MKslwS z-7AMu9%e*?U}Q!YMvGubF{YY$6BQ8`Q46It5PDaOGDNf7x6-D<0OUdOWewi8<-Ey? z_oC@nA@PZaZ;H_}VZoiGo2X$Tk~Vj0$=qVhKvp>wX|`-J+nl$mXj)y}~#ZZ+$sUu@l1UNX61ER$>naBwkRP;@%3IfyK+(#q^qUtff}>RfY0( zt|%e+8X`PZi%gf1?A%iQA@ih2+O~&QJ~Hhcuvnw1{fx+3Q-TBWnpELNLX%vjRz8m# z!?9}E)N0ew*cz;c`UN@d7IaJv=aUPm+s%P?jt zU^(*GzIBLNZBYNgl237tL^xwkJeT#_wcWg9$63ZIHsTkM9SS{x_6U8T7vkt{$pd=t zuo?sUdTF3JF!57`Y)A&E88g6SEd50=h7brctN3=BebKQ{1&hrr^5mRiyUREa7_(VX zhGa;@VQ3A#S=r4hx7k|y60~^x#zQJCE7r6!qfD=s8_HODgndXfX+fX;I8B+MN^*41 zcD2qKc}f6O&Xh(_9+k^>-Lj5lK_L@uJ5=R}hXSzE3yQ89w3q=)k)=XStBCg%IB(^8 z%s!L!Xn#H05bqVbrM=-BJf6gvPnSdBh$nQ>oBH5#%aaF{;}O;ih}w zZd7WEV`STiyij-o3jP_BP4F6>WFlJaPtrHQe?DCQM8#gOD)qttJY48M4;S12??>0h zo|*3F!p4S9#-3To&er*-pYfl@R8<3O7n6Ve?&kbQDROG}HZhcS8;Dd1iDEGEyePRQ zN-;3FjkO>(R$zmQcA|~Cc%yXVz&+fX)#rTai;1)Ih1z$59`;1FX;i6aj|8PdKDffJ=Z~ z)V?(IMDnKhSOM+*MyPq<#K65K_gn$R{kT!PP}7j<)HhJm5X$P+q52fyM^Gi!q60bE zOO++CKkSREc9Uw8CPkp~p*w>~rz}wlpRTrBX6=e|6d$e@Nz+b4Dl%{zFp)c2m}>YFUF_OXP`fPI^4Fj(g>v?`L0_xHfr4t`ntck8!K@>^{i@+YG3H z{f6!Do5(=nJm(Ew5sd58+17x}W7CTJUiUyvKJpglk7dDu z6!*g2^3ZYXBDZ|Q4#ii<5`JXXrNdMUSIjB2v*}4hJ?gThO7$$(*CR{3s?BV%5pKRV z5EMB9mAUU*ZOWSi{t?8RiuRCAO2s#F;H+~YU&+}BoBNl>NDA-qxgiUd>CQ-t)j*{Lu_^$Hc>F^a&bnXIWo~B zI7-u!NrsEmD#O^70=Eyz5tR$sB~HG|!M_D64iy1-udu#7wym2|UpLoX3KMc%cE$R{ zxz|ous;B2kPD#9e3o8t^u>9=T`_W+za7ehMJlW6ou?Rq0UJ=W_{9U6)Bs{_NH~I+9 zn2V$k?`Y?O9w7m3cRWNfxLh>?9cZQBI^Gu>bc)=jM4f!^pg*7Zk~loC`HEC{S_V&b zVVG?+IR=s5;PID}nhxs_q<1_c+j;Fcx#giFF z%(+kAQ+%l>Fx)7-s1)~PDg|rH;J-r+&z(-nJSAh@0aE>BhMjiraX`8H2Hm|M&c41y zF@47{eeWC-vb{}t4ws4f)D`sh=P!qS{;Aiy$Xuoaapu8) zo>J^X{Be~mihmuoCpsgOW1TMqF#j_Z5l~Hx*=Lpegpt7a?J)h}eyI zbYU=0{?aiQ<(MBaDZ;)oTqY0eL}!{TjB+TdMqm-(-zvTboP2DOVv#`$u4QB9bcGIL zZYIE7p~ppNk_&RRNajnJ@n@U-aK~r(_%CgR9J}Z7yFWL5*>L|&UFg3*GXHck3);E= z#|@8~l`_^C%3shLbpq6&h=v#(L~X7Lc>R%x!}ihAV*-600&?*BL)Q94)CTn{%BmC~ znMd=aW{+l>>}Hw6c9~3G^Q`3?gIk^WDEU9Oo7nI~ys{{DdyB zVoXkECp#UxIk!7Fw4bjlYXDo(Qo38fO@M%ly6WTM?E3>cy3>ZT!(<{`*CAk~V0i~$ zJl!2@PzbLc4t%^bE4+szK<@EzxRw28_Z)OAa862bcP9$Hf6(>5xb?mQ!|6N~Zn59k z^}Gh7lH3~+<@Tird#^^G={xRHB)Mbi9!@ZL-6n&~Jp3}*ULB?M4r{%)gHGE^PCM9k z_hz8F-${4xXb^Ty?TLI<{@72%C!5NcE2CcGUY z`pT)IPF-ls&4{Qp%`6xd$Zlvh#xE|R8PsB^CUG8_OgA<=%{&eY`RU7+uBypl=3d~C zilIs!ly|L8D)`JVwNm90ilZ}5kLYhsjIatVAx5mks2>Z+Sl;nB#9#{eySyW7)GDWP zP`PoUzGl&rMD1!yN@me$k*x26;ow-tS$uA}{=!ozoJ85jKvYUBhN5)nXxq3IAjT#{ zV1((B63b{!)48<;0L%7uM263k!afpR#|C(OLBz8<)5YCh26WA{Dts?lxr9$XSu%Cu~ezIsmxKHyL8IHfd z){ei=_D1viO^{of$EWDIj zF-%Q{gs!eUb16(#a8X$?0!Rd$ zk^O4#-?@T8O!^_2nP`$*KXXY6e$Rw)+HkWEL^cs3ekUI6U#ABZ)iQnxa|AuNQCplS z`&h5G04&!XUrAO?LADX(IUT+^P=QZ@S1xqP;m1;N%8>Q}Cghlg?O>UtqqoCF{sd8> zs}x^8o3m#Z5Fnuo9+njei7KEy!*-B?NS3eYi1OZwg3=c_7sFmsJakcQ;*{)8de&Os z`EcScuAvy2bLn@lS({kZab1WV3+(ldbgr5AnVVf|SA2pzBBSQ|TVN*3QDOa@;E-#z z1Gl8A6Z9-%g#j6Zj~o4J1lF@}TlhAW(i8Qj0E}XY<`V^oZNkgp62${=q77yIL*lP| zfVclqE8si+L>T0eYa(Cw=#CiV5$qp@jg~QGor*d!w*k+1Uu6}En-yZaSkARbzP4+9DP2_wbI8*R(v_no$+?19*8p;nW7me|=MHeuB zQm9y{^4CAd4=wV&;h7-T#rLCX@>wG+bBCN>C8I)?S(e-m7Z<1v9spV=8jBlkD?4tB zebJtr#+!hxUB9s$H@7Fy;O(KA+sjC^RnygnTRwm@cXY|93k@LFQVgyH(6aix4KUV{ z5=QCuv48gK}!T+mi^Qbd26NroPQ+FTyUUy8@>*K=vC$_(T%Br^7C) zyTq9ea!`$cXhm^w1&44=$7KVWUq_H;0vXc)1Z7GvgzGmhOE9Hde501FcWRI7iQsr) zy(v}lmvBGtw)BP;Iyx*$rW+bIN6YaFm&GesATj(yK6-|iw$$Ncn@WJ}oyTt`I>A&c z;7$5%3wDLT(;0s4EnJ5>8RT%s1~8?OmEVM%xe+uug$$b(ULKwv&TfClS8nz_`qxc? zDsU%1N#?fygOE>D470V{`V>3Pql3pIFGkLh^@!VOo?b`L z<50>f8IQ8U8(ZRci>k-R?rJ1kufw^q zK7jTRJLhRb6HJHd3wJy`^Edi{IA`zZP0R<(n=^5Jl7KGDzOqy~XY)5@F#wU{*3zxj z6~#q`(a=U4%X)NYs~%+=b(1P(BXJejx7V#J$2OzYlH2wi?xA;C!oSqG$5vDK7^bfw;4b}k@Oa?BoWlRjb>#YWq=+yFzjHujposGd^yXhX^(rLV={ z(NlF{8CAMwNbn3z#N%WFAa&EW{<=oJ5`_=9gw8R0&(d!rEMlVgv2yXnQuo}1^wLbm zPSU(XKPPrt;Ri(qxFwXJ!B`t)5PTGRC{=h8Ta;t2kNSjG%?+*zs&Vota5jtRapq3h zzk67Z%%6+0c-f7qSeO*2oqy!g1mYJ(CR%ueWu(@7pod295`9J^ZL!|{VgYiY zt^&qXh6Lg=$4nQS?MHiC?59m-;by)=>1Dm6q(xx)9+NIW5zpIn9ETq|n3A8MXA0#C zRabS{D?X^0vA=&Ol)ntW72GKal`@lCXxrw5Z=IgwD~9UcMWf}|oz6Xer9LidM0|ue z&jFT*b5dy!tTj^7)8;+TX{r$$UyF!|wC8fL(U=?d)cfx zRzLgb`>sAFQ^cc5E* z8Lh8B$X5Q+G(5--DHmY`ugYLK@r8?E55FVi6`f;@h5E9+(okY%2YmzgJM&`l# z4+!`A7xLr9CW#h6)OFIVN8~_am$l%eA)9hqc^s0jCnl&#zfpZcrW3#lnL*~gEA;DZ z6cjKBapB(H^mMu1a=dC^SyI?OSBr66; z1+k^_$iuR=R8oPg$dHYQAY8>PyH~|0Zo>uA3mjl@{*13wqow^opc?w54yk;Tc{IzG)r}@VT*9)B$!j+M zTTr!danAH)45DQ1lipr~_a1-T2nM7{asQu3=k^ESM-Oz3!pVZmxd7G*ZI_!)rKS40}Ix=p^ z-V_d+D~lR26Osv}MLyX?T(nC2XRcZy7>E0I3t2a80==?XYN$GzS3+LaA&du9o-sR- zHocEH!Ils*z_o_fk}7anrFn*YuZ)Iw>kk$36M8YZW$GTpr1ofLT7UF-7J-*w#H`h{ zbGKu>?=0gUmqFjGt17Z9x3jtOloNCBH1577nG2Lk)42XdsIYW(bo|szZ2b$cX`Z0g zN9c$gBI&XxfZ1}MOi=n*`gI}kx3Dc&2qKZX5kD5`VY`y{)@JxIaWN^0&?kTti z{{rup#bkFN*0=&1pCIa*`5Ja%zsm!W<^r1}`bwl{jy&BwC&&w0$S5;*C3I-s{!=oTH(BL6Z`?eT1tp3>U?5SOipGcY;LM4z$ zWib4b;k?7yIXSsMim+cpp_S_CW`?%AvbLK}uX7U57+&+n#mC1VY-9(OKpW&~YipROQ+4VJZqcthkN=1k8F+GH z^mJq`!0g&w)VVU*LGLc#5S0nweB-N zMcyhvn7nGZfT|kCn^syKw~ass{q0>#UEt}pV4x;Z;z5G~X|rX7PNf;swqt9Pv0GYi zr62?;$HK$NCHpSRy=aM3b+roBVd0J%3gZDDGf#{-p&ols!%)=WOz8|(RH=OC(evab zmrR!&vGHPgEEzc_qa~$wbVgBoFTqi3h%|$K>~WTN0P;XtN>^bBR6sFmAFOM%!Gwj| zRb_yV*;|{$PApI_r z{|mDP{m2xICd@+cg>yg={FN_e_7}Ovvb_(*F<)R|5`h;VFrhj%H;Y?V+Dg-+aF!{ZUX{*PY-(%uwXC{iIVqAAj6b%2b@Lhd4ft+6 zPU~&)o*pFvi~oM!z|B29%6{$E<30WAKJ5wX^LgJm{S|9a1i6%c?~wjn08<*tfybR* zH;6#2Os!0K9t3HHrs!UXXo1IAA7ZQkZKlFqVJI=u2-lKcH_UPW5hTe?a^**kD)&(j zrb?2FkjjV1kgIZ^4F`7D9f|j0&!!6>l?NV#HuBIN`J=IbKN23zDR&e5>Y*;^A{^vJ z?W-_w(@6Ugxauk0cLwq-?3?c%xvLph+d1O@-h3?wG~pL;iA$MY_gutXLy8K`DgzDa z0V3i_TG-Dngr{`I4=EZd(n$#1D(U~o&tSerg2V(&;P|S>l|7rtxC_r=O=8NKIfUfq zQQeZS=Q1RXIXf6kPQYC$Lrh*4sZP&DUt20w=Mr>t%sd<*RO86z&2>G~F|SJE5^?l{!~^`3E>Kw+B3s zgVZoEX$~SoAMKU4`XhB8C32w^VYqy@%mdSWh^ zibfN!=gEt$lQ#({*{MaQr_~vo(j^98MAxc}A+r z6h#yJHKjbr7g~>23JpqZY#6utRrMeZ{Ptcvtv5<_Xfko^M2E#^*P9r>KE2fV<%|jfGXS>xhEr0}2$qQ!Y<7m+cZo#B^dbBsRq( zFUHXmzXGztoP^oO!DO*^@olff(67DQyhXaj->f&|>QHOA+I#!VzgT|Ke|cx#*~ra> zKz5zwI|K9hCk9sD+x*F$01@rvKcci}K zbw|1&qLZ`Af>p+Su0Sj8@=48HU}_d%t}@p7X>`_BR?Hm0RM=Np?DI!-{~9}-V!nKp z2rpZ;e}3O#K3F&5ZCTt>80l57w;R23R)p&#Dy_#*shf~($MhZMy`lMSv(Gk17X=&| zToJl>IUvt`T8YK0UN?8;rH;W98PFvayGbmdaEtTlJUIu_yc2j{mh=I5UX7u#S8PQQ z925AqbDlo~cQ@OVj<8|a@bG;Q@)3ebY0Lwqp(u5T!_IfQ2xr&-=h4Z z{8aVEN?&?l>=cB3Y>ze+^gI|!R&~aOts&x`#5nL-uO#xL0Dq^35DUxL9d(cwIOw1* zJ7{R?#v+vuSTG+z3%W<2`eG}1%jNpn(SDvla9|~i(D936$J-$lySKvqjl+jSPTd5U zMa-A*cLHXY(}yrM7XW-Z6+8ui<@_~b9nO>%j5)I{X}Ur4yrM5<4kHsn&+9QuhEA<> zq&m~3G9o0}sd7)>D|Ib1h`Y}oxS;)uWLyQrjn-zbANclDM+mFki*R^@XF;DF>YEZ4 zRI91oO~v>K{?X~JT@2e7=d~eCcLbr~uKKVX$}c2SWDjSV&GQG%nR3U^RJDa7)Re7f zw^mQ#s)*EA;zgozs5DjJI%(T7*qt$Ipzet|RuIqXqDZq5-}mWE7NYPUKXx=v;WsqCTaR#xDq@|Y8A!y zl`TF|*ap5C?(32V@SN_(N@DK+%RIkDRVfPi`6~^8`ERbe|5ztCll&j8`#+?p z)J-?75tPwBqX|y2hX(FOBeGbVK@#G`K%zu;f*PE$M(WM61Y?2;QbKuZctJU%~PfPUL-hoJ~Ao^~j=D)zzyHeBe#Hf!H8qCPXHII!0PUbvTiIO^}SfiHLd zq42QbpeqmYA@WB97_f{ub95u#N`h%`=^^$@>XbiWn) z8E?g)0dL76=tm2fu=F|ea0WT6aHj84f`QMjP>qu&%*5$aW$rnN-u{lh@e`8SFB6nH z^7&|YMpNPF=)eK>jz)A&i&a#}dJ5*>q3>Wfv&Pm)0m;}dVNjh;A9QO_*gJbcnN4UwsuH@$ z3=m{NqPJ%V(yn-%Va6OqzF1IL@M_emR>;4WRGHquUYK<0f?ZM$_^f&-c`P1llBAt- zQrxY;-5$+z+MbZTg~zJhX9nWP1g|-8>8>S=VR70DONwD)px8Bj(BS-Y!_2l{AL-`O z9ro&R;DAHKo^O;qBfx58J!n0;A-pbKAJLd$%rs(}88cuSIzzz9!0NyX!P;b<$j)D; z{mOXO4$|fbO6KhC59i_?9Cz;4)7%QF=``XPG1)wTS6=mT)sXa#t@o$r*@vRbsC|K@ zgPF4C(qeh;v*=^BM~!;}oY{S>T&}zZ#rm;suG*ln*98vQMW?eWrfKAqyc3 ziM5E8%tm%2yVYVnyTN1JblP;wbnv8lh8T&)nlLu@bHkMnyIo*yO-mI0trZ?`5iaRE@eK&0+ znpESPZL)l8(N$}aIqL7gs(HFOLX|e%p~h*!p*ndDt=$KRV^I*xg+70#&5axT?4Va_ z&SFH_GG*QhPA#pHi$u$yDH4@7Wu8j)B&?FHVhEKX&#DWg-HLit&#VPeuoZ1m*J#&*;yCe~+cO^|V zsGW-%X(2bxsx9>lIVE|eY&j@L7ew)P{`|8vz-=K_;LZfK1kD=lsrg##vgU2@`0{>N z_|EF+#Nbc_fpdejf@L8*!L(3bOJ)V$0X`d#?fZiqSA0-0y|5s3(d@8KuRWoE^}la` zU4G-cP_k_9QTjS8ebG#Aet!ip=5Je=K|130aYwQC;=^tTkvt{Xl+8XC;^BY`%J2R; zQ#db{+7(%|29hnnf?I6ih>3BB%Bqjl^%jB~ZfkxK(|o3bCa2Xd_+OO0Q+Fm%x2;>T zoj0~^v*Lih$+qTV0cGliE-`c00)7H6}KVhKHKA!%l7g-OdO7$^Y;uTGJ zl)GBt6^ose8}{AjB#F%{?NXD_146x60k3rQMaxgUQ)Wjo-oyC&s>=o4vXS*+W0PWtgw+(qW*sMK^K zKd2tz1k^v2DML(CQVW!4Qdv@YLtp>^`sR!FrrjPo2lDS2Jl}rD&&OY>Au1YuRvKU&05oP@lu~a< zArZA8AKKwC91(;p&WSRPqP>>D8`?y3XDDirP@Vq2G`z7>7p{aytqGYHG+C>O@Wxno z6HgzzStm_w4*+O0cSxC@{$%}>u#Zu%ljoy9tZccVjKs|2c{SoqH~{<9NySg&4~R>)M3q@;k=Wb#9$Aoct)^NSmz2zrH$Va2p=%;v}cv{2ewQDQlDL5hycv?zU+E z)my%IygWU+x<21nOFGpBvrU>bB|(H}@Sxl)eWygWjTei2*8Or8Jm#n8r5A?deJ9OfK=Kz)VvGh0(j9tb<*72h^cdC| zOVi&Ja(WT()YnM4+q%KCDyh-P*^~^wU61;BgV9hv0BXFqf^mgG{A;0lNANX>3_uW1 zXhw6Ci-}EiV)H_Jfc|UN8KplzvLN>cLd*_}vJ))OS6*7&9tNtqpG~|jRz)O2 zq;5v0c}!irSu9E698F)MNN2vgw253hL7r!RL#Mshv)vrwmjv6Yls`Nf{xWN12b2O4O5? zXOC-gfls=CNizbu+`DJSGo0jb_>A#Qjd|n?N$z$}qSH4f4!^NF{$dExVC<4OnH_If zJbOUtl$S`es28=gF%}juAo2PgP(@U}ufJ1ozEE0QX%J!f{eQ(~E>|Jz2LAYxi+_%A z+5ShZO-bKW(A-Af!Tmqm+Yby7+Zfen+bV%n9|~1NqN$EnB=ZuynP3Qksw%%o8V&$c zjP|J~o>B|hkv=tyHbOmu*=6U{xhQGtu>f-ciQBX=r|BEP--pRR{c&9{3`v!k{_??d z@{^`%`f!oU&j-X1P)riDy9BB*`k3}AmZc78@?i!z&Le+?d7ID zER|rhZ8jo3Ii6-{R)LYjXz8uTR7)fjVEd4nqiz~Tb9}a4enPup$A0GHPv|rEla~;% zr&iKv(rJ5o5u&|h%DYluaj@nda$2NFSUH_woXL)bJyF7KN>j5S?m9+^een=tdFO41 z@uWg~&!XV4S>A2JLX~oWxm133&T@v`B=0@Mv_k#vWbHKl_gxtJ(r;vUh?_O4aAa%U z=ybfvaFey+HsLM&+-{UdNhYL~-%Y1c)@nXi#Ab~>-@#*eSQ2b0Lg(ZtRQ5InOuUYn z47PM#F0zs1ZZKQN=JPLbVJd0%lyB0I&G*}#^KUC$n`Vb-vcaIGD%|iz!`?|zo(@2P zb#YYhQpDU{sbfAs+Z;%TZ0gq!T0;Of`_ckz9!J&WYQq>qCj9~1eTZPr*LN?rly2BJ z3|ah@hk(vs(!(7*X(yQA@Qp9DFg|DyL0S|=nl4@P6`a+kDkYcoiiA_4^TxCAgbMEz zsHLV7Lt{kV{NMrlq%(HTxWny&Aj>%Czo}5O z^69sc-rXd^?%U_6#)}C|=E0_*F;bzTW#_J`h#o=Km9LP}sH_R^9pqzxnV{2s#g za1tTJ$jLz8&3EX8 zZ=h%2%5(d}Ao)$rk9}LAsHS6i;`3E@-+`FK3q3)6qb^CthkWQQkmt(BO zEyu$VVId>UPq~J9V|#=}HemW!zP zEuvC<2EF2rSMXFFH_tT(2bEY8uPrq`J5PGk z)P4B=dzLc`dN>usj+Xq>OK_wVCX_r{vk$y%7k*5+8c;~Jnw6*Y7)FBDPl6_Ve)^pR zU6!atL;}E5JVZD&imKfyGm2t&KooZrBtm#58MKZ^44IpCV`7jAAMFmo>5BdPNB}z` z*0vFp04)~+W+2=)2}Gw?36?pi!-n5%B(zh4HvD1nAuoA=ey5AQwe&TIBX0i= zwdS?H=y1odW8W!N)r%Xe2=k^!4Wy#+0ajKsTWY~i+!QSXtkQ%(JB0WcvbgA*D=>W0 z_!Y3}wRT8_+b*FfPChzRTWdsa?k;}Y`N{s@C-z~~{MDiV@c7gG zyVHNp?Aa=on%FByKIld@jp`^6UVY+Oqj%DfYxTI~GH@~$u!F09nxHH!(upD(gIIMH zl`7z+ZH>~Ij|rX&WL-P+CDOJoI6voO3tktYeE+1acQ`vB@d&jx5j>~YIGIhi)7@t- zzaDmc|8e`Fs4>KeZ2tyo_BTwExNS1i!-|QS;4*Paf*oYU4yA5D7gIkrHNJ&A{Trqp z_Zy%(=pr-HIjIWQIHrUB6GaN(p|3!9>NL}f4SU%oMeT9I4>yHr^%ZrlsFOnz|Xkuw?4Q8^I=WXO3wx^3fdO=ISo(!@$M7@bvh++*QjB zS?-%y22g9(ZyKL)7B z+L<~2VYO;ANG^XgeVjVEa@cjF>vH+t@rVCYGt}ON|>$T>qTLYOHYmTqEuR9rAykf)^f~pY1LYD0D(1GfJ?Dis5$|f zD(!4V)W8~8efvv40%sC+NCCGWu8`^Kt{EwT`Zl)XPiJA<`&yer_mLHzz_Gctk>Jx*1 z&hGm=52DaAOs);l41})j0(BYVvYK2f)@bp0=pQo{GSxqE+w;co+&7P#aAE-e3D=Qzv9fQmr+KTe}psiiMFnrI_U4Hn^-U}IDKmKUA zb21xa41dNe%2(yy_0m>+IW|Xw3oRB(>>em~g5U!>+=wSH`=9C7Z7qik*S6VoP z@my;Xc5~enR@C}~fRUXZGp^*ovq!|NLU>vVV~YZ9s=9Q??8$K#u!l$P%*-5_tY+}+iSaNF+Wy*l{Tvm*q1-V!OjI?-`dXasbusU zZ@Ve)cfFcpvO+Ylc@Jz@6x=htw`MyB-o!x;nc1o{iEqu=f437YmCoXpL^hhd$#ZdG zvXHr*U@np!a~eF~-R@%eC%-br%W|^gs8O5^a#jn6{kZ}mWW)OWm|9aGXcd-rb}ij2 z=sNXXchI~IRD4AD=PSXGd^KB1*Y`>XcQ@J?C|5_ma}7UpBMAvzV=98QIH#rOZI>of zhSWocsXs8gbB{N`G*}#CO1YWqNX=G~P0+;xnd3@)$lKc_LOeJE#ekYTU~`Yu>$xOl zrBCI*nnnlOMhAK*Hu~SB+8vRk(@9xMU+4%@+QMmNy~1J^>WoiOCc~$dA^UqrCYUzd}<)c7Y5-(3D_mP`d z$nDeq(pQNW=nUjbda80b!5WxJBZt0e^`CG=1QuqAP(L$Xx2te_S0o%Qj+wOLXX6Z< zFd_#m(20_M5&VPF`0kT%Y#%0kjt}^iDQgC!Aj}X_FF9eBnYSH7`Xyh7)?s7tB6qy5 zVSZ_QmoLTqvMy$9DBEb?@^{A(<%R00i+btk*jr)agEQ<~gk-7R86QIV6oRjKr?$IP zU0E-|osyy1Ji#-?zP++|1R5-=dYt|gz!S{L6Me!Mh%VO`nbci*Z=aL0HR%gq7*(Cx zhC!^EVb(&M5S_@KZx!Nk@Ct04oPqZMII7oGHjQlaHT{@oJqq80k`jLMjkQhaR-9Pn zpKA*O5t`uOh~GP(waf70>-1B~AS`VjfjRVfA0^^Ko27E}0OD48L#}^kCGyOU@&S3- zrN!yrsQl)xoa&&ecRDQ}&R2XTN*@Rjts=i8%~=$k<`1T4POPvyn4D)u%7m}*2u#1} z^q0Db$L8?Rj@L`Bx9;TPrl>=09Q(hgeE@8vXY`NJqWR}Qi1mLu?F-qu7(4vuu&?^h zSMkScu}yX*UELxFT}-emtN|%a5Vn=HyqA%%JWF!5{+re+XycG=GvjbL6Fcu(WNVT0 zxqyRxXs=`-JhNTd1O&y%_Im0{c2&0?-)Y9tA#s_-`EfyZ#{Jqc=fpFo;d6}H5r%MC*vlQa0Z6Bq?7#Y0#CF(tJqLTXJa zIgM*-5wm2PiFM>Ww*Gp>$V*V`B_++8YOEs+P?CP%uJJ6lD1*^a%jK-w4-7^t$NuIhuaJEqv;NDG$|OD`yI|+V)M=gNxI0Hc%|0ujrxyv}-CDHI z_haaD2I%&7C5Zxh2C=E=4x}-A6z(iLN%O7kJLb;Rd5tT6HjB~M=!hLAQT$`&&PZx1 zpHNTb&XGl6MdOlcCgYGq_oV=p@IBa@z)AU8#s_4<}k8Yu&>dI7k9dJ zk|kNJsw-|aBJT&OnY|v!!;q7PgNq+u>v#mxEL`X-?z(R^CvZ>8Z@Ee9fpx2DMQa&V z0D0wStlGKRGX5aLTTNg%cIQTHo!7X{AhJrCtJ9h!iP@qFP>6 zvt>fY#(*ae6&*1I2{$q#!o-&*K`9)&6*AoG6MmIrVq`^2skLk?i)LtpaPXy809@bW z#xA!+4NF@tNOa3xPn)UeJU&i?*Hv%Q;4Tz=y=sX@7`{mz`Ejr#fJx)x@M7VW68(u8 z3cVOaK)2YhVyzo6-1BJDH!PuQfn>+QEJuMkf}R)>tYd`Q2pzD0k0Og5{IRCq{UKr! z?$gHdg3eZ( zLc5$jW)T%Lr&*i2UGf{{-<&oXMf;Z7v*12;@bJgk#jiWk4BLw~;IgQa3cD`qpq@X4 zg3N!k3H<_v%K-8`e)Mxv?5u+DQgJ3ame=kG*DaR6Xan5s!W|r?+YkathQ?eE55Oo zwSH6EFDHzpA`yye2G_|jToeDKHrDAdxF8t{1;N*!wyeOXf)g%Ox zk1d*8iC}Rv1oA!>2KXe$6{#mcL3#1M%m1wCL>mn>(=5{l->2TfeeeL?}TLZyoN zH#f6I0E=8rz#*?Q>88$(V39fDpu{-z%G+qDK+Dq2S(Tg59}LY!aUZQZ<7Spr8!+GK z3}0Poj;~5QHfI`d&V6ydQyfftR7}(MT|3lnaYT$kH>2j!(J8DsKF%HG zdge90?DFgID1i*-GZSd{6l(+ zjN2TU)UHaQRIWgx`dM^*?c3Dbp2r;d%f zc>Go3|NT*=jIWy?Qa46kNrr5W#zyMr!!6bcg1&zb`@3C z4R4tcLKp+h_c+dz%Z4B8YON-kXNpsFq+&9o>ZCW;(FM?3opd> z3|O8g?qK2(6`mrMWGsph9pF$2;TSeJ1YJNbbDiw+t;8 zL>@soC&4)tz`Vy(R4TS@1^SrP>5^ImG|n~EhA1~n}WXitR$J&XJ-{1o6 z^0O7B*Il7=Wcuvl!WiZU&HPBz^rcD@({0b4ZbW5`EPGv#=&+!O$O|$ZacTA%8@+#R zT^FYCxU>sd|5(b>=zwSn|E}yCfgA$2FniO{2%B$7ye05TtHp-el0NlGcwCwbBZME_ z`UO4~xC%!oaJo`t8`AZ-5&G{D;1g;F(8w1v^FH-7Pp)rmtX#U`ogl>dLD)F<4>S+@ z_|;>1)dFqq`>P5A5#{j^o4pNOB)Kr)7x)5t@n=_WRs{oyG46n| zZttOk@G2$Ft%MYSW=IC)@i~tPxs4uo1fjOXC|-LJ+H6P{^oj=>9MtAfXJcSMMi|a9 zt%}^FS{OcHT%u`kv# zstmw1F3ze8tst|_iMVogGtz{0JcDLht|FszWozc@W%3|W8dU8Kg`SaKriIh*7n>eh za&HS~bU!6r70H8)JGoHQWU_G4$!q0@ahPxQll)Vrcip5D%o2^Tl2WkECgdh+ISWA! z?eh`RAT&DQkda`U{(}4OVkfaiK@ZkX#TUl-^^5C&T=k8AwmL^+VH?N)Snaaap!86e zFu!!3)25i>(|#c%fktK|QV0(X8bFDYWPl`sMXL?ON%ilWxNc>G8B{IdH9wU%H@Y?I zST}`M`PJv$@mcV$YgE0gtxw=tR8%!pjl9fE+N2l}3kaHgy=?n--SBT`@_c?-y8^5I zErFPes0e7qT7h(~l3M{7pmkF(z68B@^HkFh!oB*3;DaL#{7?HVZBL@->;{y@lwWMjF2*;T}~fH4r=Yy_Xh{JKUB?=Z4+ zCA{wI!n%gJ_x43Z*fqt%gDucfN&of_B5gM?s zUP@7wB0^IKdOy?5gcfV9OFu$67LL!$3eJ8zi2+cNv!y_(CJs=y{UoT)X|Z0rDOjxI z>d2#zLbq9L-W4r6adZ}xY%smc*s|}tP&M3`y)tWJc3^xY^(S?!dAX^VOv7go*rzSZ zP{By?Ve1Biy!1{$GMTAwEnw91WD5XW8jh&d4t5>^DzMMcOfw6;>wK8(5pbL_u^Y-e zEu+;GaB830{IxRvU<_naQs>nF-DC+ddXUl0w@TFh4c2S}#Kf(PA*pWCFMkR(GHI18 zZ*6JXT#L0T&zdy?E*`SAiNu;cH_8Bz>^1^G^p6eOE&j3VQ`E7C2EmYFLl~ls2^_=G zDmkGf@K>M9rySG509Kh)FI{oUU%E;UkWrM`ppiPRBz4t=aT!qv=W8IP(YF5Xyt43j zD=fq&gsVAwg_%z2Gr>)TY67HtN0Efn8m#}$1g?SGK}7!wbY=Zi9r?cX4c?ch=US;||DeJB-!7C>)K#8z>GpqO zBc?<1NB11)rj`qErwoGE@YR_!?$5_dKilV({DR4#N7 z?X&^q1n5N}POKsYc8t?=$#iNS#w+bq{hZLn?h#>>?CmqvsF@#e>DnZ_7WgRx_9e!Q zu#W0~9E0!?VO5&*SILsZ&5kSN=}~$5oH^(HW$P+Dc761$G&UDBn@MI%UExv zY+3xfh#ww4B83=AX&g-4#3WX|&gL1d1rfWUA5zR2A4a-9Wi*dbWcaYIy7=V6T4Qm2 zZgXvYetLa0)mT;L`Zj;P9W%XMQk-859U2o#oy&9=yg-EM7_eY^$`F_CG6 z>Tj9*BYcIY!=n<%m{0jakQI+0z}Y=qnzmpJG4(ec@@1*INO}B5NZFy!#>ysIBNDA1 zh#~8zMyCDb=R~QpOH7umkBs=mM;J+^%AQM@Qa^}ozIrA;8~a26CZ3b$I#OuSG*ZK? zleohi!)q0D96&n#xVOji8)*zk5}$dZVdZ<=MaSc=E?p!{^7z3XUX|yegAeu&*cYM9 zh_|L=JAiRO=(%Ri7kC;kU&5a^s7ujy7Dgu&V;-nEErLV&{Z!PIyHG4LX=@{92zGw+ zewy`)7aen1abWWLN#8N#Q{~GHm5zC5SPSQ`u+@ghG9vCp{FyGRlql3A=ed8r_LJTI z!e!Cw0`ZscU~VPN!vt!~!x+&gOEF~I!g#w%;{Kopd)JoGp%Yxz$ePVIXpmhc7!#&lU&wWu1N54#X2`bhl-2H3k3klS-HJtK_c-FIA9N?_9TvR8E zrC0%JXzz^mQ7vA0SOja>p#mGJ0UmbOfqcIyKXkYkWnGR)BXuoaq#ak! z9`R%vArbZog}-F{A?;v4TUI!d7dXN`4bSjK{{&B!_iHDvKV1QjVAVzXoR0%dzEP07 z^dWORIjQ>e^$hkn;v2Nt8?7)>p={(WXjPTTWlZrSX5)FG^4NF)g4t?K-+bJBt-yfj zM;lb(vdh$}QIk=f&~j_p<(T*p{lZfX za>0W-2YMb3`dVhz9>r9N16UtNBw1o}BNh1=chZGWRb~^PC;#udL38w=v;mWm%|tK1rGDmN%7vV#a-EL%NrtvslBl-w7!s-2b-%ozMGJ%nPmWw{Y7gJnJ1=3nN&KQX zSNlFLY7Hhpx0C!1ON=LOcurMc0?@SRIQ&$xt$9ofUrUCi6>PknV911}K4|VWPxiXK z&K6);+{ovg+I1Cr2f45m?t|{hZAYB=My8;-M%R)Ly)hS-x%Ov4sx^Di1%2UDW#1Ef zdH}Z-)b$SLL`N&~gTkKQW(4FOo!!D4GWK5VmySV8{>LqtS3Fy({6s2+=5O!JG|Q8@ z_olyts;%e6!i0`DUK=gsTXBCvrUd&wTBQcSu;>oI5o!@5j0s~SU0^cEal|b=ME)~;aOYJdo_S`>d>U?AB+;eD;zzklA;yuC@YV0a%)?ZZ|9v;>nalH@> zGv6|zZ-zM4Y{vSSem%j{VZm&YS~<%MDRlr8ciZfx`Z`k-8Nk*8-aJ(9DOwyNvy^yc z+CT5>By?uv6_S+uW4TqwkXwA;s4HB!O|!9wG^5TpIN>Na^u@gw_%s3C$xF^bw9%W9 z;Rk~qoK#9G!QO9IyovOhl%{LwYE_Vv9VtLsV9KtVQBOtKsOP8L^mTv`M+I7 zX7besKO$KsK&^y3X%|L^GZnMq$ATBAB6^`>!n-BI_w+l zHN=a3ECJM1;X*bnZ? zm~)ZdI3Hcrn?UOimGXD(>fcacO131zutIt#ayX0d6UH>(ND864%hP)5gvW-h zRHuHcf6bVaN!)MLdZayh{lDP~Tn))DE?}0%J<`Hh`nfxszj_}?0s@p9E)IiPEM4wP zin%{v=bTIu%S~ONtC}S*+{jT6#(=txNcB+F3mn7dnz|efC^oc9O;DwC?u~Lsk2!J! zQtd;0tEoAH7hu~8Su#NuV9(I6m|Av}YJ+D`rS?dJb%G*EY74dD!Bp+#hrPja5B#I( zQBVISps7#~tyMrTHE%Q@U_AvEK)l4| zbNp`kcGV8q?kTG2PS9uF#Lb8IScrLv^m~^M=@u>p4-blD^8^h~n5PbYf*!a;3Z{)8 zK;y+3R@LrWJ4?LGKChN{L}$uOD;e=Zc8Y@RdL{vRH;rq3HItg>gG!Lm$zMV)cmy$G z&GdwQrj{mlOYXME@<%wMCyHG$du}%kXfE4tTYWm31JToY&o64-7H3l zk@~wf685)EEbQyVNDC*KA;8$771<#P5{DF63@RRI=9FjN=W}OXqQL$bstE3$q5c!J zE*fX*5Wu=Ja7r9i*1$W6@Rm&!`y12nuO4uPQZ%c?Ue0ZehnN31W;`D82J`5wc@QFb zoJh<*Y$;D9C;yRi{oYXK=vVZhEQV@>FX3F^ekdYbakt1)M=UBHccKRtVD{F2mzL~k@v{PcV-%Oj$SBOm!PkXUeeKS#g#84vmKr!(H8 zU5HG`1n9tr0RDd@vOS?FWl9Jr|44R%|0Dp7v1+}D+q_!Gl&uNv-`h;TD81kdYDa@< zMbcaiX$*bAtOzz0^o)-M1I6~8kL4-bA8q;O-Z>R$FgAhiEgwkX~s;G%xy z;o={$;D0O>{8!nMake)2Z-2nqD*s0xh9`jy5&%mEMr+iu_(LQgxgN2E1u72Lm*H1n zeH8~g_B&0S93^=Brs-uOv!_>eLpeXCN#kRE<;(vIe#PR-)kIL3PUXYFp&TQC?m~LNzSZA2p!CkrU=oi+l#xE?gB4tql z6@R>5a48AiQUd(ELc*@nB9<*bU=!3dpvHa$IoLe78p)v)HqtUIhjf))NETADP(zRt zI&$!Y(gh)4qUkQ52^!9fvncc6dL7ALR^SNrob=hNgx-?DBo~p$6x>2YX$;a***rqy zL#ZjsjrQJZKuxT>hXAwVoYHoEcK5;KUv87M5JxRNTe~;U5w=OKo%8H#Mj+juWaH0h zsDZ^qy0k_%`CS>w{&BNl#woTUowY|!_dq=aavE;*?D=u^0f$B{nU+E?Vbh4NIdLI+ zqr!oq?ZyisenvK1fWL??&PFS}670oC+A zDVXlxS7co%VZ72JFIeY_E!a?n^xgUZ!V(8}LgV1B*qPwO0S1>#gGI1~93roi1WKT_|$2y!Iu(jwRqDhct?<%%Pd-}{qTrT}~V-{Wd z$?0jIc&ooyP{%u;v^v^QPHy}^U8wWzjDYqbRwxEpd&y@bxo`y2=HX{xkuE{B${^&y zGg?Cg91IPsp6x6O?$b zV)xv0?6TH%UcW>m15luKT1Otep=CTW`qKmjzO`AlozHlJ{Uw??&l6gzZ*R=HW1i(+ z;WJL=9AGl3_fs@)B~y5BX@h{H5(XZU=<^c!qmZpC(2K`i(7~Y=KvZDn#O=eH9^kL` z6w&%$h?}=7(Q2o+7B=n5U%HW}#ayP9&V8dZf)Le(FWlUKWMSzGta${>crha;3lGqm zgVmDAjlsQKRCYa0oo-Rnoj~qaVL>(+hRAY`(}Sr_qO_%n_nV=88O)RQye&?braht= z%08}$57F}i=rzWs=r>G^9g2;|-l#*}T263Y6snWH(Eqy_+@=zwQS@W+!A1I?-l{1% z=o?!8$6)${Qt|vRf6wNRzh}TYpOTxvT|T2^I>f+uc8jFttm>?b zu+4bL`aEQZEuG6*@dO>G-Z^svR8+Ax)3N7rt>NwFwPNEWE3?Qv6Vs7n)SUjClg`M)!-~o>f`4{~ixUgiks(-4VP;=^x92A7 zWS%e6CwkUS@6tNorS?E!<~G|Xb&?k#oqw9-BN}VuM2-6c(Je{ln`JET-LNc$1-mFL zF&;E2K@p{^CTB_lEpSnoi8|+0oQxEVW$m*U3#MKv*_oEUklC@CALS~s#?8|;ou8y$ zMQL(88%^R%WU>~MEsfR+iXC-o=4R5zN>?(X*ub4R8yoo;igNK0n{71&cg5M`MwBx_+_1GI7V zAk)=oenX7CnTbLFs5sumB&v3alNkAma+A_$KsO4rNl1pKAS*Ac6qd*MsPd6ax8$?a zNDkT|ZoO&jA8$Nuzy|rHx?qj8=h!X74^yR~-7COPCA$gs12YA9A?L9ej$Fr}f^|{e zoXPwIr_V>6^xENcMm3G)NR@^wIT6W|ES2S5I^Anx-XL~WYzP}`dr%Y0C%lE#3+@In z5R~B{E&Y!yU1@G~hPxO|SH&K$mYzz@uhEPR>gAUTH{F36yZ8Xe2cZFo)}pADODeGwVq3_K}tp$bl`@{!-N!~y-m^@UL*OlY zm~oliljiBtE#bDx?DhKMY~}#|AS1pC;ujMoiB+0kzUCBe{ z&L6C=sMvBKjY530))03%Fd9gc>d3v2kXSI7$k)h#YfZb7(u3hj#i)X~dh{CMzj~#p z@o9!CK4h83)fi=b)aIqF8c2iLtn7y>^B;MAe2Vm%O##|X6Sac5#)WlOhb$$s%>UTw zYN`}0J335+G}e}Q3D?$X+%2Bl;pU1ZkVFJcrzS`n=M>8TJK=kSN%2nbPCUcJM-7+@ zWik1M7R1k{Pg>g)%i2pbGmwPiCVV`E(>w}Q`7EbvmHJ4l*A{r?EVSxMERUQnl&zVo zXBC8(2;OZ!Mcz2Fn%siOLe1P%VSdK8L$>h%=>clsDyvR`0l4^7C1fBoH3E;S8dwW9 z@U$c#d4D86Gp^UJ$!+QUhs2DQDB6PHY7qZrU^azdLp>A-4XfiqzYVn7BU@#cDx!>m{%^y=+Lzk6yt-av}s_+F36ACL-rZZ0*SF>Wp%&z~>k)qZ>QWx}AT)7_d#B-n*>y!EY_ zC(n4Jq#5RVbd0%*s1qLec~$x@Z;;$QL_V>e{Q-h5Jb4xz7pf0?4DTo>{vqzYZv=mLB`?JxBmhV+ zBS4H>&>?A{WP_1{In`S6SSN|tF?NTuW-?Wn@nyZn@Irb)Hf&v&I`m>$;V5EKs_)9> ztKpYS0cPo}DBHj*eBEhSymGb`qz+rhUkUP)jkrnze_oYApXk*g-2laJ;%941JY&*p z^Zn+q4YF$*`>bL4FG8;H&Oux!q-6VCs(m!u0k4Wga<|ngFVS)0r={uYTj2H7=KF~Q z{;@;1^8P9fmx>6>M5hX-c+tPw(6(6zj8W~_3`d<-biG3&R@jERZQf=`8zcQ*9mLC+ zbOao+xY->ruj8E@FWE)bCq6X+Jf@po_n_ zqisp@Tv1CUsM^EVJY0W**L2!S#I$cErf{}Xr0*%C+U{}SkrG$AVH&zceFWKqliym` z6GNNvo_GIN7!n7RDn+@f#+5O!KN)oM5)?wP&=VgxaGJq6JOzLjwq=MgL`+((OoSJt z?jq~r_nzoO>*$ECA2AV5F}*sP?JG0(R@^6i>&^N0EGh$|l1&uTCP*5|M+Rw5zHQ}< zN4YFmaQuu+fHOiDb4 zD1>Yn#QV2D%Qan>^1P9=u>~Dzy5CDn_ zt^JJ%q49*(rd#b+gXsdahFmM558JJ9R~*51Uy}Kisavbo7qVOMHW||kpewyNhv(z~ z>&~T8TLH!&GkE~kA$rSdR1LV)=v#@ecv^e}C6YzG%LMy|NLPhw7P+k$>l9^>ytN$bl&P%>(3L%g3)mui6=kwT zwaVOOk8cyNy$aZoI;IV{Li|)=Vux|**wq|u1nm&ItuopsTg?uzEktZl4C4;#)UNFS z?FpRZ2J6tg?HKLUtn~!#2{myeU%CNUmF~XCuY8n!`RTnte-Wf3K)K}ZA|$p+)_#Eb z22F~AdH%i~8THbtg#hymoAibL0^Lgt;H7z0G~%OOrRz5Z^%TA}9rKc@6$A6lnM4Qm zl)6P9^AfKe0rO3tR0S21tx0&x(36Gy;!5uT^HjKHAN5kKEd}+BoNNK})VOsW^-`@h z1@(=cd;#-RxkVWLl&d`f{SKRq1@qLol^y+5sznF=j+&eS^OV1(AN^FQO$Ggqn5+Tw zRKK+y{Zy${1^tehTx zr2kahgubsEQIsvc3+zJy!<#`isyl5-l%EIz@se8qk=)TwPZ!3JAUzQDLlooZkCte) zrGJ#r@vq(v)WL72P^e}xjDay6!qu04j>%_7WPB|F#5t{QBePj zu(JxPD`>EFaCi6M?(PACyA#~q-Q793yByrzA?U%~-8HyF2wZ0Vs$2KY%T&K~*M8a$ zd#|qUwZ4@{3SeWifW1Nk$+4l}2&m#7nNFi`VuEbh;!$-Ow-STfs0CykTl}$tWe0eJ zEzmUJYnPpBcZCM%`j?ESF}g8~bRAoY?xC(lwHVvAm!X0^FragPgGBq6?wHWKVT@vT ztz&OluEe$I+qEqPQhYF$5w;^7qjvq^2p~0W;!YmGLZ$nc2Dssbe&EW6H2|DVc$Gcv zQ7}O=Y?>XhONe}L_XB2gS}ebdzT?s%{*)o_R|53+?RSQsqan~|A5)$ur7kVqhNHof zW3R;HDXR#Ven+dz)WkG!q6w+Bd#r=SIbk2QO$*kNy~jC8OJ!lf(s&_nFvNrzch;aU z+Jki_&TgX5tSNp_6XwQeA50{JW(wfIH8wm^FL6t1ID(?}wSEC6;pN=pak@nY1>8#V}IBSw_tEDtDK&oh~we`mWJC^hD?M!t^u06rhoPlLSeAp2xmAVlU&|r)t%#aP(0c=$>#~;tt%iQ| zpqniv2glu4*}R%* zeREMWpfXp6^)%X1M7;2KGY@L4#wmrprZ)CiwoJ&ON$*~>1dEMj(E6YL?4|*%T>QK! zTCsu!$>!o8SrYN0HDwj3tZChjG~t;QC-Ybc5ixkKG)N~WuTEkd%ns(!v@r#FSTsly ztTlA-F@qf+#x2hR4R~0Ef!oZ#w4__4OU$92l>s_OwlNA_t!mfX8L?iZ1hRHB8I4>L z2(DdZVJb&>mm5h*a~(k$BqPHkW6TpVVdRXu<}CPQgOz&hvIBeX*sP3MIHi}fq^XEg zUw(CLkOG$vc2m~b;^`_cZWbC-9@=Of4N|D=B`?aZJ;)69WUsoy?mSQbm>C%~ZnaV+ zZ$U!P%3C>1xMdt?#X6#LNSVRfG2DNumZiX~@eJ1~OFxh2Az3z$&gZp8?R{peLws{! z2~PV@F0+_RI1R>TN>M^(VvyGwsJ$f7RvBxhP9Q5O?c#|y^(P7g7cK=7rA!hh2o;2_ zWNt+PKw2ct7MA~GRpI_2HKd3GO~u8?4}JvB33~`*^%(Q7BghyZL~@T4fgtwcd8Hdb zp?G8lGwJ42dGmrWk9{E_*Iw`qIG8D&3)Z@v%E4zb5H{CSd_^&Zhz%ucwc7f|`BzTw zr_A}j>zd5j^12B<<5n+$CHr3l;1gpw-Ig4?lenx*?ytiEqBxmOzfU&Y#i!g&)O-?$ z$Q6xY$sx?BbZ3xnXMtF1%t40uFamwLMqGJCbqz6^JQsy^RYTC)Do0yoX=4LxYZ37V z;@|W(!A^A?|7I&D&XKFLC=iGWek?fyr%s;Au|0gT{Bs#-z4Qgo7Br`8<}?)1WSirD{YC$QM;Y2Qt%!P^Fn z*LH`UH)A-k>qqT0`tkPsl~Pn+o-DVOO3=C7P_M$K_A@TxO3WEDlqVpEd@lJ|=KEJe ziOU8NBEuxbF|U_eURxu_#c3GmW;gU0KrjUQyv|&m(UWM%`y|QD{f)M|{&_8psDkX9HFp#EHS3(|Mkr7`^@m|; zyw_I(@dGEqC3{6t(lt;zT~c%ZgU|ZjJS7Sw>ZC&!&}p z!^x>tF)Y9HvtD-g3Vp%jGvRl1aqPx#J&s?$TFQ$X^>;Xpjn!j&&1YE^&Pn5V5f`}_ z^V$P6*C-w?qn0^2)rJw!54HFf_YUU|foBKzxC=b%JmDgr|D0^@Zb1!H!jnAHhhm;_ zV-a@{@PO%MR-;YY-61=U}euF4L#dUcy* zJ$Y^Orm|guWIZvpbqE4_o8zP^h_MNZWIfsDDs%%fdH38#fY3GCYmBCC zP5C_oAM2tu@N(|-v_v^FEWhVWv!kx|i%pO+DxY-H$68NsDzOh3w4Q!E!uf{RXlpG8 z4%oc~Ri4YW%5#(X^RHcXcb2Z34#Fp2&iWmz8y~qZ+3R;VjGKC_x)(VmTIGnNcyI|m z=MH5(h~~e!**A7I$Cwf!yS1Hj3AZ&5aZLBSnLg7Lb+(e)H|Cy3TrN&k9kft&ajRRE zbFcZSp*?Iq?14<5xmV5>V#kOJqyrM9Q0x|enoW^y;$Dz)f@e+0J+W}EmER-Abq)zPv$S^Lx&1P&1sWcx~+IN#kN-S)=F6CSbMDFX8l;uVelA!Ls&8yGGon zZL7*ixyC9-_Vp>8kqRS5?x~b^O&x#||Jd^3219#x-{FEq9VP!4U`fSL!mcI&IPWV^RBfM`KU>?Dje=&2} z8#DSLx|T7mUg{L&$FuMLqLMGyf_ttxuE1f8@YK?Xv$90`87p|3DlG?cNR6c?%md$9 zb7u>BBHqyGI`ZLf^dw^1MR`)2y#@IXv7HM}M_rgO|SyfzVusUAor|4V9=%)D4h z5nMO@U2?%n^;gg=o^y?aE@&W8G=PRj)=z$X}FX~orSm}%?mBkQO zz|?v2+p)28ZFjK{{9}VKeCDPSjFXGc8-uAcPAQlokSrIz%}=26D{CT$Ac@7iiYV#U zJSG@-j+<=3S7{<|pY+>Zt+}iS0xKz+fv#KarTkP%oSKeLbuKKrmTqy8o9OX%?r=-$ zOhFul&RbxN1xc`mrtx8a?&CyO(UfyKu{qV-jGlijc#G~x3w1YDW z1m#(Si=$$UB$ZndOGQ#n)$_=Ydeu>x)w%As%{u6U1FA}TIc8seC9c-T-0(yqZd}R6 zdit}uj3C$(R&r1!){Si-6yEacw#U5fG7FSiUc(G23^=&N+@U24!V7}+Yet^KDeIB! z+bCm=$}V>@57rmuZ^6RuHAY&kdsgxl`df$bNjK`ZGki9owd?pMrf9`7qiE2!aTLaC z`GzQ5!=V)EZO`i`?E)j#@T2gbUE)WzXg-X1eQ`6c2fSPUF$#7Vt9GGKDLrq`tD=xu zVUd!jd8C5ZV{9!2p-KRober&iJRTgAJLNaqjQQB@#c!x}%bu|y8&3VQTklwI%gypz ziCAu{uRcEW*fz^<^#k)*9S&{$HtTNr1FqN&&Z}9^E)YM*cEv4ItcOjv?vJD{;_-pTF?Z4Z`8*Ex)CV zWw!AZKd8btSa|6KZQ<|CzLbL6IC^VtiDIv;tS8d6oTS8{Ht#Yi_;y8bTy0SY?5lKt&VD*jx_xBcQh z%rc9fWLg>7#LmtrpOI;%kK_|_+O@IiwUOzyi7APpDal708PHZ*99t<7>vXhsk)FGR zl1){7ndyYd(x4ZD&$FpD!~^%^`K|u+c)*z7wHT(pK$U<#rzY=#;Ngu3)C*(sNi5Ni z!b0pHI(Cz6Qc}h-A}oH?QOGdvs^eDcS{UtJ8TZB|m=EHpmkSS-TlB1VOg zFwAC%dEe)m2A7-(2ev%T`Uy34i^DNuFiRL9a{rFgJP!DN)oIl&b=`y3US_FTaqgvt@pQiqbas>tf5xFgsWF^`R#o@nUm&!;9Z_tvNkn zuO<$V5+Rk1Vt*z0-p&;f-@4YZwVg}dvc?OVSU=6_@K}YibIM@Ckn2LwJ=(SpZ|iD{ zfD&XpZGmWP6Lk=Ob|T$c5qVa90JD;M_Lzmh6lB@r9}Vswy$&SRA(c!N+uDX8I%E+? z#@R+gzWXj7mvXkPjO^ZQJR;TRQ5`~5wi;4$L%eS|Lhl|tc|&a7{}TaO^@3tpA&nT( zqmg`*Hu`x&&Y>2{3;VF_GO$mBM#;61qeqpfHY7TiYNIfjOdQ)G3|&0j)Q4h_woxtd z%TP-}PRmv~nvt^27O{XAolD!)9kGGdt_FD&ok!WTy%qH9m2iJ#YAsj}<{Mt7caORV&m$nr zBf!c}+3Jx;CXvPJl6&e~o>2dTRrx40T$d!+Q^m-`ck~x`n3&$jE8gXWN58?wwAG^~ zM6Yc1v60(bh?H}Jn(mHb4Q4D^^^i7NK>bPljzbcW05c%#BI5n50%Sq+g@z7%W*9NF zpnoDYYCLNFE)a7I!an?0DC1{7H-QB(!IkuXdq&hx%}v zGB~mj9Uu|+EcD0nUygBpIz~4$&ngbq-z0&>zl~6J#dk02!@X40-Uc4fJvws^ql4WJ z>&;&i+BZAi3ia_G;Ht-w>9r4bcmCabkg;%zYBve*YCP88s0SZmH_sQjhWrWLYaHY! z*sRe#QxU=Vn6ltk zt!YEMk>))S8UJX-_}Eh7&vtGC)13CUG5-zkz9FclM5L8NEA4ePVOb@P5h<13_o8ok zo<#?r$>MD_a(VvisS5Fx2~b-WXlDf&GPbp`%3&m8uy|c1ttq)}zgK9S74 zMwTfAtvs?>MGZr8Y%zli&4isYImC|&5D*I7Gan702bYp5$(=Jcaw7b;F>U_s9M*-;* zzT$h^vv&q9vH4fzGjN?w7KG)uRdFHr2AL7r6!(f6y)>vlz880CvN3vzP=BsPkQ}16 z=bY1_{uLcrVIxMS9XuvrFnZ{)FlaL|@X%;8CE~{hZt_4F zl){oVHx)n@_CS@u5-~)QNgjKz|8K)sYO2?tS3QE zY~b&PX>nY`ekfQ^6kWjAib<@Gw-X)AA+QR~nV}sSY$iVz*7M0h6xY1J2G;XI3)b`8 zL5ycKcmqvB+Ytvm@0lM>LdQ{f02hH+v@iJsEz}8HAkMKKN|9_A?~`M|6CqD5!>~UF z*0b|>bl~rHcXC4WejQlP+TS5xE1@45#$S<0&%A)}K;ib@pM5y74yZRYJ0Ym`yVRlJ z2>#-Is_!VF71$=QA~7APrN1U)l}uStL>q?rzNctS#-KK8QHRzKcao)OSHldr#+Z@+ zWLU-_wQl%;WsN}+rD?)Fj>|D(l_Ta|FisJS&;c}-ZGKIf7$nx%H;ggR;_6pTL&+J_ zVjNS3!C|qmv!hu?jKyJ7u@OioTUK2|>0*?brkb?yL^qAu(T;U&u|->k<9=!xHt@p2 z#i)}qG_U%Giem#)DjQZsLx-`eM9N#V7)5i3Y5LC@mjmmEjHN@NW0dnawQYGt=Z#bB z<*{{Q>lckv+$I<#ezk2H+n{M^*$NKG#3e#g=9Zx7+WW?{|? zn5#ql9a#y#Wfuxx1cTKRKo1b(4zU@r{6P>~=|*1#$H`x^n^yJ^Dm0 ztZ>JKf|V~kaHsrO!cl@6Hc<{<9Y(`mC!k8UYq7C%Wl(qP<9m_vf z-AGe9?ZeJ$CBN@`Llo6se@{z;GqdtDl34F&VXuKSFPREiv#Q#SY;M{eZT_=Y-t1FA zcIlOo`~;^~3Na~v4Sv56A>!sO#2}TA6!k#CAh+`^X1*>Y>%pgx=^tmg;wN!hJ0(YZ zgeb7GmBw-P}ENf-Pe3C{uMWda}b&{n)yl z@7}ka%7tAw`;|vG{Z&Xe{}pD_&^;{n*s^^Nv0vUC+@5u15c}Tw6j?VQEoUlT$@4Ja ze>g~~{$<=AeRU4D!Tv7*p|6`p1qXXoS0j5R^YqjNS^tpoO^}k4ByI^ z-2PVYbKUW`y~~H<-{bQ&GuUPjb|6m2_dA-K_Thu3@3jXmRM8iQ2vqJFG;opdGzjI8 z^)c271 zs9svx!WYp8)>K796dR((r$$U)(Q4eR(r9)r5tCDvrES3Zm{;O~g#4kbfXuylZDb9T zRe@KTR=M^aYFG1#y`-mma&LOjMR)sC%L=7gD8g01i8#Qab)$IQT&A<|tJomid^trT z8+9AG+oz9|L|DgjpRl4>MN@tKZ}iu`Kmotb=y~~f1wm)au!xhih5$mxcZcPhA)%vY z|HTRuuwM>%(VQ%_0mGD+pW~#h991{W9>@D|+)r}J>h?K5L}jaZF=d86fn!V*=v+&! z3qKTdN@n8BCI~{Nk9B5jVg{g(uKLtkf~Tq6rnYXlWGVKkeD)loJVQx%inrM^BRQ1- zNE|=ABM8X$wjykh!4KmQM2Zg;CLlyC%#0 ze)M#+oi$m!o4N*Y{bXRxo;@`Bb#2)K%%d{)!Yr(K;t8exDr==QHZxsmisNBWSjTet zGgn#5W-cx%VlwIJ?My-FYu#m&LpoxAprp!p{sH2lZn7)c@hCLiUo047K74{_RTCL3L|hMKN=0QweIZbferyJeQ|GemLI zQ46<%iG-#73UOa%Ycp%KmWX|Z&xvyz$NgSL<6c;|PBAv!&ZQE~xgRJ4paMEWSGC}T zsG%a{H7)j%rED8 zM{bP_*7tAUprpTjqx@eS3ST77|CkeUf5G{xsxJ$l^fpT`tf;_aj+2Q)7BZ%&JS{cL z%NEGXWPzJCgma}BW-n4;p^9%h4f+v!yN2vvYwCZTFrDQ2T&-Olb>x5CuzZu#sI5QH+B6!@wQ5HQuqd0!bw~9~Cklx7 zxIZDL-_C|6zZK&5bKmF>_qj+2%EG!n+3Bi&2}B}kHi5Zn*%#tBJwPV7I@u9s`2zt! zUUfnwmWxQfC6z$Yxkckg93-;(DPSETd&5dEWIrstP8yHDr{Wu|>6uC>=eSV?&~Mr|xKIMrvEM=ixxG$Z;3ws5yU(*1$<2BKYQw2yF@7X_iYLv&PYz)n0)vSB>7tp2do-_`KQHw z4$XL-;=I2m34b;o{Js?yIHUjYol5TApIOm(2Sx9!-|!RoJHU{9q(^-Afq#$y#U@_^ zs*48CUcO2ZsndQsd}IoN+k#8~Ahi`Ogc}f*q)|D|_-UP04^P1Cj05D**OGLvk~#sa zB+?d#ZZp*u7v|3i_sJM-jQ((sjIyPI)*AkC%rlDoCw7hZ9dFW3tePy{RvgicH~e;g z@b#j%F$Qg)XFe2HIt$ecAaQ%*NhMh}S44ed0Z<3DL}Q#C4)gGlu;#5Dvj6HcB~8Y_ zl{ZxzvP1_OOC;l^vSbZd(gCdirR-V#mQ=uB0CV=NK}#l}7vPwkFDfxanHI<C$P)Z`m&OnL5*}=wF>}{=TT`dR63=X%@pJYPKDbtZD~pG3Ko~qXmh}ls65v0; zN8jl;UuZ6L7H?PKAe_+^8kY$E&O zw)Uk%c5H$Mfi3c@$z|fVfx9d6W3@2yDe*t=m-78Ataivhqfg7EEIMfFo!n=(YV1^_ z_Yv;Py_%KIa|~&4vm*)s1ivBsRj}=gDF3QMiGg|e{5k(IbYie2%DAS!ClN4#9zZeL zyk;3ygCv0_LFB}n|2uQ}3&sWc-tfchJ0@HPKQo?%ZS^pTHB)7*cyQtI+JTSx5j&P7 zpgML>i2*gbL29d%+;kE29$S_aEr<3O1{jx?cJuZlnSBx0zDNW%#9P~wx8ggh_0Rg@ z0SSVEKBog8?ZMV%63%DG_jX_o$r`~gX;zEKTLd7P=!oF~=x-2QaKM$pb z&2vOtE41f>d`D4m-AV{ivaKtA5a(HjvJ9wj9O`G}&U`x0pw{*<9FNTPm;>p|ld0v2 z?ELEe_+rYFaL^AO23+LCte%m|V<5Bmw(N=2@sz|L2Yr)r+DF#_S)V`+IX#oS8@MeV z4|eOczh00h4G3!x^mi0V2u2bHNF9G)7e5Co{FJj|Lv;rDL^GV5|8;sJexog|R1GdH z?SqDN#nYt^Mr$qoHA3ZUv0cF-<8ch&5nFhtkN4-2gd22fbA0~QE5s(}0N)I093(U{ zM0pFl5A<)`#>_3KANsIwEn!0r8&f|ZoxXHH(i+AXLH%x(YfFC3L)P%PCnaDUOWaoU zaGD94Ka77x8;Vw0FYE{97|g|d>(>Zy`L1osw482w%pFb!IKz-+V-HYGrX5y}ZHr)# z#FysXs{aRsE;dNYRTcA|`+@eonW`^UBsfA@K`oTL<|6|Ufa%^_C@&7-M4!Jk(sb$N z(8|e%^JE^TqP4{bPC#QhYipn)Gyw~>OueA7#kXY|{V!Qlk08#mc-$K4XBLF~7zXrE zM;dimot*JT1?keL{m`;u;^G(R=~8Ekm$2!g10};@8W= zkI-;ul?$M`OEA2eBr!gD#eEj=HpOXfiZhpc{?)s1KP~(Vx8J8XTBVJt@<$czK*)@NdEQf zy}?I!Op04f9P4zw(T5?{XIZq^egIuwghgdLF?Urv9CLH@VC9SQ`;bZR(ael11h0(y z`IO|t@OTBEV;D^)baoO|@i{3eijk*2OBN3N$lbe_gu>*#*xl;t)rV)%^3qLo z?tB)Mdg^K)rZi`Mj}P;)=0QNZOkXZ28DaIY{a4jDLRvXaeBHNazgq4e7Pv?$5kG*?2h_JjI<#Ulp3MclHHi3leLg>UlTXX5Xp|zh8T!1~?C~r{rNY30AE@;g8Yh zt3zYhEI-QVnyH7E%ha-|sfQC8DYmEnN2fKryM@&D*BYu2$iCz~jDOvp73t$IOXJ{Fgj8M=E0h=_Hl_m3SRr!wYwbMSF5| zqC71zUYQ6;2}onp29@W{IZM#v)|fU&&y4}_adQVoXDm5^5)$$NaKJK)wRv-za>5*+ zL>Zg4(c(DG5Y1$H?3@*V3{V6x2CU=dPFo5B9|2q}|E<-rfN4WlXrMfRif5`uRh8C`p7ehz zbL~l>fLG$Wih#+o%yUbJx>(m|o`$yO>$$;SjIlsj&XW{Z<0E)+lMf~GC@q%SXPL$c zH74hfxspUf2GqL2qPTL!06$gG?cYL~zmI$bD zp>O!jUgItwX_o0z1YlYLZE}xoEl{Frn{ubOXzl52@ythayLe!F-Z<(cJ&FpwJ%CH; z$Se6Fx5TErE1w6u8?{u`*9w~me?NW6H8Q%{koj|GK0Sf`l9Bd+U|CmM)*XAzy666USHW9Y6T_`byXz;RE~J4!*I)`VV*8IpbcZLf~~ zHq)hd6|Xoa|0G@rsKYzO$u?iXto0*&rwnG0$w8MfNXf;P(Sbu62OB+Hj+T7gOVes@ zNPp3i`d0OYD54Z_HJCc1q-n)+7;nq4LgLPF0J>jL_$;ncqrtX3-UzLkQe29R`AjdA ze0IBCXVTkzC;uDiU`NrNx04jxhVyht_3@b+dWrkFmpoU|FTm-c=T@;GJEDJFQR}46 z>&q0M4W75BTYId;gHCfVIVRz}No*iiGqcC!;W|R*yo&%&+bG#Uq{BU7g)ZyK?t8Y)={% zE#GOg6r^gmD{=c76~1Jrqde%mVbekIx0Cyfh1e)$_&TKCH+*WCB`ir~$$9zC6VR2p zo=68P;hNP;R}ZB&FYak=pHTV*J{!tIzpg1BGd1d;{+xfoHE#hWvnAuh zvIO0Pk~|~CT94%!50=6F9nmv7C$`nvB21K1~}7mk&y~y5`JLt>Ualoa4Lthp`XK-4eHoLDXd) zS>~KHT(c?>ZIh}BKFTsSQl>tcA>bWl^RV|+{i`yp1LexLgp2|$wikF#xakFx2TXPJ z_g>w6RFZ~HUXA+SFzEqI2BIM{-xEYy zY1#2p%q#g+taP%%lQRtC65`mmMk6~);26eK!c(+MBKGp z5J)V+R@!r*?=UFp7;#NQ@mNw_{Eh`U*4Z9+^`qB&Ti-2&LZ#=>>mrf1#f+GVO^rDd zZHY)dPKA0YgZ8*?=})ygqltw=4dZ>MH4g`+?$*AGTBFZf4rbxYie>Ac-{$T3x+gXB z|E5)c(H~UCOoWh*3C^28)cS9lc?R4WDvCp0>Yk5Zj9)G;WhQR7Ew+rR526*{cNgaV zrCxbWK z`kev8^8L8-{S_4J9N0K17ybYGf)|{^X)kT@r!lIb)_xJqeqJ$UZ)FZG(0OS)QQcEu zH#xSBjf$9ff_5Pi^nT+&o1$C)O$e*Uh=_PUb!?vnAl2O^xQu2%11;C8 z+*PXlSVMj0JbN~rtq=A;j%zXxFwZ!`Q?JGz93z%)NUs|wjRq!D0`B0NxvnxWIfTLNal9sInp`3q!hTNrGBYel8=va8?LzV_^Y|rW;$ra-GfB z1d%^TqSP7*e;mU0w4xA3sSMKXn1?qaKfk-~i8@act}Rn+XpD83CO9Eb74yS+?ecA< zK^+#7;22@iun?ykagri*%5QML2{g`#`Pu%xH%xfLkZUuJ#ll%2K^`7Vuo8E;B}LsY zN40tNm5Mep=XpvbSQ_4fHECv(MtaV)SE-SNY_q~j(~Ysh(qv<+AsfDlAPwuFHLdFG zP~?;c2Mum%IBD z>77f3;Jh{lG-3_WZMV6bV4ZyPMAK>a^wm-K@`JPf;;LLWr$%=|DH=O&ZN92oVP=bp zqer1J@#00OXwxq&Pa)a|@Y4t!k$`S31A&=cQXCTdN}5z>W_k$o49mPp%aZ**X8rx49&O<4>UlC>aG12njXT};ckKY*e z?J&QsNo?m&Kn-;3-2@p;LoM<(Kpb~byY@+Qi)#Dt={sJq;>+@qtI`yUHrd7-tqAza zDGrXf;_LU0+#nKvq0Vm5{X83ZH#~(F(|rH8DL3Amn&Jnee)hXC%a33Dk%$G(qu;d~NDad1xtQ)4XoW~#>KL_wE z2I1a^zX?OSiE`=rZMrX{9*(3W@(ouvE`E^97yT*nVoT^~qZw@FrM`l$-liI))N< z-4N@I1i=ihE{F)M@mx2;mDmwW@PlL-m>;GfFD1$G4Q)?wWeWH4S3J3c$ekd?jr`<) zT1739vtQhHsYs?SB?^S{-E(s5AdFn3xcX`;!EZe{d#f=Kv}fT~vTht-{B;=-1}k_o zA+w)O`)a1r;Rfv#gD_?`LM59G7vUq_MD{1 z>~9uD;xs2K0UH)DY{+C|&o~C#-s&nywCCu3dl9UUV+t(J5m}Q3WbcOd)IXq+GfbZE ziRzAWZx0NGwb$Q=XSEw&lL`#cr?Au7yJ3IQ?DrL+jHngz>G;>3fwCEYYZL zedKEbBVhvh_%4q!T+>gaNt~EMQB)XZ7}+5e9`Qx7CM_^KW2|Z%B*!?*@cUuw_8-+j zxn!`4xJyS6e1@VY-lY!UK+B=>E18NX9U-tFdD zPXe=Yg)Ue+v^0K;C8%2uyGRnPFgHzft&O&_u>1~VSTfg1qTvMR;_SAk zS^$d4e(;4iN9r<6WpKLNg7U7UyhSiCnQeKC%gu>rwiC|7f1dzs`pF)ltGln_#Ilo7!`WLS`Q5#TE+Lt+|qchAE2Tu_DS4g z+M>-2aPITAiwK}_$KdSh-=Ygp>4)PC)8BM@5^du+^p)+)zo>LW?L@ZiQQsn$MtZQy zc1MH^M`SPy4M^`}Frek{eSsbAi8n?qvFF|Xkjad}FD6*oFD2ij(*U*a(eGALS<+RW zDNS)#5(;%IcWUoRt9Qbow$24T@k*@1>_3^hb-yZV<~Qx$HXSVOBTtNl{&fXAY~Ez# z$U;*tyvp_5NO}pfYZP=Y5t7syu85jP`%~-K{==gRUW(RC8aXZbP=DK5dXVG}%%?4a z17fV!dFMFAeykiI#^j0Da>_0WBxO&aTq`$422ca&CiS<#V!4w_%(&0eGSU>?(N}Zp zZqlLE?+WY-b2@6HTuNA)n{-~NpDmXSYckEtX)U>G*i|t&bFH~rE=;9${vg0dAzy~o zuWh$tG$Qv|Jwib*M6MAoxu^reufyD%E?skny^{<>n3h43fG2iW>{gzbcHM0E0Y{UU z%(RHzYVWYWHvER{GZ!sl;Y(92NgRHW0tYNd-#bH+2jW##3<1VrXEOMc>TCsaW5HoE zTnrk}1I}i!)#~9QT6kdDsfqRKcu<-&;xD?!7Jmg4kQ0&St0T|p4SRyxGZ)WJ*4)z@!vJjH#k>GqjK>tl7_B1+Evj#tZsayH)}R} zq&I>6JxT3~AzMkSz#yuqznq>w&{3>sNu#8_{kfxh@Gp{oN;}W^BYk|2g1{$C8G`ec zwm?U*x~Zoip4(NH7AVb5l_sp~KS+83LMuw`OC#ka4K3gckVjc?dMcm?% zBza1Qq*LBnAn7L#RpED2Mg6wC>7>}6-IbT_F6rM$dZ~iGmfCl~@1~FXZF7@HvAwbj zA?;hnF!11DizGHRM zL-A47kCOBvjD#$`AAnDoHWZKlP7#&Q8Ojq>UYHPCR49&20Mx9YVr7l$!$eZ0G+LUa zisC@JOp;nrO8prgo|$x7W|T(pW|P4f1%{8DGV~qEg@RRUkThv@$+4Uw+=@pR{lO!L zLc%(OI!YOzm^o?=Kd%oGCw(*srYFUh=b=govI8>@r1HWPH0FrzS9NyRLRc!wE*F9; z7vVy)=@63Xh@poT0MoQ5k^vE~x*HIs($DWI{TE>Fhk~qj8kZyvwFOI4Mm8O_K*X&>NCC=oj!}4lx(B(sV z0)vnXzQtZ zj-7Yksx^s2kj7)`m0#&|3g02PXm^yI$aWcIg;#CykS%mTgV+-s^XU5ykA1!W{->|t zL48I>{Hx~^74h3QhX37HAm(gl5&EDhlynX*N&AZcM5zzZGT1dog&2ucwDYXK9-xU&#i{q48fl@?^XPX<2UDrflSj}+&0J0 z#5DT{Q_aCzo2BCz!8&KxwQ&)g8XZp^n`5(%o!VS1cy7C-Cs?}Sbu>Jv96Gnh^Y&A* ze+p|;D4otRBaaM^GPH2J4+`S|7ls3L^?Z|4`GV=)aCIoDA#+sNo-!0@Qx?%LFyTomIgJiKPTNY=i1M`UmAZyF5b4u zvPq(U))7Mko*}!9n4@+NPCz;WKW|_GKd;}2ZYt*2ckRSpD@rA@2Kjw&eDoP>Ph`oI zIw1N8hd?|vl>OV+cX?**2{yvn9hnZ9^~uftONsdgU?2O_2O-VIJhpMF1R_nw4QRt% zDo?+(y2g%seR+E6P|TRxj)AWaatd0~kYfF858m#sZ9lJU1yz{4DTC&ZASx zhu?hvyg~|U!3vDWP20;Dvm9~Uc6%t+sa5r$^nprKD*~U;9N;xPLg>i3Y?q+3r?hiZ z8FwbaXVtAs64;B$&N>m=cFxbc<^t(mYpb8E-|5#fjrq7;;B7llY(2@mKjhR0x}GiF zqhUAi_h_P*wzOa|E#oCRPwJWLlWOt!h<~@7F0Kv&dp`_wso-ska)S7m~tSzD!KPVmYmutYyhGbMULGZ;Q=@%jkXi@eI}QrXoXj6)AT zIdJBVuXcwo4U>yAVt;C`nh5~Ja}SF~5N3_bDX*)H&(HKu*N-er$|9N}I71YEJXVGP zTZKom9|-p~q51)*!cnzd=Y~RvT|+`yLiXthGqHvbUo=MSl|QxH<4T0JYu&L|c;<)J z`YrN31Dpc4BTk}%NEZRg_ePTdz(>gz1X>UkPR?L`#EBC86r?Rk#^Y0~T8&7|3}3%? zhCD_bJRSIF_`bbP6ZZE}#UmtJO+Bvga2t*nPsEtDknNwIUYpv7z`Foh^}-(ZmCq_S zm$!Kea3uy)7Ju<;ei?qF#JM3wVbSJCQQb9wod&v~AaO4t8kW{Il~bVP40&kk>3mLr zZ_~e2yBAA1T`&ID;jb$jxLO_Dlr!-CGP6(!vtEwfBCr_wCr%(|qlTIANFY3SA17F9 z!ICJ=T(D6ztl1km`^TVlpwe*SzE?@y*F9UC6kp72dk}_WNWczt?W4>+AYsQrYziiC zI6){j-xa1_%Yo%d+0^teHm$NP6^ zdL+qhtp@-dV`?jo*;oyWNLiv|wtBoxK1kUZm4d0k5CYUqlNn{T4w<71#1O|qOF1QlbJr0o{dCaF2D zE}&o-D>>L`+UXisrt zyG89@7rB`())yP?r$Nt$FIceTefgG(e;lcB@0DZsP%@8sSg#ACKF1D5nUk>g=iynP z3Ulr$(OA(C%+~#^vn>C^T)$IZK2(QcQ{-w@h1QNeAXoMMEbDuj zc@>@3!t@TM%}L|Fet4+96Gd@`Y5U^L?iYk?2qW{dD5D5Qx|-?O?aGi ziOy35HMA>snKzqRe;Ij*In_S?TeuXrHz<9o3pxM0KAFJAf~>JhF9VibYKqPDEin`F z=>`f6QgoK56M2l_OX#6@9!_M11hjU7!EPb2XbCk~w2|aZivLY?F2mz@u$!OD z<&VJo$d0NE>Yd-3N-_Smk`@B=4?{CNFz&wpqF#%b8S9gVP{S}zXEP_}SVLi{6QXV2 zEqkzBv7k5`sW#uk_ALpN2H1?jKe5i-aw#kne)*H))Luo8P*L1tR@(rDZ<(&?jL@8M zvXFp8l6@MNgw5J|}{6-033r zS5Xm2rifh~x*y}=zs!f{H+u`U@aPslp(5Q_44iv8>Fi-mk8Y#WqlQ3#yl+o*$*b4W z@s<+F)9Sy41ciqNkSVf_{siP?P41W49BJ+iUQcYex9UAV>T$CTaL4>Yke~}A`w?Nz zc6!r5b{%_Py6Ggdo9?h(saqK_^n7u7%eT>jZ-j8{TeFGoKVqFgTKmLfijQD;{HN=o zDKT$K?*a^m&YkxcLPta~&mZg+|=H9gMt(;x9iH7=?9NzWcl4jM^ z8v`{1;cWE?@r2)M8Y2P;z3Xliln0^t@SNPzN6EwB>C`%RCYLWkf7()c1(=m7XuZhA zpW!T`vw^r{cQbCeMpzQNN)d`5RUQVKJi~Y)CZ<`e3NS7VO9aygG8?BBjUZszB;S6S z?bQl{0HbS)z{f+MYKZyt<00Is3i;5m#nGNA7!(q8#q! z&qD*WpUZ|~rlIX!${)!Tv4~p*mM|k7s(owBWnDJoV)Qy z6noE74|m@X{yRKx4#5I-=9;jE`!~ zu8Pl*Uln$zuEQg5zRsgE;!BtQ;BFz$ zC0T!MZE;t@Ksh)^Y2**eE7QQ9oDz!h27pWPB#3^8R-c(RJ$G+Ap``D*n+C^|1AFqt}D!9VkiJG9G*Z{*{6ghM8% zYxh+=p^wda&2vn(&Dx$RC$6W9^6W0ohE z`jV3;f8kp#*eEZMcAODAlj-h)-uMXf=W8~jW8VAR(Scp|i@@{>x!D`Wc~u^f9RE(o-L5HyZ}5c`X1dd zE!YrQ97RM>c7+njUH_p|D;~%j#uM9rKI8nqmr+&2FHN!cW%T{sM8fkwEh86KcRLqn zH%_4Wm;a>rYy9s6|Fw=Zoiyfw_<-l5o`aBJCikpC;9840TrlimVQ@{^p2 zoRSQwN`DI8sBH=x+TZ~Ew|-q*t}sDuF^d^5fjkPn)>EX~(@wPr<$jbO>M^4CQ z&3^Wt>SchL-$mcXj>7uDYvI1&z7%`aw%;Q9={%2rkKvnIIY*NqDd#CW;?-pF#$U?| z^lDg{W?)X6-s*KcTZHO>XSL}s@xY^*Xcql!7m_?eQt`kEwa8B6MuPj6^=bmfb4$K1 zOs}<#R)l~RnXf+Exa~prb`{#|&7u4e$0}>ROfA1eylv(e#?m%De7LTonGLX`2kl2t zVwOkjPcQ0vMKUk=aep><6>itJI2H=M5&fh+@-V_dOI`jn#3SRAL?~hn)f-{oSW1-A zQBWs_(>F+pnIo~F7;y`alK$#gbznYy0{`K9>|V}E#Gk9&_;!b*VQHzdY0vIaCgp~t z5QaJ*t()eZ5I(_(t@wwf6zm%J)92rxS$Q)m9ASlPI63s?v0*E9#%FYEnP*hme_FgL zbBu#ig~#hLFPVOx?i-23evq&wC&DSuT)|+gQ1;6d`%|Y_@Eq zvSMVW1!rXT*XYrjAFK+Pc`}kfl*v*ouc<$eq6nQ#Nz5ynsmN#+MG!${pMx14jp~qlY7#QUD&4H}{Q!Kv6;1@e*8#!-FtN$Yi;}W-( z0aEzGy`S8EkB={$QLV~p88-dcB=E#R36V8(|JX4vP}s>`z3<>b?>-B64V)D|r8P%A z@AsOT$hq{IItvU4@&^bFc_P|X)u-q!=?kzq8m!K`JKd5eEUu}2pJkp- zN|&9O-53oi*2eflTFy39ihL+sO8XUFXzR9--$A`&d6l6+-#i{nghQQ0ys4?2Z<4xPM$&k09@}%aU%u7Kk$!c8; z$)oObF?HL=WAbVie1stqKbXJjN&u2MbUCxg@4qw39L@D)zb4YcHEQ z`j5oy_Fr$5Wgmb1{RbH6;p)}uBq9J{QeH{RAc;)NlH|IlPEE8*jM>i6IdJh~QZ*x2 z4S77kyYO3-SMwiGi~ai+E=dOCM{&y^_5I)2oLsHd~in zS9#N-S5w*f;!k2Qsw15;kWi}8_gC(fI`$UE)!%L|G0e;8E~dB*tPl;9S0yM3_%KW|DvVN^voK*sgP0l}7uP(BOI1&jn1<~G zxs*^+U6d>Sj%~jt@(6Z3J-LE6%Z^=G8D5^0H^Yv1e{BdsHYBaI`yBb|}riaIgf8Fg1kU9v0A zjzvFxmExL|N<&-J zHT(LqqUd)P5sX9>O4ev~SWjrK6quvakJKjGFi3w-sGX4q=-NKvW`Ec{pms+2qZ3v? znHr-zEW%=F&$8~Iv$WjOv|Qs@CDkV%7G*^C)Ah5UQ@3S-?liTkbHmw}RZ{kBE;a=f z29M5IEUT6tgH{jTn)F4gX`^_cnZ3AgHk}rW7SU78(TOIY^|jm@tomE@sPLv;9kVm zt|=dVZZ$t)U(Ms#yqM{jV+(IzkGDy8FUs8c{KxmyK5Xt!Qcz`W_(rg|V5^vEU_n0@ zhE4o>yn5KInvRi*mwgLO`jyXf$ML)RqH2R z{jZFKW9OqphTIzg1Ow>XW0qoNIaE|q8^cbCe-#(>J<+CV`oo79Z8%6u6`gaBx40hn zo}VSlqsp!ZaO3s$MQfHx=Kdtg$OvmY$Moq!qLIazKSn~hq{rU;SZJXb-ZUZWJHL=G z`f|nEw2!OuQ2y}abP?9>#<%Y}3>Ka1bdk~MIaysb0_og173lC<+vq&>lX>A!&Z{!N zUW;g5*b{-+LnAlX)48wP|fXKR5}*W2+ZEQYtg7mGSx=_ zd5UK)2-R}x1{KI8l&RKmY}hh1kWex+Hx%%k9|_cA6eTqJT5ggW#?=V_vhA6Z%&yMd z%-oR7LK#^qZVFkea!SP{B&j+(<`Ek9hKQblho4009lif5F)|#!BTOcV)0nI4-9oX) z6O#5~M?2~o#f_3a1f+fqC5r6@k6Ra0-CXz|X5mz;lg*9!vd&k!nFPgHDVDm{d~D}< zs%W#7fKq%mdbdslRp};wADHy*cl}4f`Pm`9!&3MJemudvI+-V~&5*MeL!yv$^5SB- zIQCQfER%Mmpi%bHZoE^wAWpiWflWz!!4Gs(3odj=T1FJ0s9KSbDfWs&H{O-sD=jpszB*t;EQ=42m8C^ji_#p0qcuCGhKSYKg(FR6Zg7S<*ivnA+dD!xsz zvS}a2X*RH?UK_kB$##DF#WR(7-oiHX<9ufXKY!5I1CuVZIK|p}Bfk0eq~$=ph2b)_ zT=aWV>WFMV=pXwI5Jgu%jTd`zNW9jlNWq@Nwo$0!#OZgE62_o+@Sd8YbLgSU*+a#= zK1nAgCbx=whC@=4Ro{Ht7fda?b`G=Qn8(ntq=N-^v|t< zH$H&zrkm?!TAfsAQq%%!xm@&iME0h^tyc*IJLcH8V@OjX6Z)2dhDW_QE?R!fv+-BK3(qbAiQ9Mbs}tJjXMjp$AeO1P2WI?i=@j=aT^{{8jFi4?pJy+z&v zJ<)kHZVgShCz}i-^F{_ZF$jrK1nQ<~ds^*vgP$lFb#2RrS?kq!@0Vs}ob2`#S`S9y zBVuJE_pSdZoh27JrVbMbV)ha+i4}f)A5GWKo6kJa`PuA%@iF?hMp{yGw9JR8=`RY0 z{d+Ho+)KaRUC+C~v|gM9$$gaCMnBJjGt?cwXGg~F=8}3z--4(9iGx$p>}HpRFDRXV zojGm{X8bWTv5nz}YJVa$L;zBkyplySBh+W%a!I#J9cE1D>F!^cD1Nx_ z07aONab)b0u15>q6a8co0T&cS_^vJ_)sl)3e1v|0B|Z~2aiyfJSq>l^P{zU~4dFwO zN6o2`Oza~;jl~tx1kD0=354VzYzV{1In{l7AUAwsMr>_}7RZf2NDU%}piU%Y3gU%l zU~(<(LqLrs$|&#C2N1Eiwn)|k4v|xsun97X``Q7?1VS2S-vNhcDJ)!4W)%P;