(...);
-}
--keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
- **[] $VALUES;
- public *;
-}
--keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
- *** rewind();
+-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
+ **[] $VALUES;
+ public *;
}
-# OkHttp
--keepattributes Signature
--keepattributes *Annotation*
--keep interface com.squareup.okhttp3.** { *; }
--dontwarn com.squareup.okhttp3.**
+-keep class !android.support.v7.internal.view.menu.**,** {*;}
-#-dontwarn
-#-ignorewarnings
+-dontwarn
+-ignorewarnings
-#Jaudiotagger
--dontwarn org.jaudiotagger.**
--dontwarn org.jcodec.**
--keep class org.jaudiotagger.** { *; }
--keep class org.jcodec.** { *; }
+# ------- FastScrollRecycleView START -------
+-keep class com.simplecityapps.recyclerview_fastscroll.views.FastScrollPopup { *; }
+# ------- FastScrollRecycleView END -------
--keepclassmembers enum * { *; }
--keepattributes *Annotation*, Signature, Exception
--keepnames class androidx.navigation.fragment.NavHostFragment
--keep class * extends androidx.fragment.app.Fragment{}
--keepnames class * extends android.os.Parcelable
--keepnames class * extends java.io.Serializable
--keep class code.name.monkey.retromusic.network.model.** { *; }
--keep class code.name.monkey.retromusic.model.** { *; }
--keep class com.google.android.material.bottomsheet.** { *; }
\ No newline at end of file
+-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.** { *; }
+
+#For cast
+-keep class code.name.monkey.retromusic.cast.CastOptionsProvider { *; }
+-keep class android.support.** { *; }
+-keep class com.google.** { *; }
+-keep class java.nio.file.** { *; }
\ No newline at end of file
diff --git a/app/src/debug/res/font/bold.ttf b/app/src/debug/res/font/bold.ttf
deleted file mode 100644
index 96619df92..000000000
Binary files a/app/src/debug/res/font/bold.ttf and /dev/null differ
diff --git a/app/src/debug/res/font/google_sans_bold.ttf b/app/src/debug/res/font/google_sans_bold.ttf
deleted file mode 100644
index 80497666e..000000000
Binary files a/app/src/debug/res/font/google_sans_bold.ttf and /dev/null differ
diff --git a/app/src/debug/res/font/google_sans_medium.ttf b/app/src/debug/res/font/google_sans_medium.ttf
deleted file mode 100644
index 1543660da..000000000
Binary files a/app/src/debug/res/font/google_sans_medium.ttf and /dev/null differ
diff --git a/app/src/debug/res/font/google_sans_regular.ttf b/app/src/debug/res/font/google_sans_regular.ttf
deleted file mode 100644
index ab605f9e2..000000000
Binary files a/app/src/debug/res/font/google_sans_regular.ttf and /dev/null differ
diff --git a/app/src/debug/res/font/medium.ttf b/app/src/debug/res/font/medium.ttf
deleted file mode 100644
index fd818d6f5..000000000
Binary files a/app/src/debug/res/font/medium.ttf and /dev/null differ
diff --git a/app/src/debug/res/font/regular.ttf b/app/src/debug/res/font/regular.ttf
deleted file mode 100644
index e2c69c3fb..000000000
Binary files a/app/src/debug/res/font/regular.ttf and /dev/null differ
diff --git a/app/src/debug/res/font/sans.xml b/app/src/debug/res/font/sans.xml
deleted file mode 100644
index 7bbc8513b..000000000
--- a/app/src/debug/res/font/sans.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/debug/res/values/bools.xml b/app/src/debug/res/values/bools.xml
deleted file mode 100644
index 7d3f0ee62..000000000
--- a/app/src/debug/res/values/bools.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- true
- false
-
\ No newline at end of file
diff --git a/app/src/debug/res/values/donottranslate.xml b/app/src/debug/res/values/donottranslate.xml
deleted file mode 100644
index 79e559838..000000000
--- a/app/src/debug/res/values/donottranslate.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- Metro Debug
-
\ No newline at end of file
diff --git a/app/src/debug/res/values/styles.xml b/app/src/debug/res/values/styles.xml
deleted file mode 100644
index f3761b219..000000000
--- a/app/src/debug/res/values/styles.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 14fbaaab7..2941835c5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,57 +1,36 @@
+ package="code.name.monkey.retromusic">
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+ android:usesCleartextTraffic="false"
+ tools:ignore="AllowBackup,GoogleAppIndexingWarning"
+ tools:targetApi="m">
+ android:theme="@style/SplashTheme"
+ android:label="@string/app_name" >
@@ -62,6 +41,7 @@
+
@@ -121,54 +101,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
+
-
+
@@ -216,7 +172,7 @@
@@ -229,7 +185,7 @@
@@ -241,7 +197,7 @@
@@ -253,7 +209,7 @@
@@ -265,7 +221,7 @@
@@ -275,36 +231,13 @@
android:name="android.appwidget.provider"
android:resource="@xml/app_widget_card_info" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:label="@string/app_name"
+ tools:ignore="ExportedService">
@@ -318,33 +251,15 @@
android:name="com.lge.support.SPLIT_WINDOW"
android:value="true" />
-
-
-
+ android:name="code.name.monkey.retromusic.glide.RetroMusicGlideModule"
+ android:value="GlideModule" />
-
-
-
-
+
+
-
-
-
-
-
diff --git a/app/src/main/assets/contributors.json b/app/src/main/assets/contributors.json
new file mode 100644
index 000000000..e84023c32
--- /dev/null
+++ b/app/src/main/assets/contributors.json
@@ -0,0 +1,32 @@
+[
+ {
+ "name": "Hemanth Savarala",
+ "summary": "Lead developer",
+ "link": "https://github.com/h4h13",
+ "profile_image": "https://i.imgur.com/AoVs9oj.jpg"
+ },
+ {
+ "name": "Lennart Glamann",
+ "summary": "Designer",
+ "link": "https://t.me/FlixbusLennart",
+ "profile_image": "https://i.imgur.com/Q5Nsx1R.jpg"
+ },
+ {
+ "name": "Gaming Inc.",
+ "summary": "Telegram group maintainer",
+ "link": "https://www.gaminginc.tk/",
+ "profile_image": "https://i.imgur.com/pfvN7d9.png"
+ },
+ {
+ "name": "Milind Goel",
+ "summary": "Github & Telegram maintainer",
+ "link": "https://t.me/MilindGoel15",
+ "profile_image": "https://i.imgur.com/Bz4De21_d.jpg"
+ },
+ {
+ "name": "Abilas Sathiya",
+ "summary": "Design & Suggestions",
+ "link": "https://t.me/@abs2606",
+ "profile_image": "https://i.imgur.com/MUyEWlx.jpg"
+ }
+]
\ No newline at end of file
diff --git a/app/src/main/assets/images/daksh.png b/app/src/main/assets/images/daksh.png
deleted file mode 100644
index 737f9066c..000000000
Binary files a/app/src/main/assets/images/daksh.png and /dev/null differ
diff --git a/app/src/main/assets/images/haythem.jpg b/app/src/main/assets/images/haythem.jpg
deleted file mode 100644
index c74527f1d..000000000
Binary files a/app/src/main/assets/images/haythem.jpg and /dev/null differ
diff --git a/app/src/main/assets/images/hemanth.jpg b/app/src/main/assets/images/hemanth.jpg
deleted file mode 100644
index b8f5e7805..000000000
Binary files a/app/src/main/assets/images/hemanth.jpg and /dev/null differ
diff --git a/app/src/main/assets/images/lenny.jpg b/app/src/main/assets/images/lenny.jpg
deleted file mode 100644
index 7f8025f08..000000000
Binary files a/app/src/main/assets/images/lenny.jpg and /dev/null differ
diff --git a/app/src/main/assets/images/milind.png b/app/src/main/assets/images/milind.png
deleted file mode 100644
index bbf9b8278..000000000
Binary files a/app/src/main/assets/images/milind.png and /dev/null differ
diff --git a/app/src/main/assets/images/pratham.jpg b/app/src/main/assets/images/pratham.jpg
deleted file mode 100644
index 7f05ad9d5..000000000
Binary files a/app/src/main/assets/images/pratham.jpg and /dev/null differ
diff --git a/app/src/main/assets/index.html b/app/src/main/assets/index.html
new file mode 100644
index 000000000..4d858fba4
--- /dev/null
+++ b/app/src/main/assets/index.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+ Phonograph by
+ Karim Abou Zeid
+
+ VinylMusicPlayer by Adrien Poupa
+ RxJava by RxJava
+ authors
+ Material Dialogs and Cab
+ by Aidan Michael Follestad
+
+ Android Sliding Up Panel by The Umano Team
+ AOSP Support Libraries by AOSP contributors
+ Glide by Sam Judd
+ Retrofit by Square team
+
+
+ Material Contextual Action Bar by Aidan Michael Follestad
+ OkHttp by Square team
+
+ CircleImageView 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
+ Font
+ used(CIRCULAR STD BOOK FONT) by NIELSON CAETANO
+ Icons by Austin Andrews
+ Material Design City Wallpaper
+
+
+
+
diff --git a/app/src/main/assets/license.html b/app/src/main/assets/license.html
deleted file mode 100644
index 2fd8ba5ed..000000000
--- a/app/src/main/assets/license.html
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
-
-
-
-
-
- Phonograph by
- Karim Abou Zeid
-AOSP Support Libraries by AOSP contributors
- Glide by Sam Judd
- Retrofit by Square team
-
- OkHttp by Square team
-Koin by Arnaud Giuliani
- Material Dialogs and Cab
- by Aidan Michael Follestad
-
- Material Contextual Action Bar by Aidan Michael Follestad
- Advanced RecyclerView by Haruki Hasegawa
-Custom Activity on Crash by Eduard Ereza Martínez
-
-NanoHttpd by NanoHttpd Team
-Circular Seekbar by Tankery
-jAudioTagger by Kanedias
-Android Fast Scroll by Zhang Hai
-Image Picker by Dhaval Patel
-Material Intro by Jan Heinrich Reimer
-Slidr by Drew Heavner
-FadingEdgeLayout by bosphere
-KeyboardVisibilityEvent by Yasuhiro SHIMIZU
-android-snowfall by Jetradar Mobile
-Insetter by Chris Banes
- Icons by Austin Andrews
- Material Design City Wallpaper
-
-
-
diff --git a/app/src/main/assets/retro-changelog.html b/app/src/main/assets/retro-changelog.html
index b6b1c411a..dc00d3156 100644
--- a/app/src/main/assets/retro-changelog.html
+++ b/app/src/main/assets/retro-changelog.html
@@ -1,466 +1 @@
-
-
-
-
-
-
-
-
-
-
March 30, 2023
-
v6.1.0
-
What's New
-
- App now targets Android 13, support for Granular media permissions, Photo picker, Per-app language preferences & Predictive back gesture
-
-
Fixed
-
- Fixed playlist reordering crash
- Other minor bugs fixes and improvements
-
-
-
-
March 13, 2023
-
v6.0.4
-
What's New
-
- Minor redesign in Playlist details screen
- Updated translations
-
-
Fixed
-
- Fixed file popup menu actions in Folders tab
- Fixed playlist image loading
- Fixed blurry album art in Android 13
- Minor bug fixes and improvements
-
-
-
-
July 10, 2022
-
v6.0.3Beta
-
Fixed
-
- Migrated icons to Material symbols
-
-
-
-
June 21, 2022
-
v6.0.2Beta
-
Fixed
-
- Minor bug fixes and improvements
-
-
-
-
June 13, 2022
-
v6.0.1Beta
-
Fixed
-
- Fixed ChromeCast crash
- Fixed Slider crashes
- Fixed storage related crashes on Android 10
- Fixed CrossFade not working Fade Audio is not working
-
-
-
-
June 7, 2022
-
v6.0.0Beta
-
What's New
-
- Better Cast
- Mini player in settings screen
- Changed Seekbar with Sliders
- Added NavigationRailView for Landscape
- Show remaining time in Sleep timer dialog
-
-
Fixed
-
- Fixed Top/Recent Artists/Albums not updating (Wrong sort order)
- Fixed all Blacklist related crashes
- Fix restart button not working in crash activity
-
-
-
-
May 25, 2022
-
v5.8.5
-
What's New
-
- Display song images along in the artist and album details pages
- Removed the Internet permissions and all the associated features
-
-
Fixed
-
- Fixed crashing occurs during changing screen orientation
-
-
-
-
May 13, 2022
-
v5.8.4
-
What's New
-
- Added a toggle to enable/disable swipe down to dismiss mini player
-
-
Fixed
-
- Fixed Playback speed and pitch not working when CrossFade is enabled
- Fixed crash when adding folders to blacklist
- Fix bugs in MD3 theme
-
-
-
-
May 07, 2022
-
v5.8.3
-
What's New
-
- Added a new MD3 now playing theme
- Swipe down to dismiss Mini player
- Add support for Just Black with Material You
-
-
Fixed
-
- Fixed sharing of files from SD Card
- Fix ChromeCast crash and bugs
- Fix Audio Crossfade
- Tried to fix incorrect song data in notification
-
-
-
-
April 8, 2022
-
v5.8.0
-
What's New
-
-
Fixed
-
- Fixed Classic Notification crash
- Fixed crash when clicking on Playlist in the Search Tab
- Fixed settings change not reflecting immediately
- Fixed shuffle
- Fixed Song duration not visible in Card & Blur card themes
- Fixed some Album skip styles
- Minor bug fixes & UI improvements
-
-
-
-
March 13, 2022
-
v5.7.3
-
What's New
-
- Added adaptive color in Material now playing theme
- Added an option to share crash report
- Added options to clear, pause history
-
-
Fixed
-
- Adapt Wallpaper accent for better readability
- Optimized search
- Made sleep timer precise
-
-
-
-
February 13, 2022
-
v5.7.2Beta
-
What's New
-
- Animated splash screen on Android 12 devices
-
-
Fixed
-
- Fixed crash when removing song from Playing queue
- Fixed lyrics editing crash
- Fixed shuffle button not working
- Fixed crash on song deletion
-
-
-
-
February 1, 2022
-
v5.7.1Beta
-
What's New
-
- Added option to disable changing song by swiping anywhere on the now playing screen
-
-
Fixed
-
- Fixed Playlist save on A11+
- Fixed Just Black theme
- Fixed some UI issues
-
-
Improved
-
- Improvements to search
-
-
-
-
January 25, 2022
-
v5.7.0Beta
-
What's New
-
- Added Android Auto
- Added accent color extraction on Android 8.1+ devices
- Added new Circle widget
- Added Collapsing appbar to library tabs with an option to switch back to simple appbar
-
- Added Search tab
- Added option to use circular play button
- Added lyrics editing on A11+ devices again
- Added Long Press to forward, rewind current song
- Added ability to set Playback speed and pitch
- Added option to show lyrics over Cover
- Added option to keep screen on when showing lyrics
- Added option to switch to Manrope font
-
-
Fixed
-
- Fixed Gapless Playback
- Fixed Shuffle FAB going behind Mini Player
- Fixed crashes on Pre-marshmallow devices
- Blacklisted songs can't be played after opening from outside the app
- Fixed various small bugs and some minor improvements
-
-
-
-
January 1, 2021
-
v5.6.1
-
Fixed
-
- Fixed artist covers not updating and showing album cover images.
- Fixed FAB's not visible (Shuffle, Save, etc.)
- Fixed a crash when a Song is deleted in Artist Details
- Fixed Snowfall effect
- Fixed empty notification when queue is cleared
-
-
-
-
December 25, 2021
-
v5.6.0Beta
-
What's New
-
- Added Artwork editing for songs
- Circle theme has album art now
- Upgraded tag editor library, we should support reading tags of more formats now e.g.
- opus.
-
- Added Snowfall effect
- Crossfade effect for background when Song is changed for Blur, Blur card themes
- Album art is hidden when Show lyrics is enabled
- Added fastscroll in Playlists tab
- Added Chooser to choose what to restore
- Hide BottomNavigation when only one tab is selected in Library Categories(This was
- already there but when changing screens it was getting visible)
-
-
-
Fixed
-
- Fixed Ringtone crash
- Fixed blank album cover bug
- Fixed bottom navigation visible in Playing Queue
- Fixed lockscreen dragging glitch
- Fixed incorrect colors when no cover art is available
- Fixed favorite not updating when song is changed
- Fixed playlist not getting created & playlist creation crash with same name
- Fixed a bug in "Plain" Now playing theme where onClick event is consumed by the views
- behind the bottom sheet
-
-
-
-
-
December 6, 2021
-
v5.4.2Beta
-
Fixed
-
-
-
-
December 1, 2021
-
v5.4.1Beta
-
What's New
-
- Added file selection from system file picker for restore
- Added Grid size selection for Playlists
-
-
Improved
-
- Enable Material You by default on Android 12
- Reworked Grid Style saving
- Improved Playlist preview images
- UI improvements
-
-
Improved
-
- Fixed File deletion on Android 10
- Fixed Sleep Timer crash
- Fixed Bottom Toolbar not clickable in now playing when Shuffle is clicked
- Fixed Album Artist sort order
- Fixed a crash when clicking the "Clear All" button in the Blacklist folder selection
-
- Fixed Continuous crashes on A12 when the song ends
- Fixed New Music Mix multiple clicks crash
-
-
-
-
November 22, 2021
-
v5.4.0Beta
-
What's New
-
- Material You
- Going Edge-to-Edge
- Added Backup & restore
-
-
Improved
-
- Improved Animations
- Improved Crossfade
-
-
-
-
September 06, 2021
-
v5.0.0
-
What's New
-
- Added ability to Remember last tab
- Added Whitelisting songs
- You can now browse SDCard from Folders Tab
-
-
-
-
August 22, 2021
-
v4.4.0Beta
-
What's New
-
- Added Crossfade
- Multi-select in Album and Artist Details
- Albums now show Album Artists instead of artist of first song
-
-
Fixed
-
- Fixed Playlist Preview Images
-
-
-
-
August 11, 2021
-
v4.2.30Beta
-
What's New
-
- Revamped Playlist Tab
- Revamped Genres Tab
- Added support for embedded Synced Lyrics
- Added animated icons
-
-
Fixed
-
- Fixed Language Switching
- Fixed some reported bugs
-
-
-
-
July 18, 2021
-
v4.2.020Beta
-
What's New
-
- Added ChromeCast Support
- Added Lyrics Editor for Normal and Synced Lyrics
- Added Ripple Animation for Color Theme
- Added Drag to seek in Tiny Theme
- Added Playlist Order
- Added Search Filters
- Added Audio Fade
- Synced Lyrics in all Themes
- Swipe anywhere to change song
-
-
Improved
-
- Fixed Navigate by Album Artist
- Changed New Music Mix Actions
- Improved Animations
- And some minor bug fixes and improvements
-
-
-
-
October 12, 2020
-
v4.0.10
-
What's New
-
- Re-built from scratch using MVVM Architecture and JetPack Components
- New Material Design icon
- Implemented a custom database for playlists
- Added new Material Design motions
- Bug fixes & performance improvements
- Revamped Home tab UI
- Android 11 support
- And more!
-
-
-
-
April 30, 2020
-
v3.5.110Beta
-
What's New
-
- Changed profile form image to icon
- New what's new screen
- Added In-App language changer, where you can select language
-
-
Improved
-
- Improved loading of Songs, Albums, Artists, Genres, Playlists
-
-
-
\ No newline at end of file
+
v3.4.850
Added current playing tab options for Bottom Navigation View
Added search in genre
Fix bugs & crashes
v3.4.800
Improved dark theme colors and Follow system theme
Rounded rectangle ripple for BottomNavigationView
Follow sleep timer dialog checkbox color as accent
Added song list selection for Album and Artist details
Fixed Toolbar popup text color when selecting songs
v3.4.700
Added splash screen(for app loading time)
Updated dark theme colors
Added circular progress view
Hiding year if not showing
v3.4.600
Fix notification layout height
Fix folder list last item not showing
Added auto hide/ show controls according to first and last item
v3.4.500
Added peak theme
Added app rating dialog
Fix song name scrolling in now playing themes if it's long
Fix playing queue last item hiding FAB
Added desaturated color option for dark mode
Fix slow search loading
Fix last added slow loading
Fix home banner toolbar corner
Fix home crashing when switching between two tabs
Fix remaining time in playing queue
Fix font not applied for some components
Fix crashing on album details sorting
Fixed lot of internal bugs
Fix dialog expand
Fix list card color
Removed SlidingUpPanel to replace with BottomSheet
Removed color theme as per material design guidelines
Removed classic theme(We're bringing back)
Replace line switch to Material Switch in settings
Performance improved
Updated internal libraries
Updated translation
Limiting the use of Theme engine for making use of system colors
Change home icon from the user icon
Corrected all toolbar with elevation when scrolling
v3.3.200
Fix fullscreen bottom tabs icons squash
Improved tiny theme colors
Android auto support
New notification icon
Favorite icon in mini player
v.3.3.100
Improved Now playing controls alignment
Lot internal changes to improve performance
Fix playlist adding crash
Fix color corrections
Fix file editing crash
v3.3.000
SD card support for deleting and editing
v3.2.240
Improved options dialog with selected color and title icon
Fix dialog color on dark theme
v3.2.220
Fix Notification SeekBar position (Need Android Q test)
Rolled back settings tint icons
Changed preference category title style according Android Q
Fix tabs options not working
v3.2.203
Carousel effect improved
Settings icons are now tint accent color
Settings title, back arrow and icons are now tint accent color
Equalizer is removed
Fix keyboard not popping on Search
Curated the main options
Folder toolbar outlined, folder icon background fix and separate line removed
Edit text input handles are colored
v3.2.135
Fix crashing on sharing song
v3.2.125
Fix crashing on selecting profile picture
Semi transparent color fix(s) on now playing themes
v3.2.120
Fix crashing on choosing a theme
Fix color theme selection without pro enabled
Fix icon tint some places
v3.2.105
v3.2.100
Fix crashing on Sleep timer
Toolbar elevation removed added stroke instead
Show empty indication for home
v3.2.000
Implemented Artist image loading all thanks to VinylMusicPlayer
Fixed buttons in Genre details
Fixed color buttons in Album and Artist details screen
v3.1.900
Added Play and Shuffle buttons on Songs list, Album Details, Artist Details, Playlist
Details etc.
Home toolbar is semi transparent in Banner mode
Added new Buy Retro Music pro in settings
Improved dark color in Dark theme
v3.1.850
Toolbar will be clickable for Search
v3.1.800
Search bar CardView background
Improve volume zero
Now playing and Album theme picker rollback to dialog
Fix sharing app link
Fix scanning dialog
Added settings icons for options
v3.1.700
Cleaned internal code
Removed full screen option
Added Toolbar elevation
To access menu either tap on Toolbar or Hamburger icon
Fix back button not working on playing queue
Fix crashing on What's New screen
Fix lyrics dialog
Changed toggles to line icons
Fix crashing on artist list for number format error
Fix blacklist dialog crashing
Rearranged icons and main menu access
Fix some crashes when device is locked or background
Folder screen have main options access
Dialogs are now using Material Dialogs v3(BottomSheet)
Fix Shuffle icon for Artist, Album, Genre and Playlist details
v3.1.400
Removed sync lyrics for Android 5
Fix Seek-bar color in settings
Added keyboard to popup on search
Added keyboard to popup on search
Improved lock-screen behavior and UI
Improved text appearance
Fix bio text not showing in settings
Fix not showing slider(blur, filter song) amount in settings
Fix setting ringtone
Fix file sharing crash
Fix some crashes
Fix playlist icon on small devices
Fix empty lyrics text color
Fix album cover background purple color in color theme
v3.1.300
Fix rename playlist text color
Fix same album showing in details page
Fix lyrics text alignment on sync and lyrics reading improved
Improved home sections loading
Removed library options which are duplicated (it's available from profile menu)
Replaced collapsing Fab with Android Floating Extended Fab
Replaced home with for you
Fixed profile image not loading in about
Improved selecting user profile image
Added bio to enter custom message
Improved some UI screens
If you see entire app white or dark or black select same theme in settings to fix
FAQ's
*If you face any UI related issues you clear app data and cache, if its
not working try to
uninstall and install again.
\ No newline at end of file
diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png
index aa6e4ae9a..af146924b 100644
Binary files a/app/src/main/ic_launcher-playstore.png and b/app/src/main/ic_launcher-playstore.png differ
diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png
index 7e7647db5..ff0f8b9ff 100644
Binary files a/app/src/main/ic_launcher-web.png and b/app/src/main/ic_launcher-web.png differ
diff --git a/app/src/main/java/code/name/monkey/retromusic/App.kt b/app/src/main/java/code/name/monkey/retromusic/App.kt
index 93dfe4d96..35479e7ec 100644
--- a/app/src/main/java/code/name/monkey/retromusic/App.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/App.kt
@@ -1,67 +1,74 @@
/*
- * Copyright (c) 2020 Hemanth Savarla.
+ * Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ * This is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by
+ * the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
- *
*/
+
package code.name.monkey.retromusic
-import android.app.Application
-import androidx.preference.PreferenceManager
-import cat.ereza.customactivityoncrash.config.CaocConfig
+import android.widget.Toast
+import androidx.multidex.MultiDexApplication
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils
-import code.name.monkey.retromusic.activities.ErrorActivity
-import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
-import code.name.monkey.retromusic.helper.WallpaperAccentManager
-import org.koin.android.ext.koin.androidContext
-import org.koin.core.context.startKoin
+import code.name.monkey.retromusic.dagger.DaggerMusicComponent
+import code.name.monkey.retromusic.dagger.MusicComponent
+import code.name.monkey.retromusic.dagger.module.AppModule
+import com.anjlab.android.iab.v3.BillingProcessor
+import com.anjlab.android.iab.v3.TransactionDetails
-class App : Application() {
- private val wallpaperAccentManager = WallpaperAccentManager(this)
+class App : MultiDexApplication() {
+
+ lateinit var billingProcessor: BillingProcessor
override fun onCreate() {
+ /* if (MissingSplitsManagerFactory.create(this).disableAppIfMissingRequiredSplits()) {
+ return
+ }*/
super.onCreate()
instance = this
+ musicComponent = DaggerMusicComponent.builder()
+ .appModule(AppModule(this))
+ .build()
- startKoin {
- androidContext(this@App)
- modules(appModules)
- }
// default theme
if (!ThemeStore.isConfigured(this, 3)) {
ThemeStore.editTheme(this)
- .accentColorRes(code.name.monkey.appthemehelper.R.color.md_deep_purple_A200)
- .coloredNavigationBar(true)
- .commit()
+ .accentColorRes(R.color.md_deep_purple_A200)
+ .coloredNavigationBar(true)
+ .commit()
}
- wallpaperAccentManager.init()
if (VersionUtils.hasNougatMR())
DynamicShortcutManager(this).initDynamicShortcuts()
- // setting Error activity
- CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java)
- .restartActivity(MainActivity::class.java).apply()
+ // automatically restores purchases
+ billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY,
+ object : BillingProcessor.IBillingHandler {
+ override fun onProductPurchased(productId: String, details: TransactionDetails?) {}
- // Set Default values for now playing preferences
- // This will reduce startup time for now playing settings fragment as Preference listener of AbsSlidingMusicPanelActivity won't be called
- PreferenceManager.setDefaultValues(this, R.xml.pref_now_playing_screen, false)
+ override fun onPurchaseHistoryRestored() {
+ Toast.makeText(this@App, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show();
+ }
+
+ override fun onBillingError(errorCode: Int, error: Throwable?) {}
+
+ override fun onBillingInitialized() {}
+ })
}
override fun onTerminate() {
super.onTerminate()
- wallpaperAccentManager.release()
+ billingProcessor.release()
}
companion object {
@@ -70,5 +77,14 @@ class App : Application() {
fun getContext(): App {
return instance!!
}
+
+ fun isProVersion(): Boolean {
+ return BuildConfig.DEBUG || instance?.billingProcessor!!.isPurchased(PRO_VERSION_PRODUCT_ID)
+ }
+
+ lateinit var musicComponent: MusicComponent
+
+ const val PRO_VERSION_PRODUCT_ID = "pro_version"
+
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/Constants.kt b/app/src/main/java/code/name/monkey/retromusic/Constants.kt
index 31032f62b..6c04105ca 100644
--- a/app/src/main/java/code/name/monkey/retromusic/Constants.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/Constants.kt
@@ -1,154 +1,51 @@
/*
- * Copyright (c) 2020 Hemanth Savarla.
+ * Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ * This is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by
+ * the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
- *
*/
+
package code.name.monkey.retromusic
import android.provider.BaseColumns
import android.provider.MediaStore
object Constants {
- const val TRANSLATE = "https://crowdin.com/project/retromusicplayer"
- const val GITHUB_PROJECT = "https://github.com/MuntashirAkon/Metro"
- const val TELEGRAM_CHANGE_LOG = "https://t.me/AppManagerChannel"
+
+ const val RATE_ON_GOOGLE_PLAY = "https://play.google.com/store/apps/details?id=code.name.monkey.retromusic"
+ const val TRANSLATE = "http://monkeycodeapp.oneskyapp.com/collaboration/project?id=238534"
+ const val GITHUB_PROJECT = "https://github.com/h4h13/RetroMusicPlayer"
+ const val TELEGRAM_CHANGE_LOG = "https://t.me/retromusiclog"
const val USER_PROFILE = "profile.jpg"
const val USER_BANNER = "banner.jpg"
- const val FAQ_LINK = "https://github.com/MuntashirAkon/Metro/blob/master/FAQ.md"
+ const val APP_INSTAGRAM_LINK = "https://www.instagram.com/retromusicapp/"
+ const val APP_TELEGRAM_LINK = "https://t.me/retromusicapp/"
+ const val APP_TWITTER_LINK = "https://twitter.com/retromusicapp"
+ const val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md"
+ const val PINTEREST = "https://in.pinterest.com/retromusicapp/"
- const val IS_MUSIC =
- MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
+ const val BASE_SELECTION = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
- const val DATA = "_data"
-
- @Suppress("Deprecation")
- val baseProjection = arrayOf(
- BaseColumns._ID, // 0
- MediaStore.Audio.AudioColumns.TITLE, // 1
- MediaStore.Audio.AudioColumns.TRACK, // 2
- MediaStore.Audio.AudioColumns.YEAR, // 3
- MediaStore.Audio.AudioColumns.DURATION, // 4
- DATA, // 5
- MediaStore.Audio.AudioColumns.DATE_MODIFIED, // 6
- MediaStore.Audio.AudioColumns.ALBUM_ID, // 7
- MediaStore.Audio.AudioColumns.ALBUM, // 8
- MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
- MediaStore.Audio.AudioColumns.ARTIST, // 10
- MediaStore.Audio.AudioColumns.COMPOSER, // 11
- ALBUM_ARTIST // 12
- )
+ val baseProjection = arrayOf(BaseColumns._ID, // 0
+ MediaStore.Audio.AudioColumns.TITLE, // 1
+ MediaStore.Audio.AudioColumns.TRACK, // 2
+ MediaStore.Audio.AudioColumns.YEAR, // 3
+ MediaStore.Audio.AudioColumns.DURATION, // 4
+ MediaStore.Audio.AudioColumns.DATA, // 5
+ MediaStore.Audio.AudioColumns.DATE_MODIFIED, // 6
+ MediaStore.Audio.AudioColumns.ALBUM_ID, // 7
+ MediaStore.Audio.AudioColumns.ALBUM, // 8
+ MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
+ MediaStore.Audio.AudioColumns.ARTIST,// 10
+ MediaStore.Audio.AudioColumns.COMPOSER)// 11
const val NUMBER_OF_TOP_TRACKS = 99
-}
-const val EXTRA_PLAYLIST_TYPE = "type"
-const val EXTRA_GENRE = "extra_genre"
-const val EXTRA_PLAYLIST = "extra_playlist"
-const val EXTRA_PLAYLIST_ID = "extra_playlist_id"
-const val EXTRA_ALBUM_ID = "extra_album_id"
-const val EXTRA_ARTIST_ID = "extra_artist_id"
-const val EXTRA_SONG = "extra_songs"
-const val EXTRA_PLAYLISTS = "extra_playlists"
-const val LIBRARY_CATEGORIES = "library_categories"
-const val EXTRA_SONG_INFO = "extra_song_info"
-const val DESATURATED_COLOR = "desaturated_color"
-const val BLACK_THEME = "black_theme"
-const val KEEP_SCREEN_ON = "keep_screen_on"
-const val TOGGLE_HOME_BANNER = "toggle_home_banner"
-const val NOW_PLAYING_SCREEN_ID = "now_playing_screen_id"
-const val CAROUSEL_EFFECT = "carousel_effect"
-const val COLORED_NOTIFICATION = "colored_notification"
-const val CLASSIC_NOTIFICATION = "classic_notification"
-const val GAP_LESS_PLAYBACK = "gapless_playback"
-const val ALBUM_ART_ON_LOCK_SCREEN = "album_art_on_lock_screen"
-const val BLURRED_ALBUM_ART = "blurred_album_art"
-const val NEW_BLUR_AMOUNT = "new_blur_amount"
-const val TOGGLE_HEADSET = "toggle_headset"
-const val GENERAL_THEME = "general_theme"
-const val ACCENT_COLOR = "accent_color"
-const val SHOULD_COLOR_APP_SHORTCUTS = "should_color_app_shortcuts"
-const val CIRCULAR_ALBUM_ART = "circular_album_art"
-const val USER_NAME = "user_name"
-const val TOGGLE_FULL_SCREEN = "toggle_full_screen"
-const val TOGGLE_VOLUME = "toggle_volume"
-const val ADAPTIVE_COLOR_APP = "adaptive_color_app"
-const val HOME_ARTIST_GRID_STYLE = "home_artist_grid_style"
-const val HOME_ALBUM_GRID_STYLE = "home_album_grid_style"
-const val TOGGLE_ADD_CONTROLS = "toggle_add_controls"
-const val ALBUM_COVER_STYLE = "album_cover_style_id"
-const val ALBUM_COVER_TRANSFORM = "album_cover_transform"
-const val TAB_TEXT_MODE = "tab_text_mode"
-const val LANGUAGE_NAME = "language_name"
-const val LOCALE_AUTO_STORE_ENABLED = "locale_auto_store_enabled"
-const val SLEEP_TIMER_FINISH_SONG = "sleep_timer_finish_song"
-const val ALBUM_GRID_STYLE = "album_grid_style_home"
-const val ARTIST_GRID_STYLE = "artist_grid_style_home"
-const val SAF_SDCARD_URI = "saf_sdcard_uri"
-const val SONG_SORT_ORDER = "song_sort_order"
-const val SONG_GRID_SIZE = "song_grid_size"
-const val GENRE_SORT_ORDER = "genre_sort_order"
-const val BLUETOOTH_PLAYBACK = "bluetooth_playback"
-const val INITIALIZED_BLACKLIST = "initialized_blacklist"
-const val ARTIST_SORT_ORDER = "artist_sort_order"
-const val ARTIST_ALBUM_SORT_ORDER = "artist_album_sort_order"
-const val ALBUM_SORT_ORDER = "album_sort_order"
-const val PLAYLIST_SORT_ORDER = "playlist_sort_order"
-const val ALBUM_SONG_SORT_ORDER = "album_song_sort_order"
-const val ARTIST_SONG_SORT_ORDER = "artist_song_sort_order"
-const val ALBUM_GRID_SIZE = "album_grid_size"
-const val ALBUM_GRID_SIZE_LAND = "album_grid_size_land"
-const val SONG_GRID_SIZE_LAND = "song_grid_size_land"
-const val ARTIST_GRID_SIZE = "artist_grid_size"
-const val ARTIST_GRID_SIZE_LAND = "artist_grid_size_land"
-const val PLAYLIST_GRID_SIZE = "playlist_grid_size"
-const val PLAYLIST_GRID_SIZE_LAND = "playlist_grid_size_land"
-const val COLORED_APP_SHORTCUTS = "colored_app_shortcuts"
-const val LAST_ADDED_CUTOFF = "last_added_interval"
-const val LAST_SLEEP_TIMER_VALUE = "last_sleep_timer_value"
-const val NEXT_SLEEP_TIMER_ELAPSED_REALTIME = "next_sleep_timer_elapsed_real_time"
-const val IGNORE_MEDIA_STORE_ARTWORK = "ignore_media_store_artwork"
-const val LAST_CHANGELOG_VERSION = "last_changelog_version"
-const val START_DIRECTORY = "start_directory"
-const val RECENTLY_PLAYED_CUTOFF = "recently_played_interval"
-const val LOCK_SCREEN = "lock_screen"
-const val ALBUM_ARTISTS_ONLY = "album_artists_only"
-const val ALBUM_ARTIST = "album_artist"
-const val ALBUM_DETAIL_SONG_SORT_ORDER = "album_detail_song_sort_order"
-const val ARTIST_DETAIL_SONG_SORT_ORDER = "artist_detail_song_sort_order"
-const val LYRICS_OPTIONS = "lyrics_tab_position"
-const val CHOOSE_EQUALIZER = "choose_equalizer"
-const val EQUALIZER = "equalizer"
-const val SONG_GRID_STYLE = "song_grid_style"
-const val PAUSE_ON_ZERO_VOLUME = "pause_on_zero_volume"
-const val FILTER_SONG = "filter_song"
-const val EXPAND_NOW_PLAYING_PANEL = "expand_now_playing_panel"
-const val EXTRA_ARTIST_NAME = "extra_artist_name"
-const val TOGGLE_SUGGESTIONS = "toggle_suggestions"
-const val AUDIO_FADE_DURATION = "audio_fade_duration"
-const val CROSS_FADE_DURATION = "cross_fade_duration"
-const val SHOW_LYRICS = "show_lyrics"
-const val REMEMBER_LAST_TAB = "remember_last_tab"
-const val LAST_USED_TAB = "last_used_tab"
-const val WHITELIST_MUSIC = "whitelist_music"
-const val MATERIAL_YOU = "material_you"
-const val SNOWFALL = "snowfall"
-const val LYRICS_TYPE = "lyrics_type"
-const val PLAYBACK_SPEED = "playback_speed"
-const val PLAYBACK_PITCH = "playback_pitch"
-const val CUSTOM_FONT = "custom_font"
-const val APPBAR_MODE = "appbar_mode"
-const val WALLPAPER_ACCENT = "wallpaper_accent"
-const val SCREEN_ON_LYRICS = "screen_on_lyrics"
-const val CIRCLE_PLAY_BUTTON = "circle_play_button"
-const val SWIPE_ANYWHERE_NOW_PLAYING = "swipe_anywhere_now_playing"
-const val PAUSE_HISTORY = "pause_history"
-const val MANAGE_AUDIO_FOCUS = "manage_audio_focus"
-const val SWIPE_DOWN_DISMISS = "swipe_to_dismiss"
\ No newline at end of file
+
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/HomeSection.kt b/app/src/main/java/code/name/monkey/retromusic/HomeSection.kt
deleted file mode 100644
index 4f1273a03..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/HomeSection.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
-package code.name.monkey.retromusic
-
-import androidx.annotation.IntDef
-
-@IntDef(
- RECENT_ALBUMS,
- TOP_ALBUMS,
- RECENT_ARTISTS,
- TOP_ARTISTS,
- SUGGESTIONS,
- FAVOURITES,
- GENRES,
- PLAYLISTS
-)
-@Retention(AnnotationRetention.SOURCE)
-annotation class HomeSection
-
-const val RECENT_ALBUMS = 3
-const val TOP_ALBUMS = 1
-const val RECENT_ARTISTS = 2
-const val TOP_ARTISTS = 0
-const val SUGGESTIONS = 5
-const val FAVOURITES = 4
-const val GENRES = 6
-const val PLAYLISTS = 7
-const val HISTORY_PLAYLIST = 8
-const val LAST_ADDED_PLAYLIST = 9
-const val TOP_PLAYED_PLAYLIST = 10
diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt
deleted file mode 100644
index d88f8a760..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt
+++ /dev/null
@@ -1,156 +0,0 @@
-package code.name.monkey.retromusic
-
-import androidx.room.Room
-import code.name.monkey.retromusic.auto.AutoMusicProvider
-import code.name.monkey.retromusic.db.MIGRATION_23_24
-import code.name.monkey.retromusic.db.RetroDatabase
-import code.name.monkey.retromusic.fragments.LibraryViewModel
-import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel
-import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel
-import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel
-import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel
-import code.name.monkey.retromusic.model.Genre
-import code.name.monkey.retromusic.repository.*
-import org.koin.android.ext.koin.androidContext
-import org.koin.androidx.viewmodel.dsl.viewModel
-import org.koin.dsl.bind
-import org.koin.dsl.module
-
-private val roomModule = module {
-
- single {
- Room.databaseBuilder(androidContext(), RetroDatabase::class.java, "playlist.db")
- .addMigrations(MIGRATION_23_24)
- .build()
- }
-
- factory {
- get().playlistDao()
- }
-
- factory {
- get().playCountDao()
- }
-
- factory {
- get().historyDao()
- }
-
- single {
- RealRoomRepository(get(), get(), get())
- } bind RoomRepository::class
-}
-private val autoModule = module {
- single {
- AutoMusicProvider(
- androidContext(),
- get(),
- get(),
- get(),
- get(),
- get(),
- get()
- )
- }
-}
-private val mainModule = module {
- single {
- androidContext().contentResolver
- }
-}
-private val dataModule = module {
- single {
- RealRepository(
- get(),
- get(),
- get(),
- get(),
- get(),
- get(),
- get(),
- get(),
- get(),
- get(),
- )
- } bind Repository::class
-
- single {
- RealSongRepository(get())
- } bind SongRepository::class
-
- single {
- RealGenreRepository(get(), get())
- } bind GenreRepository::class
-
- single {
- RealAlbumRepository(get())
- } bind AlbumRepository::class
-
- single {
- RealArtistRepository(get(), get())
- } bind ArtistRepository::class
-
- single {
- RealPlaylistRepository(get())
- } bind PlaylistRepository::class
-
- single {
- RealTopPlayedRepository(get(), get(), get(), get())
- } bind TopPlayedRepository::class
-
- single {
- RealLastAddedRepository(
- get(),
- get(),
- get()
- )
- } bind LastAddedRepository::class
-
- single {
- RealSearchRepository(
- get(),
- get(),
- get(),
- get(),
- get()
- )
- }
-}
-
-private val viewModules = module {
-
- viewModel {
- LibraryViewModel(get())
- }
-
- viewModel { (albumId: Long) ->
- AlbumDetailsViewModel(
- get(),
- albumId
- )
- }
-
- viewModel { (artistId: Long?, artistName: String?) ->
- ArtistDetailsViewModel(
- get(),
- artistId,
- artistName
- )
- }
-
- viewModel { (playlistId: Long) ->
- PlaylistDetailsViewModel(
- get(),
- playlistId
- )
- }
-
- viewModel { (genre: Genre) ->
- GenreDetailsViewModel(
- get(),
- genre
- )
- }
-}
-
-val appModules = listOf(mainModule, dataModule, autoModule, viewModules, roomModule)
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/Result.kt b/app/src/main/java/code/name/monkey/retromusic/Result.kt
new file mode 100644
index 000000000..f2f00f8b9
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/Result.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 Hemanth Savarala.
+ *
+ * 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
+
+/**
+ * Created by hemanths on 2019-10-23.
+ */
+
+sealed class Result {
+ class Success(val data: T) : Result()
+ class Error(val exception: Throwable) : Result()
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/AboutActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/AboutActivity.kt
new file mode 100644
index 000000000..7fa5f9790
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/AboutActivity.kt
@@ -0,0 +1,174 @@
+package code.name.monkey.retromusic.activities
+
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Bundle
+import android.view.MenuItem
+import android.view.View
+import androidx.core.app.ShareCompat
+import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.LinearLayoutManager
+import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
+import code.name.monkey.retromusic.Constants.APP_INSTAGRAM_LINK
+import code.name.monkey.retromusic.Constants.APP_TELEGRAM_LINK
+import code.name.monkey.retromusic.Constants.APP_TWITTER_LINK
+import code.name.monkey.retromusic.Constants.FAQ_LINK
+import code.name.monkey.retromusic.Constants.GITHUB_PROJECT
+import code.name.monkey.retromusic.Constants.PINTEREST
+import code.name.monkey.retromusic.Constants.RATE_ON_GOOGLE_PLAY
+import code.name.monkey.retromusic.Constants.TELEGRAM_CHANGE_LOG
+import code.name.monkey.retromusic.Constants.TRANSLATE
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsBaseActivity
+import code.name.monkey.retromusic.adapter.ContributorAdapter
+import code.name.monkey.retromusic.extensions.surfaceColor
+import code.name.monkey.retromusic.model.Contributor
+import code.name.monkey.retromusic.util.NavigationUtil
+import code.name.monkey.retromusic.util.PreferenceUtil
+import com.afollestad.materialdialogs.LayoutMode
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.bottomsheets.BottomSheet
+import com.afollestad.materialdialogs.list.listItems
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import kotlinx.android.synthetic.main.activity_about.*
+import kotlinx.android.synthetic.main.card_credit.*
+import kotlinx.android.synthetic.main.card_other.*
+import kotlinx.android.synthetic.main.card_retro_info.*
+import kotlinx.android.synthetic.main.card_social.*
+import java.io.IOException
+import java.nio.charset.StandardCharsets
+
+class AboutActivity : AbsBaseActivity(), View.OnClickListener {
+
+ private val assetJsonData: String?
+ get() {
+ val json: String
+ try {
+ val inputStream = assets.open("contributors.json")
+ val size = inputStream.available()
+ val buffer = ByteArray(size)
+ inputStream.read(buffer)
+ inputStream.close()
+ json = String(buffer, StandardCharsets.UTF_8)
+ } catch (ex: IOException) {
+ ex.printStackTrace()
+ return null
+ }
+
+ return json
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setDrawUnderStatusBar()
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_about)
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setLightNavigationBar(true)
+
+
+ loadContributors()
+ setSupportActionBar(toolbar)
+ toolbar.apply {
+ setBackgroundColor(surfaceColor(context))
+ setNavigationOnClickListener { onBackPressed() }
+ ToolbarContentTintHelper.colorBackButton(toolbar)
+ }
+ version.setSummary(getAppVersion())
+ setUpView()
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ onBackPressed()
+ return true
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+ private fun openUrl(url: String) {
+ val i = Intent(Intent.ACTION_VIEW)
+ i.data = Uri.parse(url)
+ i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ startActivity(i)
+ }
+
+ private fun setUpView() {
+ appGithub.setOnClickListener(this)
+ faqLink.setOnClickListener(this)
+ telegramLink.setOnClickListener(this)
+ appRate.setOnClickListener(this)
+ appTranslation.setOnClickListener(this)
+ appShare.setOnClickListener(this)
+ donateLink.setOnClickListener(this)
+ instagramLink.setOnClickListener(this)
+ twitterLink.setOnClickListener(this)
+ changelog.setOnClickListener(this)
+ openSource.setOnClickListener(this)
+ pinterestLink.setOnClickListener(this)
+ bugReportLink.setOnClickListener(this)
+
+ }
+
+ override fun onClick(view: View) {
+ when (view.id) {
+ R.id.pinterestLink -> openUrl(PINTEREST)
+ R.id.faqLink -> openUrl(FAQ_LINK)
+ R.id.telegramLink -> openUrl(APP_TELEGRAM_LINK)
+ R.id.appGithub -> openUrl(GITHUB_PROJECT)
+ R.id.appTranslation -> openUrl(TRANSLATE)
+ R.id.appRate -> openUrl(RATE_ON_GOOGLE_PLAY)
+ R.id.appShare -> shareApp()
+ R.id.donateLink -> NavigationUtil.goToSupportDevelopment(this)
+ R.id.instagramLink -> openUrl(APP_INSTAGRAM_LINK)
+ R.id.twitterLink -> openUrl(APP_TWITTER_LINK)
+ R.id.changelog -> showChangeLogOptions()
+ R.id.openSource -> NavigationUtil.goToOpenSource(this)
+ R.id.bugReportLink -> NavigationUtil.bugReport(this)
+ }
+ }
+
+ private fun showChangeLogOptions() {
+ MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
+ cornerRadius(PreferenceUtil.getInstance(this@AboutActivity).dialogCorner)
+ listItems(items = listOf("Telegram Channel", "App")) { _, position, _ ->
+ if (position == 0) {
+ openUrl(TELEGRAM_CHANGE_LOG)
+ } else {
+ NavigationUtil.gotoWhatNews(this@AboutActivity)
+ }
+ }
+ }
+ }
+
+ private fun getAppVersion(): String {
+ return try {
+ val packageInfo = packageManager.getPackageInfo(packageName, 0)
+ packageInfo.versionName
+ } catch (e: PackageManager.NameNotFoundException) {
+ e.printStackTrace()
+ "0.0.0"
+ }
+ }
+
+ private fun shareApp() {
+ ShareCompat.IntentBuilder.from(this).setType("text/plain")
+ .setChooserTitle(R.string.share_app)
+ .setText(String.format(getString(R.string.app_share), packageName)).startChooser()
+ }
+
+ private fun loadContributors() {
+ val data = assetJsonData
+ val type = object : TypeToken>() {
+
+ }.type
+ val contributors = Gson().fromJson>(data, type)
+
+ val contributorAdapter = ContributorAdapter(contributors)
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ recyclerView.itemAnimator = DefaultItemAnimator()
+ recyclerView.adapter = contributorAdapter
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt
new file mode 100644
index 000000000..14bad2579
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt
@@ -0,0 +1,306 @@
+package code.name.monkey.retromusic.activities
+
+import android.app.ActivityOptions
+import android.content.Intent
+import android.os.Bundle
+import android.view.Menu
+import android.view.MenuItem
+import android.view.SubMenu
+import android.view.View
+import android.widget.ImageView
+import androidx.core.app.ActivityCompat
+import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.LinearLayoutManager
+import code.name.monkey.appthemehelper.ThemeStore
+import code.name.monkey.appthemehelper.util.ATHUtil
+import code.name.monkey.appthemehelper.util.MaterialUtil
+import code.name.monkey.retromusic.App
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
+import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
+import code.name.monkey.retromusic.activities.tageditor.AlbumTagEditorActivity
+import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
+import code.name.monkey.retromusic.album.album.HorizontalAlbumAdapter
+import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
+import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
+import code.name.monkey.retromusic.extensions.ripAlpha
+import code.name.monkey.retromusic.extensions.show
+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.helper.MusicPlayerRemote
+import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder
+import code.name.monkey.retromusic.interfaces.CabHolder
+import code.name.monkey.retromusic.model.Album
+import code.name.monkey.retromusic.model.Artist
+import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsPresenter
+import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsView
+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.RetroColorUtil
+import com.afollestad.materialcab.MaterialCab
+import com.bumptech.glide.Glide
+import kotlinx.android.synthetic.main.activity_album.*
+import kotlinx.android.synthetic.main.activity_album_content.*
+import java.util.*
+import javax.inject.Inject
+import android.util.Pair as UtilPair
+
+
+class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, CabHolder {
+ override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
+ cab?.let {
+ if (it.isActive) it.finish()
+ }
+ cab = MaterialCab(this, R.id.cab_stub)
+ .setMenu(menuRes)
+ .setCloseDrawableRes(R.drawable.ic_close_white_24dp)
+ .setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorSurface)))
+ .start(callback)
+ return cab as MaterialCab
+ }
+
+ private lateinit var simpleSongAdapter: SimpleSongAdapter
+ private lateinit var album: Album
+ private lateinit var artistImage: ImageView
+ private var cab: MaterialCab? = null
+ private val savedSortOrder: String
+ get() = PreferenceUtil.getInstance(this).albumDetailSongSortOrder
+
+ override fun createContentView(): View {
+ return wrapSlidingMusicPanel(R.layout.activity_album)
+ }
+
+ @Inject
+ lateinit var albumDetailsPresenter: AlbumDetailsPresenter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setDrawUnderStatusBar()
+ super.onCreate(savedInstanceState)
+ toggleBottomNavigationView(true)
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setLightNavigationBar(true)
+
+ ActivityCompat.postponeEnterTransition(this)
+
+ App.musicComponent.inject(this)
+ artistImage = findViewById(R.id.artistImage)
+
+ setupRecyclerView()
+
+ artistImage.setOnClickListener {
+ val artistPairs = ActivityOptions.makeSceneTransitionAnimation(this, UtilPair.create(artistImage, getString(R.string.transition_artist_image)))
+ NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs)
+ }
+ playAction.apply {
+ setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
+ }
+ shuffleAction.apply {
+ setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) }
+ }
+
+
+ albumDetailsPresenter.attachView(this)
+
+ if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
+ intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
+ } else {
+ finish()
+ }
+ }
+
+ private fun setupRecyclerView() {
+ simpleSongAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song, this)
+ recyclerView.apply {
+ layoutManager = LinearLayoutManager(this@AlbumDetailsActivity)
+ itemAnimator = DefaultItemAnimator()
+ isNestedScrollingEnabled = false
+ adapter = simpleSongAdapter
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ albumDetailsPresenter.detachView()
+ }
+
+ override fun complete() {
+ ActivityCompat.startPostponedEnterTransition(this)
+ }
+
+ override fun album(album: Album) {
+
+ if (album.songs!!.isEmpty()) {
+ finish()
+ return
+ }
+ this.album = album
+
+ albumTitle.text = album.title
+ if (MusicUtil.getYearString(album.year) == "-") {
+ albumText.text = String.format("%s • %s", album.artistName, MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, album.songs)))
+ } else {
+ albumText.text = String.format("%s • %s • %s", album.artistName, MusicUtil.getYearString(album.year), MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, album.songs)))
+ }
+ loadAlbumCover()
+ simpleSongAdapter.swapDataSet(album.songs)
+ albumDetailsPresenter.loadMore(album.artistId)
+ }
+
+ override fun moreAlbums(albums: ArrayList) {
+ moreTitle.show()
+ moreRecyclerView.show()
+ moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName)
+
+ val albumAdapter = HorizontalAlbumAdapter(this, albums, false, null)
+ moreRecyclerView.layoutManager = GridLayoutManager(
+ this,
+ 1,
+ GridLayoutManager.HORIZONTAL,
+ false
+ )
+ moreRecyclerView.adapter = albumAdapter
+ }
+
+ override fun loadArtistImage(artist: Artist) {
+ ArtistGlideRequest.Builder.from(Glide.with(this), artist).generatePalette(this).build()
+ .dontAnimate().dontTransform().into(object : RetroMusicColoredTarget(artistImage) {
+ override fun onColorReady(color: Int) {
+
+ }
+ })
+
+ }
+
+ private fun loadAlbumCover() {
+ SongGlideRequest.Builder.from(Glide.with(this), album.safeGetFirstSong())
+ .checkIgnoreMediaStore(this).generatePalette(this).build().dontAnimate().dontTransform()
+ .into(object : RetroMusicColoredTarget(image) {
+ override fun onColorReady(color: Int) {
+ setColors(color)
+ }
+ })
+ }
+
+ private fun setColors(color: Int) {
+ val themeColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color.ripAlpha()
+ else ThemeStore.accentColor(this)
+
+ songTitle.setTextColor(themeColor)
+ moreTitle.setTextColor(themeColor)
+
+ val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor)
+ color.ripAlpha()
+ else
+ ATHUtil.resolveColor(this, R.attr.colorSurface)
+
+ MaterialUtil.setTint(button = shuffleAction, color = buttonColor)
+ MaterialUtil.setTint(button = playAction, color = buttonColor)
+
+ val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
+ //status_bar.setBackgroundColor(toolbarColor)
+ toolbar.setBackgroundColor(toolbarColor)
+ setSupportActionBar(toolbar)
+ supportActionBar?.title = null
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_album_detail, menu)
+ val sortOrder = menu.findItem(R.id.action_sort_order)
+ setUpSortOrderMenu(sortOrder.subMenu)
+ return super.onCreateOptionsMenu(menu)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ return handleSortOrderMenuItem(item)
+ }
+
+ private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
+ var sortOrder: String? = null
+ val songs = simpleSongAdapter.dataSet
+ when (item.itemId) {
+ R.id.action_play_next -> {
+ MusicPlayerRemote.playNext(songs)
+ return true
+ }
+ R.id.action_add_to_current_playing -> {
+ MusicPlayerRemote.enqueue(songs)
+ return true
+ }
+ R.id.action_add_to_playlist -> {
+ AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
+ return true
+ }
+ R.id.action_delete_from_device -> {
+ DeleteSongsDialog.create(songs).show(supportFragmentManager, "DELETE_SONGS")
+ return true
+ }
+ android.R.id.home -> {
+ super.onBackPressed()
+ return true
+ }
+ R.id.action_tag_editor -> {
+ val intent = Intent(this, AlbumTagEditorActivity::class.java)
+ intent.putExtra(AbsTagEditorActivity.EXTRA_ID, album.id)
+ val options = ActivityOptions.makeSceneTransitionAnimation(this, image, getString(R.string.transition_album_art))
+ startActivityForResult(intent, TAG_EDITOR_REQUEST, options.toBundle())
+ return true
+ }
+ /*Sort*/
+ R.id.action_sort_order_title -> sortOrder = AlbumSongSortOrder.SONG_A_Z
+ R.id.action_sort_order_title_desc -> sortOrder = AlbumSongSortOrder.SONG_Z_A
+ R.id.action_sort_order_track_list -> sortOrder = AlbumSongSortOrder.SONG_TRACK_LIST
+ R.id.action_sort_order_artist_song_duration -> sortOrder = AlbumSongSortOrder.SONG_DURATION
+ }
+ if (sortOrder != null) {
+ item.isChecked = true
+ setSaveSortOrder(sortOrder)
+ }
+ return true
+ }
+
+ private fun setUpSortOrderMenu(sortOrder: SubMenu) {
+ when (savedSortOrder) {
+ AlbumSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title).isChecked = true
+ AlbumSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc).isChecked = true
+ AlbumSongSortOrder.SONG_TRACK_LIST -> sortOrder.findItem(R.id.action_sort_order_track_list).isChecked = true
+ AlbumSongSortOrder.SONG_DURATION -> sortOrder.findItem(R.id.action_sort_order_artist_song_duration).isChecked = true
+ }
+ }
+
+ private fun setSaveSortOrder(sortOrder: String?) {
+ PreferenceUtil.getInstance(this).albumDetailSongSortOrder = sortOrder
+ reload()
+ }
+
+ override fun onMediaStoreChanged() {
+ super.onMediaStoreChanged()
+ reload()
+ }
+
+ private fun reload() {
+ if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
+ intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
+ } else {
+ finish()
+ }
+ }
+
+ override fun onBackPressed() {
+ if (cab != null && cab!!.isActive) {
+ cab?.finish()
+ } else {
+ super.onBackPressed()
+ }
+ }
+
+ companion object {
+
+ const val EXTRA_ALBUM_ID = "extra_album_id"
+ private const val TAG_EDITOR_REQUEST = 2001
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt
new file mode 100755
index 000000000..f9b917225
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt
@@ -0,0 +1,321 @@
+package code.name.monkey.retromusic.activities
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.text.Html
+import android.text.Spanned
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.widget.Toast
+import androidx.core.app.ActivityCompat
+import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.LinearLayoutManager
+import code.name.monkey.appthemehelper.ThemeStore
+import code.name.monkey.appthemehelper.util.ATHUtil
+import code.name.monkey.appthemehelper.util.MaterialUtil
+import code.name.monkey.retromusic.App
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
+import code.name.monkey.retromusic.album.album.AlbumAdapter
+import code.name.monkey.retromusic.album.album.HorizontalAlbumAdapter
+import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
+import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
+import code.name.monkey.retromusic.extensions.ripAlpha
+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.interfaces.CabHolder
+import code.name.monkey.retromusic.model.Artist
+import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsPresenter
+import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsView
+import code.name.monkey.retromusic.rest.model.LastFmArtist
+import code.name.monkey.retromusic.util.*
+import com.afollestad.materialcab.MaterialCab
+import com.bumptech.glide.Glide
+import kotlinx.android.synthetic.main.activity_artist_content.*
+import kotlinx.android.synthetic.main.activity_artist_details.*
+import java.util.*
+import javax.inject.Inject
+import kotlin.collections.ArrayList
+
+class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView, CabHolder {
+ override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
+ cab?.let {
+ if (it.isActive) it.finish()
+ }
+ cab = MaterialCab(this, R.id.cab_stub)
+ .setMenu(menuRes)
+ .setCloseDrawableRes(R.drawable.ic_close_white_24dp)
+ .setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorSurface)))
+ .start(callback)
+ return cab as MaterialCab
+ }
+
+ private var cab: MaterialCab? = null
+ private var biography: Spanned? = null
+ private lateinit var artist: Artist
+ private lateinit var songAdapter: SimpleSongAdapter
+ private lateinit var albumAdapter: AlbumAdapter
+ private var forceDownload: Boolean = false
+
+ override fun createContentView(): View {
+ return wrapSlidingMusicPanel(R.layout.activity_artist_details)
+ }
+
+ @Inject
+ lateinit var artistDetailsPresenter: ArtistDetailsPresenter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setDrawUnderStatusBar()
+ super.onCreate(savedInstanceState)
+ toggleBottomNavigationView(true)
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setLightNavigationBar(true)
+
+ ActivityCompat.postponeEnterTransition(this)
+
+ setUpViews()
+
+ playAction.apply {
+ setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
+ }
+ shuffleAction.apply {
+ setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
+ }
+
+ biographyText.setOnClickListener {
+ if (biographyText.maxLines == 4) {
+ biographyText.maxLines = Integer.MAX_VALUE
+ } else {
+ biographyText.maxLines = 4
+ }
+ }
+
+ App.musicComponent.inject(this)
+ artistDetailsPresenter.attachView(this)
+
+ if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
+ intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) }
+ } else {
+ finish()
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ artistDetailsPresenter.detachView()
+ }
+
+ private fun setUpViews() {
+ setupRecyclerView()
+ setupContainerHeight()
+ }
+
+ private fun setupContainerHeight() {
+ imageContainer?.let {
+ val params = it.layoutParams
+ params.width = DensityUtil.getScreenHeight(this) / 2
+ it.layoutParams = params
+ }
+ }
+
+ private fun setupRecyclerView() {
+ albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), false, null)
+ albumRecyclerView.apply {
+ itemAnimator = DefaultItemAnimator()
+ layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
+ adapter = albumAdapter
+ }
+ songAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song, this)
+ recyclerView.apply {
+ itemAnimator = DefaultItemAnimator()
+ layoutManager = LinearLayoutManager(this.context)
+ adapter = songAdapter
+ }
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ when (requestCode) {
+ REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
+ data?.data?.let {
+ CustomArtistImageUtil.getInstance(this).setCustomArtistImage(artist, it)
+ }
+ }
+ else -> if (resultCode == Activity.RESULT_OK) {
+ reload()
+ }
+ }
+ }
+
+ override fun showEmptyView() {
+
+ }
+
+ override fun complete() {
+ ActivityCompat.startPostponedEnterTransition(this)
+ }
+
+ override fun artist(artist: Artist) {
+ if (artist.songCount <= 0) {
+ finish()
+ }
+ this.artist = artist
+ loadArtistImage()
+
+ if (RetroUtil.isAllowedToDownloadMetadata(this)) {
+ loadBiography(artist.name)
+ }
+ artistTitle.text = artist.name
+ text.text = String.format(
+ "%s • %s",
+ MusicUtil.getArtistInfoString(this, artist),
+ MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, artist.songs))
+ )
+
+ songAdapter.swapDataSet(artist.songs)
+ albumAdapter.swapDataSet(artist.albums!!)
+ }
+
+ private fun loadBiography(
+ name: String, lang: String? = Locale.getDefault().language
+ ) {
+ biography = null
+ this.lang = lang
+ artistDetailsPresenter.loadBiography(name, lang, null)
+ }
+
+ override fun artistInfo(lastFmArtist: LastFmArtist?) {
+ if (lastFmArtist != null && lastFmArtist.artist != null) {
+ val bioContent = lastFmArtist.artist.bio.content
+ if (bioContent != null && bioContent.trim { it <= ' ' }.isNotEmpty()) {
+ biographyText.visibility = View.VISIBLE
+ biographyTitle.visibility = View.VISIBLE
+ biography = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ Html.fromHtml(bioContent, Html.FROM_HTML_MODE_LEGACY)
+ } else {
+ Html.fromHtml(bioContent)
+ }
+ biographyText.text = biography
+ }
+ }
+
+ // If the "lang" parameter is set and no biography is given, retry with default language
+ if (biography == null && lang != null) {
+ loadBiography(artist.name, null)
+ }
+ }
+
+ private var lang: String? = null
+
+ private fun loadArtistImage() {
+ ArtistGlideRequest.Builder.from(Glide.with(this), artist).generatePalette(this).build()
+ .dontAnimate().into(object : RetroMusicColoredTarget(artistImage) {
+ override fun onColorReady(color: Int) {
+ setColors(color)
+ }
+ })
+ }
+
+ private fun setColors(color: Int) {
+ val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor)
+ color.ripAlpha()
+ else
+ ThemeStore.accentColor(this)
+
+ albumTitle.setTextColor(textColor)
+ songTitle.setTextColor(textColor)
+ biographyTitle.setTextColor(textColor)
+
+ val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor)
+ color.ripAlpha()
+ else
+ ATHUtil.resolveColor(this, R.attr.colorSurface)
+
+ MaterialUtil.setTint(button = shuffleAction, color = buttonColor)
+ MaterialUtil.setTint(button = playAction, color = buttonColor)
+
+ val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
+ //status_bar.setBackgroundColor(toolbarColor)
+ toolbar.setBackgroundColor(toolbarColor)
+ setSupportActionBar(toolbar)
+ supportActionBar?.title = null
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ return handleSortOrderMenuItem(item)
+ }
+
+ private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
+ val songs = artist.songs
+ when (item.itemId) {
+ android.R.id.home -> {
+ super.onBackPressed()
+ return true
+ }
+ R.id.action_play_next -> {
+ MusicPlayerRemote.playNext(songs)
+ return true
+ }
+ R.id.action_add_to_current_playing -> {
+ MusicPlayerRemote.enqueue(songs)
+ return true
+ }
+ R.id.action_add_to_playlist -> {
+ AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
+ return true
+ }
+ R.id.action_set_artist_image -> {
+ val intent = Intent(Intent.ACTION_GET_CONTENT)
+ intent.type = "image/*"
+ startActivityForResult(Intent.createChooser(intent, getString(R.string.pick_from_local_storage)), REQUEST_CODE_SELECT_IMAGE)
+ return true
+ }
+ R.id.action_reset_artist_image -> {
+ Toast.makeText(this@ArtistDetailActivity, resources.getString(R.string.updating), Toast.LENGTH_SHORT).show()
+ CustomArtistImageUtil.getInstance(this@ArtistDetailActivity).resetCustomArtistImage(artist)
+ forceDownload = true
+ return true
+ }
+ }
+ return true
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_artist_detail, menu)
+ return super.onCreateOptionsMenu(menu)
+ }
+
+ override fun onMediaStoreChanged() {
+ super.onMediaStoreChanged()
+ reload()
+ }
+
+ private fun reload() {
+ if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
+ intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) }
+ } else {
+ finish()
+ }
+ }
+
+ override fun onBackPressed() {
+ if (cab != null && cab!!.isActive) {
+ cab?.finish()
+ } else {
+ super.onBackPressed()
+ }
+ }
+
+ companion object {
+
+ const val EXTRA_ARTIST_ID = "extra_artist_id"
+ const val REQUEST_CODE_SELECT_IMAGE = 9003
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt
deleted file mode 100644
index af3890d22..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
-package code.name.monkey.retromusic.activities
-
-import android.content.Intent
-import android.graphics.Color
-import android.graphics.PorterDuff
-import android.os.Bundle
-import androidx.lifecycle.lifecycleScope
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
-import code.name.monkey.retromusic.databinding.ActivityDriveModeBinding
-import code.name.monkey.retromusic.db.toSongEntity
-import code.name.monkey.retromusic.extensions.accentColor
-import code.name.monkey.retromusic.extensions.drawAboveSystemBars
-import code.name.monkey.retromusic.glide.BlurTransformation
-import code.name.monkey.retromusic.glide.RetroGlideExtension
-import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions
-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.model.Song
-import code.name.monkey.retromusic.repository.RealRepository
-import code.name.monkey.retromusic.service.MusicService
-import code.name.monkey.retromusic.util.MusicUtil
-import com.bumptech.glide.Glide
-import com.google.android.material.slider.Slider
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import org.koin.android.ext.android.inject
-
-
-/**
- * Created by hemanths on 2020-02-02.
- */
-
-class DriveModeActivity : AbsMusicServiceActivity(), Callback {
-
- private lateinit var binding: ActivityDriveModeBinding
- private var lastPlaybackControlsColor: Int = Color.GRAY
- private var lastDisabledPlaybackControlsColor: Int = Color.GRAY
- private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
- private val repository: RealRepository by inject()
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = ActivityDriveModeBinding.inflate(layoutInflater)
- setContentView(binding.root)
- setUpMusicControllers()
-
- progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
- lastPlaybackControlsColor = accentColor()
- binding.close.setOnClickListener {
- onBackPressedDispatcher.onBackPressed()
- }
- binding.repeatButton.drawAboveSystemBars()
- }
-
- private fun setUpMusicControllers() {
- setUpPlayPauseFab()
- setUpPrevNext()
- setUpRepeatButton()
- setUpShuffleButton()
- setUpProgressSlider()
- setupFavouriteToggle()
- }
-
- private fun setupFavouriteToggle() {
- binding.songFavourite.setOnClickListener {
- toggleFavorite(MusicPlayerRemote.currentSong)
- }
- }
-
- private fun toggleFavorite(song: Song) {
- lifecycleScope.launch(Dispatchers.IO) {
- val playlist = repository.favoritePlaylist()
- val songEntity = song.toSongEntity(playlist.playListId)
- val isFavorite = repository.isSongFavorite(song.id)
- if (isFavorite) {
- repository.removeSongFromPlaylist(songEntity)
- } else {
- repository.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
- }
- sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
- }
- }
-
- private fun updateFavorite() {
- lifecycleScope.launch(Dispatchers.IO) {
- val isFavorite: Boolean =
- repository.isSongFavorite(MusicPlayerRemote.currentSong.id)
- withContext(Dispatchers.Main) {
- binding.songFavourite.setImageResource(if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border)
- }
- }
- }
-
- private fun setUpProgressSlider() {
- binding.progressSlider.addOnChangeListener { _: Slider, progress: Float, fromUser: Boolean ->
- if (fromUser) {
- MusicPlayerRemote.seekTo(progress.toInt())
- onUpdateProgressViews(
- MusicPlayerRemote.songProgressMillis,
- MusicPlayerRemote.songDurationMillis
- )
- }
- }
- }
-
- override fun onPause() {
- super.onPause()
- progressViewUpdateHelper.stop()
- }
-
- override fun onResume() {
- super.onResume()
- progressViewUpdateHelper.start()
- }
-
- private fun setUpPrevNext() {
- binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
- binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
- }
-
- private fun setUpShuffleButton() {
- binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
- }
-
- private fun setUpRepeatButton() {
- binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
- }
-
- private fun setUpPlayPauseFab() {
- binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
- }
-
- override fun onRepeatModeChanged() {
- super.onRepeatModeChanged()
- updateRepeatState()
- }
-
- override fun onShuffleModeChanged() {
- super.onShuffleModeChanged()
- updateShuffleState()
- }
-
- override fun onPlayStateChanged() {
- super.onPlayStateChanged()
- updatePlayPauseDrawableState()
- }
-
- override fun onServiceConnected() {
- super.onServiceConnected()
- updatePlayPauseDrawableState()
- updateSong()
- updateRepeatState()
- updateShuffleState()
- updateFavorite()
- }
-
- private fun updatePlayPauseDrawableState() {
- if (MusicPlayerRemote.isPlaying) {
- binding.playPauseButton.setImageResource(R.drawable.ic_pause)
- } else {
- binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow)
- }
- }
-
- fun updateShuffleState() {
- when (MusicPlayerRemote.shuffleMode) {
- MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
- lastPlaybackControlsColor,
- PorterDuff.Mode.SRC_IN
- )
-
- else -> binding.shuffleButton.setColorFilter(
- lastDisabledPlaybackControlsColor,
- PorterDuff.Mode.SRC_IN
- )
- }
- }
-
- private fun updateRepeatState() {
- when (MusicPlayerRemote.repeatMode) {
- MusicService.REPEAT_MODE_NONE -> {
- binding.repeatButton.setImageResource(R.drawable.ic_repeat)
- binding.repeatButton.setColorFilter(
- lastDisabledPlaybackControlsColor,
- PorterDuff.Mode.SRC_IN
- )
- }
-
- MusicService.REPEAT_MODE_ALL -> {
- binding.repeatButton.setImageResource(R.drawable.ic_repeat)
- binding.repeatButton.setColorFilter(
- lastPlaybackControlsColor,
- PorterDuff.Mode.SRC_IN
- )
- }
-
- MusicService.REPEAT_MODE_THIS -> {
- binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
- binding.repeatButton.setColorFilter(
- lastPlaybackControlsColor,
- PorterDuff.Mode.SRC_IN
- )
- }
- }
- }
-
- override fun onPlayingMetaChanged() {
- super.onPlayingMetaChanged()
- updateSong()
- updateFavorite()
- }
-
- override fun onFavoriteStateChanged() {
- super.onFavoriteStateChanged()
- updateFavorite()
- }
-
- private fun updateSong() {
- val song = MusicPlayerRemote.currentSong
-
- binding.songTitle.text = song.title
- binding.songText.text = song.artistName
-
- Glide.with(this)
- .load(RetroGlideExtension.getSongModel(song))
- .songCoverOptions(song)
- .transform(BlurTransformation.Builder(this).build())
- .into(binding.image)
- }
-
- override fun onUpdateProgressViews(progress: Int, total: Int) {
- binding.progressSlider.run {
- valueTo = total.toFloat()
- value = progress.toFloat().coerceIn(valueFrom, valueTo)
- }
-
- binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
- binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
- }
-}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/ErrorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/ErrorActivity.kt
deleted file mode 100644
index 6823b80f8..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/ErrorActivity.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-package code.name.monkey.retromusic.activities
-
-import android.os.Bundle
-import android.widget.Button
-import android.widget.ImageView
-import androidx.appcompat.app.AppCompatActivity
-import cat.ereza.customactivityoncrash.CustomActivityOnCrash
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.util.FileUtils.createFile
-import code.name.monkey.retromusic.util.Share.shareFile
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import java.text.DateFormat
-import java.text.SimpleDateFormat
-import java.util.*
-
-class ErrorActivity : AppCompatActivity() {
- private val dayFormat: DateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
- private val reportPrefix = "bug_report-"
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(cat.ereza.customactivityoncrash.R.layout.customactivityoncrash_default_error_activity)
-
- val restartButton =
- findViewById(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_restart_button)
-
- val config = CustomActivityOnCrash.getConfigFromIntent(intent)
- if (config == null) {
- finish()
- return
- }
- restartButton.setText(cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_restart_app)
- restartButton.setOnClickListener {
- CustomActivityOnCrash.restartApplication(
- this@ErrorActivity,
- config
- )
- }
- val moreInfoButton =
- findViewById(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_more_info_button)
-
- moreInfoButton.setOnClickListener { //We retrieve all the error data and show it
- MaterialAlertDialogBuilder(this@ErrorActivity)
- .setTitle(cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_error_details_title)
- .setMessage(
- CustomActivityOnCrash.getAllErrorDetailsFromIntent(
- this@ErrorActivity,
- intent
- )
- )
- .setPositiveButton(
- cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_error_details_close,
- null
- )
- .setNeutralButton(
- R.string.customactivityoncrash_error_activity_error_details_share
- ) { _, _ ->
-
- val bugReport = createFile(
- context = this,
- "Bug Report",
- "$reportPrefix${dayFormat.format(Date())}",
- CustomActivityOnCrash.getAllErrorDetailsFromIntent(
- this@ErrorActivity,
- intent
- ), ".txt"
- )
- shareFile(this, bugReport, "text/*")
- }
- .show()
- }
- val errorActivityDrawableId = config.errorDrawable
- val errorImageView =
- findViewById(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_image)
- if (errorActivityDrawableId != null) {
- errorImageView.setImageResource(
- errorActivityDrawableId
- )
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/GenreDetailsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/GenreDetailsActivity.kt
new file mode 100644
index 000000000..6d3ca8091
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/GenreDetailsActivity.kt
@@ -0,0 +1,151 @@
+package code.name.monkey.retromusic.activities
+
+import android.os.Bundle
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import code.name.monkey.appthemehelper.util.ATHUtil
+import code.name.monkey.retromusic.App
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
+import code.name.monkey.retromusic.adapter.song.ShuffleButtonSongAdapter
+import code.name.monkey.retromusic.extensions.applyToolbar
+import code.name.monkey.retromusic.helper.menu.GenreMenuHelper
+import code.name.monkey.retromusic.interfaces.CabHolder
+import code.name.monkey.retromusic.model.Genre
+import code.name.monkey.retromusic.model.Song
+import code.name.monkey.retromusic.mvp.presenter.GenreDetailsPresenter
+import code.name.monkey.retromusic.mvp.presenter.GenreDetailsView
+import code.name.monkey.retromusic.util.RetroColorUtil
+import code.name.monkey.retromusic.util.ViewUtil
+import com.afollestad.materialcab.MaterialCab
+import kotlinx.android.synthetic.main.activity_playlist_detail.*
+import java.util.*
+import javax.inject.Inject
+
+/**
+ * @author Hemanth S (h4h13).
+ */
+
+class GenreDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder, GenreDetailsView {
+
+ @Inject
+ lateinit var genreDetailsPresenter: GenreDetailsPresenter
+
+ private lateinit var genre: Genre
+ private lateinit var songAdapter: ShuffleButtonSongAdapter
+ private var cab: MaterialCab? = null
+
+ private fun getEmojiByUnicode(unicode: Int): String {
+ return String(Character.toChars(unicode))
+ }
+
+ private fun checkIsEmpty() {
+ emptyEmoji.text = getEmojiByUnicode(0x1F631)
+ empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setDrawUnderStatusBar()
+ super.onCreate(savedInstanceState)
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setLightNavigationBar(true)
+ toggleBottomNavigationView(true)
+
+ if (intent.extras != null) {
+ genre = intent?.extras?.getParcelable(EXTRA_GENRE_ID)!!
+ } else {
+ finish()
+ }
+
+ setUpToolBar()
+ setupRecyclerView()
+
+ App.musicComponent.inject(this)
+ genreDetailsPresenter.attachView(this)
+
+ }
+
+ private fun setUpToolBar() {
+ applyToolbar(toolbar)
+ title = genre.name
+ }
+
+ override fun onResume() {
+ super.onResume()
+ genreDetailsPresenter.loadGenreSongs(genre.id)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ genreDetailsPresenter.detachView()
+ }
+
+ override fun createContentView(): View {
+ return wrapSlidingMusicPanel(R.layout.activity_playlist_detail)
+ }
+
+ override fun showEmptyView() {
+
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_genre_detail, menu)
+ return super.onCreateOptionsMenu(menu)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ onBackPressed()
+ }
+ return GenreMenuHelper.handleMenuClick(this, genre, item)
+ }
+
+ private fun setupRecyclerView() {
+ ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
+ songAdapter = ShuffleButtonSongAdapter(this, ArrayList(), R.layout.item_list, false, this)
+ recyclerView.apply {
+ itemAnimator = DefaultItemAnimator()
+ layoutManager = LinearLayoutManager(this@GenreDetailsActivity)
+ adapter = songAdapter
+ }
+ songAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
+ override fun onChanged() {
+ super.onChanged()
+ checkIsEmpty()
+ }
+ })
+ }
+
+ override fun songs(songs: ArrayList) {
+ songAdapter.swapDataSet(songs)
+ }
+
+ override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
+ if (cab != null && cab!!.isActive) cab!!.finish()
+ cab = MaterialCab(this, R.id.cab_stub).setMenu(menuRes).setCloseDrawableRes(R.drawable.ic_close_white_24dp).setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorSurface))).start(callback)
+ return cab!!
+ }
+
+ override fun onBackPressed() {
+ if (cab != null && cab!!.isActive) cab!!.finish()
+ else {
+ recyclerView!!.stopScroll()
+ super.onBackPressed()
+ }
+ }
+
+ override fun onMediaStoreChanged() {
+ super.onMediaStoreChanged()
+ genreDetailsPresenter.loadGenreSongs(genre.id)
+ }
+
+ companion object {
+ const val EXTRA_GENRE_ID = "extra_genre_id"
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.java b/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.java
new file mode 100644
index 000000000..00e742ac2
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019 Hemanth Savarala.
+ *
+ * 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.activities;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.webkit.WebView;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.Toolbar;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+import code.name.monkey.appthemehelper.ThemeStore;
+import code.name.monkey.appthemehelper.util.ColorUtil;
+import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper;
+import code.name.monkey.retromusic.R;
+import code.name.monkey.retromusic.activities.base.AbsBaseActivity;
+
+import static code.name.monkey.appthemehelper.util.ATHUtil.INSTANCE;
+
+/**
+ * Created by hemanths on 2019-09-27.
+ */
+public class LicenseActivity extends AbsBaseActivity {
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private String colorToCSS(int color) {
+ return String.format("rgb(%d, %d, %d)", Color.red(color), Color.green(color), Color.blue(color)); // on API 29, WebView doesn't load with hex colors
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ setDrawUnderStatusBar();
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_license);
+ setStatusbarColorAuto();
+ setNavigationbarColorAuto();
+ setLightNavigationBar(true);
+ Toolbar toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ ToolbarContentTintHelper.colorBackButton(toolbar);
+ toolbar.setBackgroundColor(INSTANCE.resolveColor(this, R.attr.colorSurface));
+ WebView webView = findViewById(R.id.license);
+ try {
+ StringBuilder buf = new StringBuilder();
+ InputStream json = getAssets().open("index.html");
+ BufferedReader in = new BufferedReader(new InputStreamReader(json, StandardCharsets.UTF_8));
+ String str;
+ while ((str = in.readLine()) != null)
+ buf.append(str);
+ in.close();
+
+ // Inject color values for WebView body background and links
+ final boolean isDark = INSTANCE.isWindowBackgroundDark(this);
+ final String backgroundColor = colorToCSS(INSTANCE.resolveColor(this, android.R.attr.windowBackground, Color.parseColor(isDark ? "#424242" : "#ffffff")));
+ final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000"));
+ final String changeLog = buf.toString()
+ .replace("{style-placeholder}",
+ String.format("body { background-color: %s; color: %s; }", backgroundColor, contentColor))
+ .replace("{link-color}", colorToCSS(ThemeStore.Companion.accentColor(this)))
+ .replace("{link-color-active}", colorToCSS(ColorUtil.INSTANCE.lightenColor(ThemeStore.Companion.accentColor(this))));
+
+ webView.loadData(changeLog, "text/html", "UTF-8");
+ } catch (Throwable e) {
+ webView.loadData("Unable to load " + e.getLocalizedMessage() + "
", "text/html", "UTF-8");
+ }
+
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt
deleted file mode 100644
index e41352dae..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2019 Hemanth Savarala.
- *
- * 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.activities
-
-import android.graphics.Color
-import android.os.Bundle
-import android.view.MenuItem
-import code.name.monkey.appthemehelper.util.ATHUtil.isWindowBackgroundDark
-import code.name.monkey.appthemehelper.util.ColorUtil.lightenColor
-import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
-import code.name.monkey.retromusic.activities.base.AbsThemeActivity
-import code.name.monkey.retromusic.databinding.ActivityLicenseBinding
-import code.name.monkey.retromusic.extensions.accentColor
-import code.name.monkey.retromusic.extensions.drawAboveSystemBars
-import code.name.monkey.retromusic.extensions.surfaceColor
-import java.io.BufferedReader
-import java.io.InputStreamReader
-import java.nio.charset.StandardCharsets
-
-/** Created by hemanths on 2019-09-27. */
-class LicenseActivity : AbsThemeActivity() {
- private lateinit var binding: ActivityLicenseBinding
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = ActivityLicenseBinding.inflate(layoutInflater)
- setContentView(binding.root)
- setSupportActionBar(binding.toolbar)
- ToolbarContentTintHelper.colorBackButton(binding.toolbar)
- try {
- val buf = StringBuilder()
- val json = assets.open("license.html")
- BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8)).use { br ->
- var str: String?
- while (br.readLine().also { str = it } != null) {
- buf.append(str)
- }
- }
-
- // Inject color values for WebView body background and links
- val isDark = isWindowBackgroundDark(this)
- val backgroundColor = colorToCSS(
- surfaceColor(Color.parseColor(if (isDark) "#424242" else "#ffffff"))
- )
- val contentColor = colorToCSS(Color.parseColor(if (isDark) "#ffffff" else "#000000"))
- val changeLog = buf.toString()
- .replace(
- "{style-placeholder}", String.format(
- "body { background-color: %s; color: %s; }", backgroundColor, contentColor
- )
- )
- .replace("{link-color}", colorToCSS(accentColor()))
- .replace(
- "{link-color-active}",
- colorToCSS(
- lightenColor(accentColor())
- )
- )
- binding.license.loadData(changeLog, "text/html", "UTF-8")
- } catch (e: Throwable) {
- binding.license.loadData(
- "Unable to load " + e.localizedMessage + "
", "text/html", "UTF-8"
- )
- }
- binding.license.drawAboveSystemBars()
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == android.R.id.home) {
- onBackPressedDispatcher.onBackPressed()
- return true
- }
- return super.onOptionsItemSelected(item)
- }
-
- private fun colorToCSS(color: Int): String {
- return String.format(
- "rgb(%d, %d, %d)",
- Color.red(color),
- Color.green(color),
- Color.blue(color)
- ) // on API 29, WebView doesn't load with hex colors
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/LockScreenActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/LockScreenActivity.kt
index 3ac219871..3f0dffbd3 100644
--- a/app/src/main/java/code/name/monkey/retromusic/activities/LockScreenActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/LockScreenActivity.kt
@@ -1,121 +1,96 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.activities
import android.app.KeyguardManager
+import android.content.Context
+import android.os.Build
import android.os.Bundle
+import android.view.View
import android.view.WindowManager
-import androidx.core.content.getSystemService
-import code.name.monkey.appthemehelper.util.VersionUtils
+import androidx.core.view.ViewCompat
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
-import code.name.monkey.retromusic.databinding.ActivityLockScreenBinding
-import code.name.monkey.retromusic.extensions.hideStatusBar
-import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
-import code.name.monkey.retromusic.extensions.whichFragment
-import code.name.monkey.retromusic.fragments.player.lockscreen.LockScreenControlsFragment
-import code.name.monkey.retromusic.glide.RetroGlideExtension
-import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
-import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions
+import code.name.monkey.retromusic.fragments.player.lockscreen.LockScreenPlayerControlsFragment
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.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import com.r0adkll.slidr.Slidr
import com.r0adkll.slidr.model.SlidrConfig
import com.r0adkll.slidr.model.SlidrListener
import com.r0adkll.slidr.model.SlidrPosition
+import kotlinx.android.synthetic.main.activity_lock_screen.*
class LockScreenActivity : AbsMusicServiceActivity() {
- private lateinit var binding: ActivityLockScreenBinding
- private var fragment: LockScreenControlsFragment? = null
+ private var fragment: LockScreenPlayerControlsFragment? = null
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- lockScreenInit()
- binding = ActivityLockScreenBinding.inflate(layoutInflater)
- setContentView(binding.root)
- hideStatusBar()
- setTaskDescriptionColorAuto()
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
+ setShowWhenLocked(true)
+ setTurnScreenOn(true)
+ } else {
+ this.window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
+ }
+ setDrawUnderStatusBar()
+ setContentView(R.layout.activity_lock_screen)
+ hideStatusBar()
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setLightNavigationBar(true)
- val config = SlidrConfig.Builder().listener(object : SlidrListener {
- override fun onSlideStateChanged(state: Int) {
- }
+ val config = SlidrConfig.Builder().listener(object : SlidrListener {
+ override fun onSlideStateChanged(state: Int) {
- override fun onSlideChange(percent: Float) {
- }
+ }
- override fun onSlideOpened() {
- }
+ override fun onSlideChange(percent: Float) {
- override fun onSlideClosed(): Boolean {
- if (VersionUtils.hasOreo()) {
- val keyguardManager =
- getSystemService()
- keyguardManager?.requestDismissKeyguard(this@LockScreenActivity, null)
- }
- finish()
- return true
- }
- }).position(SlidrPosition.BOTTOM).build()
+ }
- Slidr.attach(this, config)
+ override fun onSlideOpened() {
- fragment = whichFragment(R.id.playback_controls_fragment)
+ }
- binding.slide.apply {
- translationY = 100f
- alpha = 0f
- animate().translationY(0f).alpha(1f).setDuration(1500).start()
- }
- }
+ override fun onSlideClosed(): Boolean {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
+ keyguardManager.requestDismissKeyguard(this@LockScreenActivity, null)
+ }
+ finish()
+ return true
+ }
+ }).position(SlidrPosition.BOTTOM).build()
- @Suppress("Deprecation")
- private fun lockScreenInit() {
- if (VersionUtils.hasOreoMR1()) {
- setShowWhenLocked(true)
- //setTurnScreenOn(true)
- } else {
- window.addFlags(
- WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- // or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
- )
- }
- }
+ Slidr.attach(this, config)
- override fun onPlayingMetaChanged() {
- super.onPlayingMetaChanged()
- updateSongs()
- }
+ fragment = supportFragmentManager.findFragmentById(R.id.playback_controls_fragment) as LockScreenPlayerControlsFragment?
- override fun onServiceConnected() {
- super.onServiceConnected()
- updateSongs()
- }
+ findViewById(R.id.slide).apply {
+ translationY = 100f
+ alpha = 0f
+ ViewCompat.animate(this).translationY(0f).alpha(1f).setDuration(1500).start()
+ }
+ }
- private fun updateSongs() {
- val song = MusicPlayerRemote.currentSong
- Glide.with(this)
- .asBitmapPalette()
- .songCoverOptions(song)
- .load(RetroGlideExtension.getSongModel(song))
- .dontAnimate()
- .into(object : RetroMusicColoredTarget(binding.image) {
- override fun onColorReady(colors: MediaNotificationProcessor) {
- fragment?.setColor(colors)
- }
- })
- }
-}
+ override fun onPlayingMetaChanged() {
+ super.onPlayingMetaChanged()
+ updateSongs()
+ }
+
+ override fun onServiceConnected() {
+ super.onServiceConnected()
+ updateSongs()
+ }
+
+ private fun updateSongs() {
+ val song = MusicPlayerRemote.currentSong
+ SongGlideRequest.Builder.from(Glide.with(this), song).checkIgnoreMediaStore(this)
+ .generatePalette(this).build().dontAnimate()
+ .into(object : RetroMusicColoredTarget(image) {
+ override fun onColorReady(color: Int) {
+ fragment?.setDark(color)
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/LyricsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/LyricsActivity.kt
new file mode 100644
index 000000000..70551114c
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/LyricsActivity.kt
@@ -0,0 +1,421 @@
+package code.name.monkey.retromusic.activities
+
+import android.annotation.SuppressLint
+import android.content.res.ColorStateList
+import android.os.AsyncTask
+import android.os.Build
+import android.os.Bundle
+import android.text.InputType
+import android.text.TextUtils
+import android.view.*
+import androidx.annotation.StringRes
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.fragment.app.FragmentStatePagerAdapter
+import androidx.viewpager.widget.ViewPager
+import code.name.monkey.appthemehelper.ThemeStore
+import code.name.monkey.appthemehelper.util.ColorUtil
+import code.name.monkey.appthemehelper.util.MaterialUtil
+import code.name.monkey.appthemehelper.util.MaterialValueHelper
+import code.name.monkey.appthemehelper.util.TintHelper
+import code.name.monkey.retromusic.App
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
+import code.name.monkey.retromusic.activities.tageditor.WriteTagsAsyncTask
+import code.name.monkey.retromusic.extensions.applyToolbar
+import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
+import code.name.monkey.retromusic.helper.MusicPlayerRemote
+import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
+import code.name.monkey.retromusic.lyrics.LrcHelper
+import code.name.monkey.retromusic.lyrics.LrcView
+import code.name.monkey.retromusic.model.Song
+import code.name.monkey.retromusic.model.lyrics.Lyrics
+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 com.afollestad.materialdialogs.LayoutMode
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.bottomsheets.BottomSheet
+import com.afollestad.materialdialogs.input.getInputLayout
+import com.afollestad.materialdialogs.input.input
+import kotlinx.android.synthetic.main.activity_lyrics.*
+import kotlinx.android.synthetic.main.fragment_lyrics.*
+import kotlinx.android.synthetic.main.fragment_synced.*
+import org.jaudiotagger.tag.FieldKey
+import java.io.File
+import java.util.*
+import kotlin.collections.ArrayList
+
+class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener, ViewPager.OnPageChangeListener {
+ override fun onPageScrollStateChanged(state: Int) {
+ when (state) {
+ ViewPager.SCROLL_STATE_IDLE -> fab.show()
+ ViewPager.SCROLL_STATE_DRAGGING, ViewPager.SCROLL_STATE_SETTLING -> fab.hide()
+ }
+ }
+
+ override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
+ }
+
+ override fun onPageSelected(position: Int) {
+ PreferenceUtil.getInstance(this).lyricsOptions = position
+ if (position == 0) fab.text = getString(R.string.synced_lyrics)
+ else if (position == 1) fab.text = getString(R.string.lyrics)
+ }
+
+ override fun onClick(v: View?) {
+ when (viewPager.currentItem) {
+ 0 -> showSyncedLyrics()
+ 1 -> showLyricsSaveDialog()
+ }
+ }
+
+ private lateinit var song: Song
+ private var lyricsString: String? = null
+
+ private val googleSearchLrcUrl: String
+ get() {
+ var baseUrl = "http://www.google.com/search?"
+ var query = song.title + "+" + song.artistName
+ query = "q=" + query.replace(" ", "+") + " .lrc"
+ baseUrl += query
+ return baseUrl
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_lyrics)
+ setStatusbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setNavigationbarColorAuto()
+
+ applyToolbar(toolbar)
+ fab.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
+ ColorStateList.valueOf(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.accentColor(this))))
+ .apply {
+ fab.setTextColor(this)
+ fab.iconTint = this
+ }
+ setupWakelock()
+
+ viewPager.apply {
+ adapter = PagerAdapter(supportFragmentManager)
+ currentItem = PreferenceUtil.getInstance(this@LyricsActivity).lyricsOptions
+ addOnPageChangeListener(this@LyricsActivity)
+ }
+
+ tabs.apply {
+ setupWithViewPager(viewPager)
+ setSelectedTabIndicator(
+ TintHelper.createTintedDrawable(
+ ContextCompat.getDrawable(
+ this@LyricsActivity, R.drawable.tab_indicator
+ ), ThemeStore.accentColor(this@LyricsActivity)
+ )
+ )
+ setTabTextColors(
+ ThemeStore.textColorSecondary(this@LyricsActivity),
+ ThemeStore.accentColor(this@LyricsActivity)
+ )
+ setSelectedTabIndicatorColor(ThemeStore.accentColor(context))
+ }
+ fab.setOnClickListener(this)
+ }
+
+ override fun onPlayingMetaChanged() {
+ super.onPlayingMetaChanged()
+ song = MusicPlayerRemote.currentSong
+ toolbar.title = song.title
+ toolbar.subtitle = song.artistName
+ }
+
+ override fun onServiceConnected() {
+ super.onServiceConnected()
+ song = MusicPlayerRemote.currentSong
+ toolbar.title = song.title
+ toolbar.subtitle = song.artistName
+ }
+
+ private fun setupWakelock() {
+ window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ onBackPressed()
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+ private fun showSyncedLyrics() {
+ var content = ""
+ try {
+ content = LyricUtil.getStringFromFile(song.data, song.artistName)
+ } catch (e: Exception) {
+ try {
+ content = LyricUtil.getStringFromFile(song.title, song.artistName)
+ } catch (e2: Exception) {
+
+ }
+ e.printStackTrace()
+ }
+
+ val materialDialog = MaterialDialog(
+ this, BottomSheet(LayoutMode.WRAP_CONTENT)
+ ).show {
+ title(R.string.add_time_framed_lryics)
+ negativeButton(R.string.action_search) {
+ RetroUtil.openUrl(
+ this@LyricsActivity, googleSearchLrcUrl
+ )
+ }
+ input(
+ hint = getString(R.string.paste_lyrics_here),
+ prefill = content,
+ inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
+ ) { _, input ->
+ LyricUtil.writeLrcToLoc(song.data, song.artistName, input.toString())
+ }
+ positiveButton(android.R.string.ok) {
+ updateSong()
+ }
+ }
+ MaterialUtil.setTint(materialDialog.getInputLayout(), false)
+ }
+
+ private fun updateSong() {
+ val page = supportFragmentManager.findFragmentByTag("android:switcher:" + R.id.viewPager + ":" + viewPager.currentItem)
+ if (viewPager.currentItem == 0 && page != null) {
+ (page as BaseLyricsFragment).upDateSong()
+ }
+ }
+
+ private fun showLyricsSaveDialog() {
+ val content: String = if (lyricsString == null) {
+ ""
+ } else {
+ lyricsString!!
+ }
+
+ val materialDialog = MaterialDialog(
+ this, BottomSheet(LayoutMode.WRAP_CONTENT)
+ ).show {
+ title(R.string.add_lyrics)
+ negativeButton(R.string.action_search) {
+ RetroUtil.openUrl(
+ this@LyricsActivity, getGoogleSearchUrl()
+ )
+ }
+ input(
+ hint = getString(R.string.paste_lyrics_here),
+ prefill = content,
+ inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
+ ) { _, input ->
+ val fieldKeyValueMap = EnumMap(FieldKey::class.java)
+ fieldKeyValueMap[FieldKey.LYRICS] = input.toString()
+ WriteTagsAsyncTask(this@LyricsActivity).execute(
+ WriteTagsAsyncTask.LoadingInfo(
+ getSongPaths(song), fieldKeyValueMap, null
+ )
+ )
+ }
+ positiveButton(android.R.string.ok) {
+ updateSong()
+ }
+ }
+ MaterialUtil.setTint(materialDialog.getInputLayout(), false)
+ }
+
+ private fun getSongPaths(song: Song): ArrayList {
+ val paths = ArrayList(1)
+ paths.add(song.data)
+ return paths
+ }
+
+ private fun getGoogleSearchUrl(): String {
+ var baseUrl = "http://www.google.com/search?"
+ var query = song.title + "+" + song.artistName
+ query = "q=" + query.replace(" ", "+") + " lyrics"
+ baseUrl += query
+ return baseUrl
+ }
+
+ class PagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(
+ fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
+ ) {
+ class Tabs(
+ @StringRes val title: Int, val fragment: Fragment
+ )
+
+ private var tabs = ArrayList()
+
+ init {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ tabs.add(Tabs(R.string.synced_lyrics, SyncedLyricsFragment()))
+ }
+ tabs.add(Tabs(R.string.normal_lyrics, OfflineLyricsFragment()))
+ }
+
+ override fun getItem(position: Int): Fragment {
+ return tabs[position].fragment
+ }
+
+ override fun getPageTitle(position: Int): CharSequence? {
+ return App.getContext().getString(tabs[position].title)
+ }
+
+ override fun getCount(): Int {
+ return tabs.size
+ }
+
+ }
+
+ abstract class BaseLyricsFragment : AbsMusicServiceFragment() {
+ abstract fun upDateSong()
+
+ override fun onPlayingMetaChanged() {
+ super.onPlayingMetaChanged()
+ upDateSong()
+ }
+
+ override fun onServiceConnected() {
+ super.onServiceConnected()
+ upDateSong()
+ }
+
+ }
+
+ class OfflineLyricsFragment : BaseLyricsFragment() {
+ override fun upDateSong() {
+ loadSongLyrics()
+ }
+
+ private var updateLyricsAsyncTask: AsyncTask<*, *, *>? = null
+ private var lyrics: Lyrics? = null
+
+ @SuppressLint("StaticFieldLeak")
+ private fun loadSongLyrics() {
+ if (updateLyricsAsyncTask != null) {
+ updateLyricsAsyncTask!!.cancel(false)
+ }
+ val song = MusicPlayerRemote.currentSong
+ updateLyricsAsyncTask = object : AsyncTask() {
+ override fun doInBackground(vararg params: Void?): Lyrics? {
+ val data = MusicUtil.getLyrics(song)
+ return if (TextUtils.isEmpty(data)) {
+ null
+ } else Lyrics.parse(song, data!!)
+ }
+
+ override fun onPreExecute() {
+ super.onPreExecute()
+ lyrics = null
+ }
+
+ override fun onPostExecute(l: Lyrics?) {
+ lyrics = l
+ offlineLyrics?.visibility = View.VISIBLE
+ if (l == null) {
+ offlineLyrics?.setText(R.string.no_lyrics_found)
+ return
+ }
+ (activity as LyricsActivity).lyricsString = l.text
+ offlineLyrics?.text = l.text
+ }
+
+ override fun onCancelled(s: Lyrics?) {
+ onPostExecute(null)
+ }
+ }.execute()
+ }
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ loadSongLyrics()
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ if (updateLyricsAsyncTask != null && !updateLyricsAsyncTask!!.isCancelled) {
+ updateLyricsAsyncTask?.cancel(true)
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.fragment_lyrics, container, false)
+ }
+ }
+
+ class SyncedLyricsFragment : BaseLyricsFragment(), MusicProgressViewUpdateHelper.Callback {
+ override fun upDateSong() {
+ loadLRCLyrics()
+ }
+
+ private lateinit var updateHelper: MusicProgressViewUpdateHelper
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.fragment_synced, container, false)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ updateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupLyricsView()
+ }
+
+ private fun setupLyricsView() {
+ lyricsView.apply {
+ val context = activity!!
+ setCurrentPlayLineColor(ThemeStore.accentColor(context))
+ setIndicatorTextColor(ThemeStore.accentColor(context))
+ setCurrentIndicateLineTextColor(ThemeStore.textColorPrimary(context))
+ setNoLrcTextColor(ThemeStore.textColorPrimary(context))
+ setOnPlayIndicatorLineListener(object : LrcView.OnPlayIndicatorLineListener {
+ override fun onPlay(time: Long, content: String) {
+ MusicPlayerRemote.seekTo(time.toInt())
+ }
+ })
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ updateHelper.start()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ updateHelper.stop()
+ }
+
+ override fun onUpdateProgressViews(progress: Int, total: Int) {
+ lyricsView.updateTime(progress.toLong())
+ }
+
+ private fun loadLRCLyrics() {
+ val song = MusicPlayerRemote.currentSong
+ if (LyricUtil.isLrcFile2Exist(song.data, song.artistName)) {
+ showLyricsLocal(LyricUtil.getLocalLyricFile(song.data, song.artistName))
+ } else {
+ if (LyricUtil.isLrcFileExist(song.title, song.artistName)) {
+ showLyricsLocal(LyricUtil.getLocalLyricFile(song.title, song.artistName))
+ }
+ }
+ }
+
+ private fun showLyricsLocal(file: File?) {
+ if (file != null) {
+ lyricsView.setLrcData(LrcHelper.parseLrcFromFile(file))
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt
index e9cb29abe..116c73500 100644
--- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt
@@ -1,214 +1,267 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.activities
-import android.content.Intent
-import android.net.Uri
+import android.content.*
import android.os.Bundle
import android.provider.MediaStore
-import androidx.lifecycle.lifecycleScope
-import androidx.navigation.contains
-import androidx.navigation.ui.setupWithNavController
+import android.util.Log
+import android.view.View
+import androidx.core.app.ActivityCompat
+import androidx.fragment.app.Fragment
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
-import code.name.monkey.retromusic.extensions.*
+import code.name.monkey.retromusic.fragments.mainactivity.LibraryFragment
+import code.name.monkey.retromusic.fragments.mainactivity.folders.FoldersFragment
+import code.name.monkey.retromusic.fragments.mainactivity.home.BannerHomeFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
-import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs
-import code.name.monkey.retromusic.interfaces.IScrollHelper
-import code.name.monkey.retromusic.model.CategoryInfo
-import code.name.monkey.retromusic.model.Song
-import code.name.monkey.retromusic.repository.PlaylistSongsLoader
+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.service.MusicService
+import code.name.monkey.retromusic.util.AppRater
import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.logE
-import kotlinx.coroutines.Dispatchers.IO
-import kotlinx.coroutines.launch
-import org.koin.android.ext.android.get
+import io.reactivex.disposables.CompositeDisposable
+import java.util.*
-class MainActivity : AbsSlidingMusicPanelActivity() {
- companion object {
- const val TAG = "MainActivity"
- const val EXPAND_PANEL = "expand_panel"
+class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
+
+ private lateinit var currentFragment: MainActivityFragmentCallbacks
+
+ private var blockRequestPermissions: Boolean = false
+ private val disposable = CompositeDisposable()
+ private val broadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ val action = intent.action
+ if (action != null && action == Intent.ACTION_SCREEN_OFF) {
+ if (PreferenceUtil.getInstance(this@MainActivity).lockScreen && MusicPlayerRemote.isPlaying) {
+ val activity = Intent(context, LockScreenActivity::class.java)
+ activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
+ ActivityCompat.startActivity(context, activity, null)
+ }
+ }
+ }
}
- override fun onCreate(savedInstanceState: Bundle?) {
+ override fun createContentView(): View {
+ return wrapSlidingMusicPanel(R.layout.activity_main_content)
+ }
+
+ override fun onCreate(
+ savedInstanceState: Bundle?
+ ) {
+ setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
- setTaskDescriptionColorAuto()
- hideStatusBar()
- updateTabs()
+ getBottomNavigationView().selectedItemId = PreferenceUtil.getInstance(this).lastPage
+ getBottomNavigationView().setOnNavigationItemSelectedListener {
+ PreferenceUtil.getInstance(this).lastPage = it.itemId
+ selectedFragment(it.itemId)
+ true
+ }
- setupNavigationController()
+ if (savedInstanceState == null) {
+ setMusicChooser(PreferenceUtil.getInstance(this).lastMusicChooser)
+ } else {
+ restoreCurrentFragment()
+ }
- WhatsNewFragment.showChangeLog(this)
+ checkShowChangelog()
+ AppRater.appLaunched(this)
}
- private fun setupNavigationController() {
- val navController = findNavController(R.id.fragment_container)
- val navInflater = navController.navInflater
- val navGraph = navInflater.inflate(R.navigation.main_graph)
+ private fun checkShowChangelog() {
+ try {
+ val pInfo = packageManager.getPackageInfo(packageName, 0)
+ val currentVersion = pInfo.versionCode
+ if (currentVersion != PreferenceUtil.getInstance(this).lastChangelogVersion) {
+ startActivityForResult(
+ Intent(this, WhatsNewActivity::class.java),
+ APP_INTRO_REQUEST
+ )
+ }
+ } catch (e: Throwable) {
+ e.printStackTrace()
+ }
- val categoryInfo: CategoryInfo = PreferenceUtil.libraryCategory.first { it.visible }
- if (categoryInfo.visible) {
- if (!navGraph.contains(PreferenceUtil.lastTab)) PreferenceUtil.lastTab =
- categoryInfo.category.id
- navGraph.setStartDestination(
- if (PreferenceUtil.rememberLastTab) {
- PreferenceUtil.lastTab.let {
- if (it == 0) {
- categoryInfo.category.id
- } else {
- it
- }
- }
- } else categoryInfo.category.id
- )
- }
- navController.graph = navGraph
- navigationView.setupWithNavController(navController)
- // Scroll Fragment to top
- navigationView.setOnItemReselectedListener {
- currentFragment(R.id.fragment_container).apply {
- if (this is IScrollHelper) {
- scrollToTop()
- }
- }
- }
- navController.addOnDestinationChangedListener { _, destination, _ ->
- if (destination.id == navGraph.startDestinationId) {
- currentFragment(R.id.fragment_container)?.enterTransition = null
- }
- when (destination.id) {
- R.id.action_home, R.id.action_song, R.id.action_album, R.id.action_artist, R.id.action_folder, R.id.action_playlist, R.id.action_genre, R.id.action_search -> {
- // Save the last tab
- if (PreferenceUtil.rememberLastTab) {
- saveTab(destination.id)
- }
- // Show Bottom Navigation Bar
- setBottomNavVisibility(visible = true, animate = true)
- }
- R.id.playing_queue_fragment -> {
- setBottomNavVisibility(visible = false, hideBottomSheet = true)
- }
- else -> setBottomNavVisibility(
- visible = false,
- animate = true
- ) // Hide Bottom Navigation Bar
+ }
+
+ override fun onResume() {
+ super.onResume()
+ val screenOnOff = IntentFilter()
+ screenOnOff.addAction(Intent.ACTION_SCREEN_OFF)
+ registerReceiver(broadcastReceiver, screenOnOff)
+
+ PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this)
+
+ if (intent.hasExtra("expand")) {
+ if (intent.getBooleanExtra("expand", false)) {
+ expandPanel()
+ intent.putExtra("expand", false)
}
}
}
- private fun saveTab(id: Int) {
- if (PreferenceUtil.libraryCategory.firstOrNull { it.category.id == id }?.visible == true) {
- PreferenceUtil.lastTab = id
+ override fun onDestroy() {
+ super.onDestroy()
+ disposable.clear()
+ unregisterReceiver(broadcastReceiver)
+ PreferenceUtil.getInstance(this).unregisterOnSharedPreferenceChangedListener(this)
+ }
+
+ private fun setCurrentFragment(fragment: Fragment, tag: String) {
+ if (tag != supportFragmentManager.findFragmentById(R.id.fragment_container)?.tag) {
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.fragment_container, fragment, tag).commit()
+ currentFragment = fragment as MainActivityFragmentCallbacks
}
}
- override fun onSupportNavigateUp(): Boolean =
- findNavController(R.id.fragment_container).navigateUp()
+ fun setDetailsFragments(fragment: Fragment, tag: String) {
+ supportFragmentManager.beginTransaction()
+ .add(R.id.fragment_container, fragment, tag)
+ .addToBackStack(tag)
+ .commit()
+ currentFragment = fragment as MainActivityFragmentCallbacks
+ }
- override fun onNewIntent(intent: Intent?) {
- super.onNewIntent(intent)
- val expand = intent?.extra(EXPAND_PANEL)?.value ?: false
- if (expand && PreferenceUtil.isExpandPanel) {
- fromNotification = true
- slidingPanel.bringToFront()
- expandPanel()
- intent?.removeExtra(EXPAND_PANEL)
+ private fun restoreCurrentFragment() {
+ currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as MainActivityFragmentCallbacks
+ }
+
+ private fun handlePlaybackIntent(intent: Intent?) {
+ if (intent == null) {
+ return
+ }
+ val uri = intent.data
+ val mimeType = intent.type
+ var handled = false
+ if (intent.action != null && intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH) {
+ val songs = SearchQueryHelper.getSongs(this, intent.extras!!)
+ if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) {
+ MusicPlayerRemote.openAndShuffleQueue(songs, true)
+ } else {
+ MusicPlayerRemote.openQueue(songs, 0, true)
+ }
+ handled = true
}
- }
- override fun onServiceConnected() {
- super.onServiceConnected()
- intent ?: return
- handlePlaybackIntent(intent)
- }
-
- private fun handlePlaybackIntent(intent: Intent) {
- lifecycleScope.launch(IO) {
- val uri: Uri? = intent.data
- val mimeType: String? = intent.type
- var handled = false
- if (intent.action != null &&
- intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
- ) {
- val songs: List = getSongs(intent.extras!!)
- if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) {
- MusicPlayerRemote.openAndShuffleQueue(songs, true)
- } else {
- MusicPlayerRemote.openQueue(songs, 0, true)
- }
+ if (uri != null && uri.toString().isNotEmpty()) {
+ MusicPlayerRemote.playFromUri(uri)
+ handled = true
+ } else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
+ val id = parseIdFromIntent(intent, "playlistId", "playlist").toInt()
+ if (id >= 0) {
+ val position = intent.getIntExtra("position", 0)
+ val songs = ArrayList(PlaylistSongsLoader.getPlaylistSongList(this, id))
+ MusicPlayerRemote.openQueue(songs, position, true)
handled = true
}
- if (uri != null && uri.toString().isNotEmpty()) {
- MusicPlayerRemote.playFromUri(this@MainActivity, uri)
+ } else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
+ val id = parseIdFromIntent(intent, "albumId", "album").toInt()
+ if (id >= 0) {
+ val position = intent.getIntExtra("position", 0)
+ MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).songs!!, position, true)
handled = true
- } else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
- val id = parseLongFromIntent(intent, "playlistId", "playlist")
- if (id >= 0L) {
- val position: Int = intent.getIntExtra("position", 0)
- val songs: List = PlaylistSongsLoader.getPlaylistSongList(get(), id)
- MusicPlayerRemote.openQueue(songs, position, true)
- handled = true
- }
- } else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
- val id = parseLongFromIntent(intent, "albumId", "album")
- if (id >= 0L) {
- val position: Int = intent.getIntExtra("position", 0)
- val songs = libraryViewModel.albumById(id).songs
- MusicPlayerRemote.openQueue(
- songs,
- position,
- true
- )
- handled = true
- }
- } else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
- val id = parseLongFromIntent(intent, "artistId", "artist")
- if (id >= 0L) {
- val position: Int = intent.getIntExtra("position", 0)
- val songs: List = libraryViewModel.artistById(id).songs
- MusicPlayerRemote.openQueue(
- songs,
- position,
- true
- )
- handled = true
- }
}
- if (handled) {
- setIntent(Intent())
+ } else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
+ val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
+ if (id >= 0) {
+ val position = intent.getIntExtra("position", 0)
+ MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).songs, position, true)
+ handled = true
}
}
+ if (handled) {
+ setIntent(Intent())
+ }
}
- private fun parseLongFromIntent(
- intent: Intent,
- longKey: String,
- stringKey: String,
- ): Long {
+ private fun parseIdFromIntent(intent: Intent, longKey: String, stringKey: String): Long {
var id = intent.getLongExtra(longKey, -1)
if (id < 0) {
val idString = intent.getStringExtra(stringKey)
if (idString != null) {
try {
- id = idString.toLong()
+ id = java.lang.Long.parseLong(idString)
} catch (e: NumberFormatException) {
- logE(e)
+ Log.e(TAG, e.message)
}
}
}
return id
}
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ when (requestCode) {
+ APP_INTRO_REQUEST -> {
+ blockRequestPermissions = false
+ if (!hasPermissions()) {
+ requestPermissions()
+ }
+ }
+ REQUEST_CODE_THEME, APP_USER_INFO_REQUEST -> postRecreate()
+ PURCHASE_REQUEST -> {
+ if (resultCode == RESULT_OK) {
+ //checkSetUpPro();
+ }
+ }
+ }
+
+ }
+
+ override fun handleBackPress(): Boolean {
+ return super.handleBackPress() || currentFragment.handleBackPress()
+ }
+
+ override fun onServiceConnected() {
+ super.onServiceConnected()
+ handlePlaybackIntent(intent)
+ }
+
+ override fun requestPermissions() {
+ if (!blockRequestPermissions) {
+ super.requestPermissions()
+ }
+ }
+
+ override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
+ if (key == PreferenceUtil.GENERAL_THEME || key == PreferenceUtil.BLACK_THEME || key == PreferenceUtil.ADAPTIVE_COLOR_APP || key == PreferenceUtil.DOMINANT_COLOR || key == PreferenceUtil.USER_NAME || key == PreferenceUtil.TOGGLE_FULL_SCREEN || key == PreferenceUtil.TOGGLE_VOLUME || key == PreferenceUtil.ROUND_CORNERS || key == PreferenceUtil.CAROUSEL_EFFECT || key == PreferenceUtil.NOW_PLAYING_SCREEN_ID || key == PreferenceUtil.TOGGLE_GENRE || key == PreferenceUtil.BANNER_IMAGE_PATH || key == PreferenceUtil.PROFILE_IMAGE_PATH || key == PreferenceUtil.CIRCULAR_ALBUM_ART || key == PreferenceUtil.KEEP_SCREEN_ON || key == PreferenceUtil.TOGGLE_SEPARATE_LINE || key == PreferenceUtil.ALBUM_GRID_STYLE || key == PreferenceUtil.ARTIST_GRID_STYLE || key == PreferenceUtil.TOGGLE_HOME_BANNER || key == PreferenceUtil.TOGGLE_ADD_CONTROLS || key == PreferenceUtil.ALBUM_COVER_STYLE || key == PreferenceUtil.HOME_ARTIST_GRID_STYLE || key == PreferenceUtil.ALBUM_COVER_TRANSFORM || key == PreferenceUtil.DESATURATED_COLOR || key == PreferenceUtil.TAB_TEXT_MODE || key == PreferenceUtil.LIBRARY_CATEGORIES) postRecreate()
+
+ }
+
+ private fun selectedFragment(itemId: Int) {
+ when (itemId) {
+ R.id.action_album,
+ R.id.action_artist,
+ R.id.action_playlist,
+ R.id.action_genre,
+ R.id.action_playing_queue,
+ R.id.action_song -> setCurrentFragment(LibraryFragment.newInstance(itemId), itemId.toString())
+ R.id.action_home -> setCurrentFragment(BannerHomeFragment.newInstance(), BannerHomeFragment.TAG)
+ else -> {
+ setCurrentFragment(BannerHomeFragment.newInstance(), BannerHomeFragment.TAG)
+ }
+ }
+ }
+
+ fun setMusicChooser(key: Int) {
+ PreferenceUtil.getInstance(this).lastMusicChooser = key
+ when (key) {
+ FOLDER -> setCurrentFragment(FoldersFragment.newInstance(this), FoldersFragment.TAG)
+ else -> selectedFragment(PreferenceUtil.getInstance(this).lastPage)
+ }
+ }
+
+ companion object {
+ const val APP_INTRO_REQUEST = 2323
+ const val HOME = 0
+ const val FOLDER = 1
+ const val LIBRARY = 2
+ private const val TAG = "MainActivity"
+ private const val APP_USER_INFO_REQUEST = 9003
+ private const val REQUEST_CODE_THEME = 9002
+ private const val PURCHASE_REQUEST = 101
+ }
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/PermissionActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/PermissionActivity.kt
deleted file mode 100644
index 5cb64cf93..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/PermissionActivity.kt
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
-package code.name.monkey.retromusic.activities
-
-import android.Manifest.permission.BLUETOOTH_CONNECT
-import android.content.Intent
-import android.content.pm.PackageManager
-import android.content.res.ColorStateList
-import android.os.Build
-import android.os.Bundle
-import android.provider.Settings
-import androidx.activity.OnBackPressedCallback
-import androidx.annotation.RequiresApi
-import androidx.core.app.ActivityCompat
-import androidx.core.net.toUri
-import androidx.core.text.parseAsHtml
-import androidx.core.view.isVisible
-import code.name.monkey.appthemehelper.util.VersionUtils
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
-import code.name.monkey.retromusic.databinding.ActivityPermissionBinding
-import code.name.monkey.retromusic.extensions.*
-
-class PermissionActivity : AbsMusicServiceActivity() {
- private lateinit var binding: ActivityPermissionBinding
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = ActivityPermissionBinding.inflate(layoutInflater)
- setContentView(binding.root)
- setStatusBarColorAuto()
- setTaskDescriptionColorAuto()
- setupTitle()
-
- binding.storagePermission.setButtonClick {
- requestPermissions()
- }
- if (VersionUtils.hasMarshmallow()) {
- binding.audioPermission.show()
- binding.audioPermission.setButtonClick {
- if (!hasAudioPermission()) {
- val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
- intent.data = ("package:" + applicationContext.packageName).toUri()
- startActivity(intent)
- }
- }
- }
-
- if (VersionUtils.hasS()) {
- binding.bluetoothPermission.show()
- binding.bluetoothPermission.setButtonClick {
- ActivityCompat.requestPermissions(
- this,
- arrayOf(BLUETOOTH_CONNECT),
- BLUETOOTH_PERMISSION_REQUEST
- )
- }
- } else {
- binding.audioPermission.setNumber("2")
- }
-
- binding.finish.accentBackgroundColor()
- binding.finish.setOnClickListener {
- if (hasPermissions()) {
- startActivity(
- Intent(this, MainActivity::class.java).addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK or
- Intent.FLAG_ACTIVITY_CLEAR_TASK
- )
- )
- finish()
- }
- }
- onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
- override fun handleOnBackPressed() {
- finishAffinity()
- remove()
- }
- })
- }
-
- private fun setupTitle() {
- val appName =
- getString(
- R.string.message_welcome,
- "Metro "
- )
- .parseAsHtml()
- binding.appNameText.text = appName
- }
-
- override fun onResume() {
- super.onResume()
- binding.finish.isEnabled = hasStoragePermission()
- if (hasStoragePermission()) {
- binding.storagePermission.checkImage.isVisible = true
- binding.storagePermission.checkImage.imageTintList =
- ColorStateList.valueOf(accentColor())
- }
- if (VersionUtils.hasMarshmallow()) {
- if (hasAudioPermission()) {
- binding.audioPermission.checkImage.isVisible = true
- binding.audioPermission.checkImage.imageTintList =
- ColorStateList.valueOf(accentColor())
- }
- }
- if (VersionUtils.hasS()) {
- if (hasBluetoothPermission()) {
- binding.bluetoothPermission.checkImage.isVisible = true
- binding.bluetoothPermission.checkImage.imageTintList =
- ColorStateList.valueOf(accentColor())
- }
- }
- }
-
- private fun hasStoragePermission(): Boolean {
- return hasPermissions()
- }
-
- @RequiresApi(Build.VERSION_CODES.S)
- private fun hasBluetoothPermission(): Boolean {
- return ActivityCompat.checkSelfPermission(
- this,
- BLUETOOTH_CONNECT
- ) == PackageManager.PERMISSION_GRANTED
- }
-
- @RequiresApi(Build.VERSION_CODES.M)
- private fun hasAudioPermission(): Boolean {
- return Settings.System.canWrite(this)
- }
-}
diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/queue/PlayingQueueFragment.kt b/app/src/main/java/code/name/monkey/retromusic/activities/PlayingQueueActivity.kt
similarity index 52%
rename from app/src/main/java/code/name/monkey/retromusic/fragments/queue/PlayingQueueFragment.kt
rename to app/src/main/java/code/name/monkey/retromusic/activities/PlayingQueueActivity.kt
index 0526ade15..194bb26b3 100644
--- a/app/src/main/java/code/name/monkey/retromusic/fragments/queue/PlayingQueueFragment.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/PlayingQueueActivity.kt
@@ -1,47 +1,29 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
-package code.name.monkey.retromusic.fragments.queue
+package code.name.monkey.retromusic.activities
import android.content.res.ColorStateList
import android.os.Bundle
-import android.view.View
-import androidx.navigation.fragment.findNavController
+import android.view.MenuItem
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+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.activities.MainActivity
+import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
-import code.name.monkey.retromusic.databinding.FragmentPlayingQueueBinding
-import code.name.monkey.retromusic.extensions.accentColor
-import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
+import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.MusicUtil
-import code.name.monkey.retromusic.util.ThemedFastScroller
+import code.name.monkey.retromusic.util.ViewUtil
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
+import kotlinx.android.synthetic.main.activity_playing_queue.*
-class PlayingQueueFragment : AbsMusicServiceFragment(R.layout.fragment_playing_queue) {
+open class PlayingQueueActivity : AbsMusicServiceActivity() {
- private var _binding: FragmentPlayingQueueBinding? = null
- private val binding get() = _binding!!
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
private var recyclerViewSwipeManager: RecyclerViewSwipeManager? = null
@@ -49,29 +31,37 @@ class PlayingQueueFragment : AbsMusicServiceFragment(R.layout.fragment_playing_q
private var playingQueueAdapter: PlayingQueueAdapter? = null
private lateinit var linearLayoutManager: LinearLayoutManager
- val mainActivity: MainActivity
- get() = activity as MainActivity
-
private fun getUpNextAndQueueTime(): String {
val duration = MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.position)
- return MusicUtil.buildInfoString(
- resources.getString(R.string.up_next),
- MusicUtil.getReadableDurationString(duration)
- )
+ return MusicUtil.buildInfoString(resources.getString(R.string.up_next), MusicUtil.getReadableDurationString(duration))
}
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- _binding = FragmentPlayingQueueBinding.bind(view)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setDrawUnderStatusBar()
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_playing_queue)
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setLightNavigationBar(true)
setupToolbar()
setUpRecyclerView()
- binding.clearQueue.setOnClickListener {
+ clearQueue.setOnClickListener {
MusicPlayerRemote.clearQueue()
}
checkForPadding()
- mainActivity.collapsePanel()
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ return when (item.itemId) {
+ android.R.id.home -> {
+ onBackPressed()
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
}
private fun setUpRecyclerView() {
@@ -79,47 +69,48 @@ class PlayingQueueFragment : AbsMusicServiceFragment(R.layout.fragment_playing_q
recyclerViewDragDropManager = RecyclerViewDragDropManager()
recyclerViewSwipeManager = RecyclerViewSwipeManager()
+ val animator = DraggableItemAnimator()
+ animator.supportsChangeAnimations = false
+
playingQueueAdapter = PlayingQueueAdapter(
- requireActivity(),
- MusicPlayerRemote.playingQueue.toMutableList(),
- MusicPlayerRemote.position,
- R.layout.item_queue
+ this,
+ MusicPlayerRemote.playingQueue,
+ MusicPlayerRemote.position,
+ R.layout.item_queue
)
wrappedAdapter = recyclerViewDragDropManager?.createWrappedAdapter(playingQueueAdapter!!)
wrappedAdapter = wrappedAdapter?.let { recyclerViewSwipeManager?.createWrappedAdapter(it) }
- linearLayoutManager = LinearLayoutManager(requireContext())
+ linearLayoutManager = LinearLayoutManager(this)
-
- binding.recyclerView.apply {
- layoutManager = linearLayoutManager
- adapter = wrappedAdapter
- itemAnimator = DraggableItemAnimator()
- recyclerViewTouchActionGuardManager?.attachRecyclerView(this)
- recyclerViewDragDropManager?.attachRecyclerView(this)
- recyclerViewSwipeManager?.attachRecyclerView(this)
- }
+ recyclerView.layoutManager = linearLayoutManager
+ recyclerView.adapter = wrappedAdapter
+ recyclerView.itemAnimator = animator
+ recyclerViewTouchActionGuardManager?.attachRecyclerView(recyclerView)
+ recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
+ recyclerViewSwipeManager?.attachRecyclerView(recyclerView)
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
- binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > 0) {
- binding.clearQueue.shrink()
+ clearQueue.shrink()
} else if (dy < 0) {
- binding.clearQueue.extend()
+ clearQueue.extend()
}
}
})
- ThemedFastScroller.create(binding.recyclerView)
+ ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
}
private fun checkForPadding() {
+
}
override fun onQueueChanged() {
if (MusicPlayerRemote.playingQueue.isEmpty()) {
- findNavController().navigateUp()
+ finish()
return
}
checkForPadding()
@@ -133,7 +124,7 @@ class PlayingQueueFragment : AbsMusicServiceFragment(R.layout.fragment_playing_q
}
private fun updateCurrentSong() {
- binding.appBarLayout.toolbar.subtitle = getUpNextAndQueueTime()
+ playerQueueSubHeader.text = getUpNextAndQueueTime()
}
override fun onPlayingMetaChanged() {
@@ -143,15 +134,16 @@ class PlayingQueueFragment : AbsMusicServiceFragment(R.layout.fragment_playing_q
private fun updateQueuePosition() {
playingQueueAdapter?.setCurrent(MusicPlayerRemote.position)
resetToCurrentPosition()
- binding.appBarLayout.toolbar.subtitle = getUpNextAndQueueTime()
+ playerQueueSubHeader.text = getUpNextAndQueueTime()
}
private fun updateQueue() {
playingQueueAdapter?.swapDataSet(MusicPlayerRemote.playingQueue, MusicPlayerRemote.position)
+ resetToCurrentPosition()
}
private fun resetToCurrentPosition() {
- binding.recyclerView.stopScroll()
+ recyclerView.stopScroll()
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
@@ -177,33 +169,26 @@ class PlayingQueueFragment : AbsMusicServiceFragment(R.layout.fragment_playing_q
}
playingQueueAdapter = null
super.onDestroy()
- if (MusicPlayerRemote.playingQueue.isNotEmpty())
- mainActivity.expandPanel()
}
private fun setupToolbar() {
- binding.appBarLayout.toolbar.subtitle = getUpNextAndQueueTime()
- binding.appBarLayout.toolbar.isTitleCentered = false
- binding.clearQueue.backgroundTintList = ColorStateList.valueOf(accentColor())
+ playerQueueSubHeader.text = getUpNextAndQueueTime()
+ playerQueueSubHeader.setTextColor(ThemeStore.accentColor(this))
+
+ applyToolbar(toolbar)
+ clearQueue.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(
- MaterialValueHelper.getPrimaryTextColor(
- requireContext(),
- ColorUtil.isColorLight(accentColor())
- )
+ MaterialValueHelper.getPrimaryTextColor(
+ this,
+ ColorUtil.isColorLight(
+ ThemeStore.accentColor(
+ this
+ )
+ )
+ )
).apply {
- binding.clearQueue.setTextColor(this)
- binding.clearQueue.iconTint = this
- }
- binding.appBarLayout.pinWhenScrolled()
- binding.appBarLayout.toolbar.apply {
- setNavigationOnClickListener {
- findNavController().navigateUp()
- }
- setTitle(R.string.now_playing_queue)
- setTitleTextAppearance(context, R.style.ToolbarTextAppearanceNormal)
- setNavigationIcon(R.drawable.ic_arrow_back)
- ToolbarContentTintHelper.colorBackButton(this)
+ clearQueue.setTextColor(this)
+ clearQueue.iconTint = this
}
}
}
-
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt
new file mode 100644
index 000000000..5d1361ce8
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt
@@ -0,0 +1,232 @@
+package code.name.monkey.retromusic.activities
+
+import android.os.Bundle
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import code.name.monkey.appthemehelper.util.ATHUtil
+import code.name.monkey.retromusic.App
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
+import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter
+import code.name.monkey.retromusic.adapter.song.PlaylistSongAdapter
+import code.name.monkey.retromusic.adapter.song.SongAdapter
+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.model.AbsCustomPlaylist
+import code.name.monkey.retromusic.model.Playlist
+import code.name.monkey.retromusic.model.Song
+import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsPresenter
+import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsView
+import code.name.monkey.retromusic.util.DensityUtil
+import code.name.monkey.retromusic.util.PlaylistsUtil
+import code.name.monkey.retromusic.util.RetroColorUtil
+import code.name.monkey.retromusic.util.ViewUtil
+import com.afollestad.materialcab.MaterialCab
+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 kotlinx.android.synthetic.main.activity_playlist_detail.*
+import javax.inject.Inject
+
+class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, PlaylistSongsView {
+
+ @Inject
+ lateinit var playlistSongsPresenter: PlaylistSongsPresenter
+
+ private lateinit var playlist: Playlist
+ private var cab: MaterialCab? = null
+ private lateinit var adapter: SongAdapter
+ private var wrappedAdapter: RecyclerView.Adapter<*>? = null
+ private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setDrawUnderStatusBar()
+ super.onCreate(savedInstanceState)
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setLightNavigationBar(true)
+ toggleBottomNavigationView(true)
+
+ App.musicComponent.inject(this)
+ playlistSongsPresenter.attachView(this)
+
+ if (intent.extras != null) {
+ playlist = intent.extras!!.getParcelable(EXTRA_PLAYLIST)!!
+ } else {
+ finish()
+ }
+
+ setUpToolBar()
+ setUpRecyclerView()
+ }
+
+ override fun createContentView(): View {
+ return wrapSlidingMusicPanel(R.layout.activity_playlist_detail)
+ }
+
+ private fun setUpRecyclerView() {
+ ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ if (playlist is AbsCustomPlaylist) {
+ adapter = PlaylistSongAdapter(this, ArrayList(), R.layout.item_list, false, this)
+ recyclerView.adapter = adapter
+ } else {
+ recyclerViewDragDropManager = RecyclerViewDragDropManager()
+ val animator = RefactoredDefaultItemAnimator()
+ adapter = OrderablePlaylistSongAdapter(this,
+ ArrayList(),
+ R.layout.item_list,
+ false,
+ this,
+ object : OrderablePlaylistSongAdapter.OnMoveItemListener {
+ override fun onMoveItem(fromPosition: Int, toPosition: Int) {
+ if (PlaylistsUtil.moveItem(this@PlaylistDetailActivity, playlist.id, fromPosition, toPosition)) {
+ val song = adapter.dataSet.removeAt(fromPosition)
+ adapter.dataSet.add(toPosition, song)
+ adapter.notifyItemMoved(fromPosition, toPosition)
+ }
+ }
+ })
+ wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter)
+
+ recyclerView.adapter = wrappedAdapter
+ recyclerView.itemAnimator = animator
+
+ recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
+ }
+ adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
+ override fun onChanged() {
+ super.onChanged()
+ checkIsEmpty()
+ }
+ })
+ }
+
+ override fun onResume() {
+ super.onResume()
+ playlistSongsPresenter.loadPlaylistSongs(playlist)
+ }
+
+ private fun setUpToolBar() {
+ toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
+ setSupportActionBar(toolbar)
+ title = playlist.name
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(
+ if (playlist is AbsCustomPlaylist) R.menu.menu_smart_playlist_detail
+ else R.menu.menu_playlist_detail, menu
+ )
+ return super.onCreateOptionsMenu(menu)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ android.R.id.home -> {
+ onBackPressed()
+ return true
+ }
+ }
+ return PlaylistMenuHelper.handleMenuClick(this, playlist, item)
+ }
+
+ override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
+ if (cab != null && cab!!.isActive) {
+ cab!!.finish()
+ }
+ cab = MaterialCab(this, R.id.cab_stub).setMenu(menuRes).setCloseDrawableRes(R.drawable.ic_close_white_24dp).setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorSurface))).start(callback)
+ return cab!!
+ }
+
+ override fun onBackPressed() {
+ if (cab != null && cab!!.isActive) {
+ cab!!.finish()
+ } else {
+ recyclerView!!.stopScroll()
+ super.onBackPressed()
+ }
+ }
+
+ override fun onMediaStoreChanged() {
+ super.onMediaStoreChanged()
+ if (playlist !is AbsCustomPlaylist) {
+ // Playlist deleted
+ if (!PlaylistsUtil.doesPlaylistExist(this, playlist.id)) {
+ finish()
+ return
+ }
+ // Playlist renamed
+ val playlistName = PlaylistsUtil.getNameForPlaylist(this, playlist.id.toLong())
+ if (playlistName != playlist.name) {
+ playlist = PlaylistLoader.getPlaylist(this, playlist.id)
+ setToolbarTitle(playlist.name)
+ }
+ }
+ playlistSongsPresenter.loadPlaylistSongs(playlist)
+ }
+
+ private fun setToolbarTitle(title: String) {
+ supportActionBar!!.title = title
+ }
+
+ private fun checkForPadding() {
+ val height = DensityUtil.dip2px(this, 52f)
+ recyclerView.setPadding(0, 0, 0, (height))
+ }
+
+ private fun checkIsEmpty() {
+ checkForPadding()
+ emptyEmoji.text = getEmojiByUnicode(0x1F631)
+ empty.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
+ emptyText.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
+ }
+
+ private fun getEmojiByUnicode(unicode: Int): String {
+ return String(Character.toChars(unicode))
+ }
+
+ public override fun onPause() {
+ if (recyclerViewDragDropManager != null) {
+ recyclerViewDragDropManager!!.cancelDrag()
+ }
+ super.onPause()
+ }
+
+ override fun onDestroy() {
+ if (recyclerViewDragDropManager != null) {
+ recyclerViewDragDropManager!!.release()
+ recyclerViewDragDropManager = null
+ }
+
+ if (recyclerView != null) {
+ recyclerView!!.itemAnimator = null
+ recyclerView!!.adapter = null
+ }
+
+ if (wrappedAdapter != null) {
+ WrapperAdapterUtils.releaseAll(wrappedAdapter)
+ wrappedAdapter = null
+ }
+ super.onDestroy()
+ playlistSongsPresenter.detachView()
+ }
+
+ override fun showEmptyView() {
+ empty.visibility = View.VISIBLE
+ emptyText.visibility = View.VISIBLE
+ }
+
+ override fun songs(songs: ArrayList) {
+ adapter.swapDataSet(songs)
+ }
+
+ companion object {
+ var EXTRA_PLAYLIST = "extra_playlist"
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt
new file mode 100644
index 000000000..419f81df3
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt
@@ -0,0 +1,155 @@
+package code.name.monkey.retromusic.activities
+
+import android.content.Intent
+import android.os.AsyncTask
+import android.os.Bundle
+import android.util.Log
+import android.view.MenuItem
+import android.widget.Toast
+import code.name.monkey.appthemehelper.util.MaterialUtil
+import code.name.monkey.retromusic.App
+import code.name.monkey.retromusic.BuildConfig
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsBaseActivity
+import code.name.monkey.retromusic.extensions.applyToolbar
+import com.anjlab.android.iab.v3.BillingProcessor
+import com.anjlab.android.iab.v3.TransactionDetails
+import kotlinx.android.synthetic.main.activity_pro_version.*
+import java.lang.ref.WeakReference
+
+class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
+
+ private lateinit var billingProcessor: BillingProcessor
+ private var restorePurchaseAsyncTask: AsyncTask<*, *, *>? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_pro_version)
+ setDrawUnderStatusBar()
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setLightNavigationBar(true)
+
+ applyToolbar(toolbar)
+
+ restoreButton.isEnabled = false
+ purchaseButton.isEnabled = false
+
+ billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this)
+
+ MaterialUtil.setTint(restoreButton, false)
+ MaterialUtil.setTint(purchaseButton, true)
+
+ restoreButton.setOnClickListener {
+ if (restorePurchaseAsyncTask == null || restorePurchaseAsyncTask!!.status != AsyncTask.Status.RUNNING) {
+ restorePurchase()
+ }
+
+ }
+ purchaseButton.setOnClickListener {
+ billingProcessor.purchase(this@PurchaseActivity, App.PRO_VERSION_PRODUCT_ID)
+ }
+ }
+
+ private fun restorePurchase() {
+ if (restorePurchaseAsyncTask != null) {
+ restorePurchaseAsyncTask!!.cancel(false)
+ }
+ restorePurchaseAsyncTask = RestorePurchaseAsyncTask(this).execute()
+ }
+
+ override fun onProductPurchased(productId: String, details: TransactionDetails?) {
+ Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show()
+ setResult(RESULT_OK)
+ }
+
+ override fun onPurchaseHistoryRestored() {
+ if (App.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 fun onBillingError(errorCode: Int, error: Throwable?) {
+ Log.e(TAG, "Billing error: code = $errorCode", error)
+ }
+
+ override fun onBillingInitialized() {
+ restoreButton.isEnabled = true
+ purchaseButton.isEnabled = true
+ }
+
+ public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (!billingProcessor.handleActivityResult(requestCode, resultCode, data)) {
+ super.onActivityResult(requestCode, resultCode, data)
+ }
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ android.R.id.home -> finish()
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+ override fun onDestroy() {
+ billingProcessor.release()
+ super.onDestroy()
+ }
+
+ private class RestorePurchaseAsyncTask internal constructor(purchaseActivity: PurchaseActivity) : AsyncTask() {
+
+ private val buyActivityWeakReference: WeakReference = WeakReference(
+ purchaseActivity
+ )
+
+ override fun onPreExecute() {
+ super.onPreExecute()
+ val purchaseActivity = buyActivityWeakReference.get()
+ if (purchaseActivity != null) {
+ Toast.makeText(purchaseActivity, R.string.restoring_purchase, Toast.LENGTH_SHORT)
+ .show()
+ } else {
+ cancel(false)
+ }
+ }
+
+ override fun doInBackground(vararg params: Void): Boolean? {
+ val purchaseActivity = buyActivityWeakReference.get()
+ if (purchaseActivity != null) {
+ return purchaseActivity.billingProcessor.loadOwnedPurchasesFromGoogle()
+ }
+ cancel(false)
+ return null
+ }
+
+ override fun onPostExecute(b: Boolean?) {
+ super.onPostExecute(b)
+ val 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()
+ }
+ }
+ }
+
+ companion object {
+ private const val TAG: String = "PurchaseActivity"
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/SearchActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/SearchActivity.kt
new file mode 100644
index 000000000..082adc6b5
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/SearchActivity.kt
@@ -0,0 +1,223 @@
+package code.name.monkey.retromusic.activities
+
+import android.app.Activity
+import android.app.Service
+import android.content.ActivityNotFoundException
+import android.content.Intent
+import android.content.res.ColorStateList
+import android.os.Bundle
+import android.speech.RecognizerIntent
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import android.widget.TextView.BufferType
+import android.widget.Toast
+import androidx.appcompat.widget.SearchView.OnQueryTextListener
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import androidx.transition.TransitionManager
+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.retromusic.App
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
+import code.name.monkey.retromusic.adapter.SearchAdapter
+import code.name.monkey.retromusic.mvp.presenter.SearchPresenter
+import code.name.monkey.retromusic.mvp.presenter.SearchView
+import code.name.monkey.retromusic.util.RetroUtil
+import com.google.android.material.textfield.TextInputEditText
+import kotlinx.android.synthetic.main.activity_search.*
+import java.util.*
+import javax.inject.Inject
+import kotlin.collections.ArrayList
+
+class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatcher, SearchView {
+ @Inject
+ lateinit var searchPresenter: SearchPresenter
+
+ private var searchAdapter: SearchAdapter? = null
+ private var query: String? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setDrawUnderStatusBar()
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_search)
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setLightNavigationBar(true)
+
+ App.musicComponent.inject(this)
+ searchPresenter.attachView(this)
+
+ setupRecyclerView()
+ setUpToolBar()
+ setupSearchView()
+
+ if (intent.getBooleanExtra(EXTRA_SHOW_MIC, false)) {
+ startMicSearch()
+ }
+
+ back.setOnClickListener { onBackPressed() }
+ voiceSearch.setOnClickListener { startMicSearch() }
+ clearText.setOnClickListener { searchView.clearText() }
+ searchContainer.backgroundTintList = ColorStateList.valueOf(ATHUtil.resolveColor(this, R.attr.colorSurface))
+
+ keyboardPopup.setOnClickListener {
+ val inputManager = getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
+ inputManager.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT)
+ }
+
+ keyboardPopup.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
+ ColorStateList.valueOf(
+ MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.accentColor(this)))
+ ).apply {
+ keyboardPopup.setTextColor(this)
+ keyboardPopup.iconTint = this
+ }
+ if (savedInstanceState != null) {
+ query = savedInstanceState.getString(QUERY)
+ }
+
+ }
+
+ private fun setupRecyclerView() {
+ searchAdapter = SearchAdapter(this, emptyList())
+ searchAdapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
+ override fun onChanged() {
+ super.onChanged()
+ empty.visibility = if (searchAdapter!!.itemCount < 1) View.VISIBLE else View.GONE
+ }
+ })
+ recyclerView.apply {
+ layoutManager = LinearLayoutManager(this@SearchActivity)
+ adapter = searchAdapter
+ }
+ recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+ super.onScrolled(recyclerView, dx, dy)
+ if (dy > 0) {
+ keyboardPopup.shrink()
+ } else if (dy < 0) {
+ keyboardPopup.extend()
+ }
+ }
+ })
+ }
+
+ private fun setupSearchView() {
+ searchView.addTextChangedListener(this)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ searchPresenter.detachView()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putString(QUERY, query)
+ }
+
+ private fun setUpToolBar() {
+ title = null
+ }
+
+ private fun search(query: String) {
+ this.query = query
+ TransitionManager.beginDelayedTransition(appBarLayout)
+ voiceSearch.visibility = if (query.isNotEmpty()) View.GONE else View.VISIBLE
+ clearText.visibility = if (query.isNotEmpty()) View.VISIBLE else View.GONE
+ searchPresenter.search(query)
+ }
+
+ override fun onMediaStoreChanged() {
+ super.onMediaStoreChanged()
+ query?.let { search(it) }
+ }
+
+ override fun onQueryTextSubmit(query: String): Boolean {
+ hideSoftKeyboard()
+ return false
+ }
+
+ override fun onQueryTextChange(newText: String): Boolean {
+ search(newText)
+ return false
+ }
+
+ private fun hideSoftKeyboard() {
+ RetroUtil.hideSoftKeyboard(this@SearchActivity)
+ if (searchView != null) {
+ searchView.clearFocus()
+ }
+ }
+
+ override fun showEmptyView() {
+ searchAdapter?.swapDataSet(ArrayList())
+ }
+
+ override fun showData(data: MutableList) {
+ searchAdapter?.swapDataSet(data)
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ when (requestCode) {
+ REQ_CODE_SPEECH_INPUT -> {
+ if (resultCode == Activity.RESULT_OK && null != data) {
+ val result: ArrayList? = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
+ query = result?.get(0)
+ searchView.setText(query, BufferType.EDITABLE)
+ searchPresenter.search(query!!)
+ }
+ }
+ }
+ }
+
+ private fun startMicSearch() {
+ val intent = 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 (e: ActivityNotFoundException) {
+ e.printStackTrace()
+ Toast.makeText(this, getString(R.string.speech_not_supported), Toast.LENGTH_SHORT)
+ .show()
+ }
+
+ }
+
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+
+ }
+
+ override fun onTextChanged(newText: CharSequence, start: Int, before: Int, count: Int) {
+ search(newText.toString())
+ }
+
+ override fun afterTextChanged(s: Editable) {
+
+ }
+
+ companion object {
+ val TAG: String = SearchActivity::class.java.simpleName
+
+ const val EXTRA_SHOW_MIC = "extra_show_mic"
+ const val QUERY: String = "query"
+
+ private const val REQ_CODE_SPEECH_INPUT = 9002
+ }
+}
+
+fun TextInputEditText.clearText() {
+ text = null
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/SettingsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/SettingsActivity.kt
new file mode 100755
index 000000000..b11287322
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/SettingsActivity.kt
@@ -0,0 +1,82 @@
+package code.name.monkey.retromusic.activities
+
+import android.os.Bundle
+import android.view.MenuItem
+import androidx.annotation.StringRes
+import androidx.fragment.app.Fragment
+import androidx.transition.TransitionManager
+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.activities.base.AbsBaseActivity
+import code.name.monkey.retromusic.fragments.settings.MainSettingsFragment
+import kotlinx.android.synthetic.main.activity_settings.*
+
+class SettingsActivity : AbsBaseActivity() {
+
+ private val fragmentManager = supportFragmentManager
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setDrawUnderStatusBar()
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_settings)
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setLightNavigationBar(true)
+
+ setupToolbar()
+
+ if (savedInstanceState == null) {
+ fragmentManager.beginTransaction().replace(R.id.contentFrame, MainSettingsFragment()).commit()
+ }
+ }
+
+ private fun setupToolbar() {
+ setTitle(R.string.action_settings)
+ toolbar.apply {
+ setBackgroundColor(ATHUtil.resolveColor(this@SettingsActivity, R.attr.colorSurface))
+ setNavigationOnClickListener { onBackPressed() }
+ ToolbarContentTintHelper.colorBackButton(toolbar)
+ }
+ setSupportActionBar(toolbar)
+ }
+
+ fun setupFragment(fragment: Fragment, @StringRes titleName: Int) {
+ val fragmentTransaction = fragmentManager
+ .beginTransaction()
+ .setCustomAnimations(R.anim.sliding_in_left, R.anim.sliding_out_right, android.R.anim.slide_in_left, android.R.anim.slide_out_right)
+
+ if (detailContentFrame == null) {
+ fragmentTransaction.replace(R.id.contentFrame, fragment, fragment.tag)
+ fragmentTransaction.addToBackStack(null)
+ fragmentTransaction.commit()
+ } else {
+ fragmentTransaction.replace(R.id.detailContentFrame, fragment, fragment.tag)
+ fragmentTransaction.commit()
+ }
+
+ TransitionManager.beginDelayedTransition(appBarLayout)
+ setTitle(titleName)
+ }
+
+ override fun onBackPressed() {
+ if (fragmentManager.backStackEntryCount == 0) {
+ super.onBackPressed()
+ } else {
+ setTitle(R.string.action_settings)
+ fragmentManager.popBackStack()
+ }
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ onBackPressed()
+ return true
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+ companion object {
+ const val TAG: String = "SettingsActivity"
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/ShareInstagramStory.kt b/app/src/main/java/code/name/monkey/retromusic/activities/ShareInstagramStory.kt
deleted file mode 100644
index 546c9d794..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/ShareInstagramStory.kt
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
-package code.name.monkey.retromusic.activities
-
-import android.content.res.ColorStateList
-import android.graphics.Bitmap
-import android.graphics.Color
-import android.graphics.drawable.GradientDrawable
-import android.os.Bundle
-import android.provider.MediaStore.Images.Media
-import android.view.MenuItem
-import androidx.core.net.toUri
-import androidx.core.os.BundleCompat
-import androidx.core.view.drawToBitmap
-import code.name.monkey.appthemehelper.util.ColorUtil
-import code.name.monkey.appthemehelper.util.MaterialValueHelper
-import code.name.monkey.retromusic.activities.base.AbsThemeActivity
-import code.name.monkey.retromusic.databinding.ActivityShareInstagramBinding
-import code.name.monkey.retromusic.extensions.accentColor
-import code.name.monkey.retromusic.extensions.setStatusBarColor
-import code.name.monkey.retromusic.glide.RetroGlideExtension
-import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
-import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions
-import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
-import code.name.monkey.retromusic.model.Song
-import code.name.monkey.retromusic.util.Share
-import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
-import com.bumptech.glide.Glide
-
-/**
- * Created by hemanths on 2020-02-02.
- */
-
-class ShareInstagramStory : AbsThemeActivity() {
-
- private lateinit var binding: ActivityShareInstagramBinding
-
- companion object {
- const val EXTRA_SONG = "extra_song"
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == android.R.id.home) {
- onBackPressedDispatcher.onBackPressed()
- return true
- }
- return super.onOptionsItemSelected(item)
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = ActivityShareInstagramBinding.inflate(layoutInflater)
- setContentView(binding.root)
- setStatusBarColor(Color.TRANSPARENT)
-
- binding.toolbar.setBackgroundColor(Color.TRANSPARENT)
- setSupportActionBar(binding.toolbar)
-
- val song = intent.extras?.let { BundleCompat.getParcelable(it, EXTRA_SONG, Song::class.java) }
- song?.let { songFinal ->
- Glide.with(this)
- .asBitmapPalette()
- .songCoverOptions(songFinal)
- .load(RetroGlideExtension.getSongModel(songFinal))
- .into(object : RetroMusicColoredTarget(binding.image) {
- override fun onColorReady(colors: MediaNotificationProcessor) {
- setColors(colors.backgroundColor)
- }
- })
-
- binding.shareTitle.text = songFinal.title
- binding.shareText.text = songFinal.artistName
- binding.shareButton.setOnClickListener {
- val path: String = Media.insertImage(
- contentResolver,
- binding.mainContent.drawToBitmap(Bitmap.Config.ARGB_8888),
- "Design", null
- )
- Share.shareStoryToSocial(
- this@ShareInstagramStory,
- path.toUri()
- )
- }
- }
- binding.shareButton.setTextColor(
- MaterialValueHelper.getPrimaryTextColor(
- this,
- ColorUtil.isColorLight(accentColor())
- )
- )
- binding.shareButton.backgroundTintList =
- ColorStateList.valueOf(accentColor())
- }
-
- private fun setColors(color: Int) {
- binding.mainContent.background =
- GradientDrawable(
- GradientDrawable.Orientation.TOP_BOTTOM,
- intArrayOf(color, Color.BLACK)
- )
- }
-}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt
new file mode 100644
index 000000000..0f27363ea
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt
@@ -0,0 +1,247 @@
+package code.name.monkey.retromusic.activities
+
+import android.content.Intent
+import android.graphics.Paint
+import android.os.AsyncTask
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import android.widget.Toast
+import androidx.annotation.LayoutRes
+import androidx.appcompat.widget.AppCompatImageView
+import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+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.BuildConfig
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsBaseActivity
+import code.name.monkey.retromusic.extensions.applyToolbar
+import com.anjlab.android.iab.v3.BillingProcessor
+import com.anjlab.android.iab.v3.SkuDetails
+import com.anjlab.android.iab.v3.TransactionDetails
+import kotlinx.android.synthetic.main.activity_donation.*
+import java.lang.ref.WeakReference
+import java.util.*
+
+class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
+
+ companion object {
+ val TAG: String = SupportDevelopmentActivity::class.java.simpleName
+ const val DONATION_PRODUCT_IDS = R.array.donation_ids
+ private const val TEZ_REQUEST_CODE = 123
+ }
+
+ var billingProcessor: BillingProcessor? = null
+ private var skuDetailsLoadAsyncTask: AsyncTask<*, *, *>? = null
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ onBackPressed()
+ return true
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+ fun donate(i: Int) {
+ val ids = resources.getStringArray(DONATION_PRODUCT_IDS)
+ billingProcessor!!.purchase(this, ids[i])
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_donation)
+
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setLightNavigationBar(true)
+
+ setupToolbar()
+
+ billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this)
+ TintHelper.setTint(progress, ThemeStore.accentColor(this))
+ donation.setTextColor(ThemeStore.accentColor(this))
+ }
+
+ private fun setupToolbar() {
+ applyToolbar(toolbar)
+ }
+
+ override fun onBillingInitialized() {
+ loadSkuDetails()
+ }
+
+ private fun loadSkuDetails() {
+ if (skuDetailsLoadAsyncTask != null) {
+ skuDetailsLoadAsyncTask!!.cancel(false)
+ }
+ skuDetailsLoadAsyncTask = SkuDetailsLoadAsyncTask(this).execute()
+
+ }
+
+ override fun onProductPurchased(productId: String, details: TransactionDetails?) {
+ //loadSkuDetails();
+ Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show()
+ }
+
+ override fun onBillingError(errorCode: Int, error: Throwable?) {
+ Log.e(TAG, "Billing error: code = $errorCode", error)
+ }
+
+ override fun onPurchaseHistoryRestored() {
+ //loadSkuDetails();
+ Toast.makeText(this, R.string.restored_previous_purchases, Toast.LENGTH_SHORT).show()
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (!billingProcessor!!.handleActivityResult(requestCode, resultCode, data)) {
+ super.onActivityResult(requestCode, resultCode, data)
+ }
+ if (requestCode == TEZ_REQUEST_CODE) {
+ // Process based on the data in response.
+ Log.d("result", data!!.getStringExtra("Status"))
+ }
+ }
+
+ override fun onDestroy() {
+ if (billingProcessor != null) {
+ billingProcessor!!.release()
+ }
+ if (skuDetailsLoadAsyncTask != null) {
+ skuDetailsLoadAsyncTask!!.cancel(true)
+ }
+ super.onDestroy()
+ }
+}
+
+private class SkuDetailsLoadAsyncTask internal constructor(supportDevelopmentActivity: SupportDevelopmentActivity) : AsyncTask>() {
+ private val weakReference: WeakReference = WeakReference(
+ supportDevelopmentActivity
+ )
+
+ override fun onPreExecute() {
+ super.onPreExecute()
+ val supportDevelopmentActivity = weakReference.get() ?: return
+
+ supportDevelopmentActivity.progressContainer.visibility = View.VISIBLE
+ supportDevelopmentActivity.recyclerView.visibility = View.GONE
+ }
+
+ override fun doInBackground(vararg params: Void): List? {
+ val dialog = weakReference.get()
+ if (dialog != null) {
+ val ids = dialog.resources.getStringArray(SupportDevelopmentActivity.DONATION_PRODUCT_IDS)
+ return dialog.billingProcessor!!.getPurchaseListingDetails(ArrayList(Arrays.asList(*ids)))
+ }
+ cancel(false)
+ return null
+ }
+
+ override fun onPostExecute(skuDetails: List?) {
+ super.onPostExecute(skuDetails)
+ val dialog = weakReference.get() ?: return
+
+ if (skuDetails == null || skuDetails.isEmpty()) {
+ dialog.progressContainer.visibility = View.GONE
+ return
+ }
+
+ dialog.progressContainer.visibility = View.GONE
+ dialog.recyclerView.itemAnimator = DefaultItemAnimator()
+ dialog.recyclerView.layoutManager = GridLayoutManager(dialog, 2)
+ dialog.recyclerView.adapter = SkuDetailsAdapter(dialog, skuDetails)
+ dialog.recyclerView.visibility = View.VISIBLE
+ }
+}
+
+class SkuDetailsAdapter(
+ private var donationsDialog: SupportDevelopmentActivity, objects: List
+) : RecyclerView.Adapter() {
+ private var skuDetailsList: List = ArrayList()
+
+ init {
+ skuDetailsList = objects
+ }
+
+ private fun getIcon(position: Int): Int {
+ return when (position) {
+ 0 -> R.drawable.ic_cookie_white_24dp
+ 1 -> R.drawable.ic_take_away_white_24dp
+ 2 -> R.drawable.ic_take_away_coffe_white_24dp
+ 3 -> R.drawable.ic_beer_white_24dp
+ 4 -> R.drawable.ic_fast_food_meal_white_24dp
+ 5 -> R.drawable.ic_popcorn_white_24dp
+ 6 -> R.drawable.ic_card_giftcard_white_24dp
+ else -> R.drawable.ic_card_giftcard_white_24dp
+ }
+ }
+
+ override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder {
+ return ViewHolder(
+ LayoutInflater.from(donationsDialog).inflate(
+ LAYOUT_RES_ID,
+ viewGroup,
+ false
+ )
+ )
+ }
+
+ override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
+ val skuDetails = skuDetailsList[i]
+ viewHolder.title.text = skuDetails.title.replace("(Retro Music Player)", "")
+ .trim { it <= ' ' }
+ viewHolder.text.text = skuDetails.description
+ viewHolder.text.visibility = View.GONE
+ viewHolder.price.text = skuDetails.priceText
+ viewHolder.image.setImageResource(getIcon(i))
+
+ val purchased = donationsDialog.billingProcessor!!.isPurchased(skuDetails.productId)
+ val titleTextColor = if (purchased) ATHUtil.resolveColor(
+ donationsDialog,
+ android.R.attr.textColorHint
+ ) else ThemeStore.textColorPrimary(donationsDialog)
+ val contentTextColor = if (purchased) titleTextColor else ThemeStore.textColorSecondary(
+ donationsDialog
+ )
+
+
+ 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 { _, _ -> purchased }
+ viewHolder.itemView.setOnClickListener { donationsDialog.donate(i) }
+ }
+
+ override fun getItemCount(): Int {
+ return skuDetailsList.size
+ }
+
+ class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+ var title: TextView = view.findViewById(R.id.itemTitle)
+ var text: TextView = view.findViewById(R.id.itemText)
+ var price: TextView = view.findViewById(R.id.itemPrice)
+ var image: AppCompatImageView = view.findViewById(R.id.itemImage)
+ }
+
+ companion object {
+ @LayoutRes
+ private val LAYOUT_RES_ID = R.layout.item_donation_option
+
+ private fun strikeThrough(textView: TextView, strikeThrough: Boolean) {
+ textView.paintFlags = if (strikeThrough) textView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
+ else textView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
+ }
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/UserInfoActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/UserInfoActivity.kt
new file mode 100644
index 000000000..c623d11d9
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/UserInfoActivity.kt
@@ -0,0 +1,245 @@
+package code.name.monkey.retromusic.activities
+
+import android.app.Activity
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.content.res.ColorStateList
+import android.graphics.Bitmap
+import android.net.Uri
+import android.os.Bundle
+import android.provider.MediaStore.Images.Media
+import android.provider.MediaStore.Images.Media.getBitmap
+import android.text.TextUtils
+import android.view.MenuItem
+import android.widget.Toast
+import code.name.monkey.appthemehelper.ThemeStore
+import code.name.monkey.appthemehelper.util.ColorUtil
+import code.name.monkey.appthemehelper.util.MaterialUtil
+import code.name.monkey.appthemehelper.util.MaterialValueHelper
+import code.name.monkey.retromusic.App
+import code.name.monkey.retromusic.Constants.USER_BANNER
+import code.name.monkey.retromusic.Constants.USER_PROFILE
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsBaseActivity
+import code.name.monkey.retromusic.extensions.applyToolbar
+import code.name.monkey.retromusic.util.Compressor
+import code.name.monkey.retromusic.util.ImageUtil.getResizedBitmap
+import code.name.monkey.retromusic.util.PreferenceUtil
+import com.afollestad.materialdialogs.LayoutMode
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.bottomsheets.BottomSheet
+import com.afollestad.materialdialogs.list.listItems
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.schedulers.Schedulers
+import kotlinx.android.synthetic.main.activity_user_info.*
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+
+class UserInfoActivity : AbsBaseActivity() {
+
+ private var disposable = CompositeDisposable()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_user_info)
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ setLightNavigationBar(true)
+
+ applyToolbar(toolbar)
+
+ MaterialUtil.setTint(nameContainer, false)
+ name.setText(PreferenceUtil.getInstance(this).userName)
+
+ if (PreferenceUtil.getInstance(this).profileImage.isNotEmpty()) {
+ loadImageFromStorage(PreferenceUtil.getInstance(this).profileImage)
+ }
+ if (PreferenceUtil.getInstance(this).bannerImage.isNotEmpty()) {
+ loadBannerFromStorage(PreferenceUtil.getInstance(this).bannerImage)
+ }
+ userImage.setOnClickListener {
+ MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
+ cornerRadius(PreferenceUtil.getInstance(this@UserInfoActivity).dialogCorner)
+ title(text = getString(R.string.set_photo))
+ listItems(items = listOf(getString(R.string.new_profile_photo), getString(R.string.remove_profile_photo))) { _, position, _ ->
+ when (position) {
+ 0 -> pickNewPhoto()
+ 1 -> PreferenceUtil.getInstance(this@UserInfoActivity).saveProfileImage("")
+ }
+ }
+ }
+ }
+ bannerSelect.setOnClickListener {
+ MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
+ cornerRadius(PreferenceUtil.getInstance(this@UserInfoActivity).dialogCorner)
+ title(R.string.select_banner_photo)
+ listItems(items = listOf(getString(R.string.new_banner_photo), getString(R.string.remove_banner_photo)))
+ { _, position, _ ->
+ when (position) {
+ 0 -> selectBannerImage()
+ 1 -> PreferenceUtil.getInstance(this@UserInfoActivity).setBannerImagePath("")
+ }
+ }
+ }
+ }
+ next.setOnClickListener {
+ val nameString = name.text.toString().trim { it <= ' ' }
+ if (TextUtils.isEmpty(nameString)) {
+ Toast.makeText(this, "Umm name is empty", Toast.LENGTH_SHORT).show()
+ return@setOnClickListener
+ }
+ PreferenceUtil.getInstance(this).userName = nameString
+ setResult(Activity.RESULT_OK)
+ finish()
+ }
+ next.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
+ ColorStateList.valueOf(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.accentColor(this))))
+ .apply {
+ next.setTextColor(this)
+ next.iconTint = this
+ }
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ onBackPressed()
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+ private fun selectBannerImage() {
+ val pickImageIntent = Intent(Intent.ACTION_PICK, Media.EXTERNAL_CONTENT_URI)
+ pickImageIntent.type = "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)
+ }
+
+ private fun pickNewPhoto() {
+ val pickImageIntent = Intent(Intent.ACTION_PICK, Media.EXTERNAL_CONTENT_URI)
+ pickImageIntent.type = "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)
+ }
+
+ public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ if (resultCode == Activity.RESULT_OK && data != null) {
+ when (requestCode) {
+ PICK_IMAGE_REQUEST -> {
+ try {
+ data.data?.let {
+ val bitmap = getResizedBitmap(
+ getBitmap(contentResolver, it),
+ PROFILE_ICON_SIZE
+ )
+ val profileImagePath = saveToInternalStorage(bitmap, USER_PROFILE)
+ PreferenceUtil.getInstance(this).saveProfileImage(profileImagePath)
+ loadImageFromStorage(profileImagePath)
+ }
+
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ PICK_BANNER_REQUEST -> {
+ try {
+ data.data?.let {
+ val bitmap = getBitmap(contentResolver, it)
+ val profileImagePath = saveToInternalStorage(bitmap, USER_BANNER)
+ PreferenceUtil.getInstance(this).setBannerImagePath(profileImagePath)
+ loadBannerFromStorage(profileImagePath)
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+
+ private fun getImagePath(aUri: Uri, aSelection: String?): String? {
+ var path: String? = null
+ val cursor = App.getContext().contentResolver.query(aUri, null, aSelection, null, null)
+ if (cursor != null) {
+ if (cursor.moveToFirst()) {
+ path = cursor.getString(cursor.getColumnIndex(Media.DATA))
+ }
+ cursor.close()
+ }
+ return path
+ }
+
+ private fun loadBannerFromStorage(profileImagePath: String) {
+ disposable.add(Compressor(this).setQuality(100)
+ .setCompressFormat(Bitmap.CompressFormat.WEBP)
+ .compressToBitmapAsFlowable(File(profileImagePath, USER_BANNER))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ bitmap -> bannerImage.setImageBitmap(bitmap) }, { t -> println(t) })
+ )
+ }
+
+ private fun loadImageFromStorage(path: String) {
+ disposable.add(Compressor(this)
+ .setMaxHeight(300)
+ .setMaxWidth(300)
+ .setQuality(75)
+ .setCompressFormat(Bitmap.CompressFormat.WEBP)
+ .compressToBitmapAsFlowable(File(path, USER_PROFILE))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ bitmap -> userImage.setImageBitmap(bitmap) }, { t -> println(t) })
+ )
+ }
+
+ private fun saveToInternalStorage(bitmapImage: Bitmap, userBanner: String): String {
+ val cw = ContextWrapper(this)
+ val directory = cw.getDir("imageDir", Context.MODE_PRIVATE)
+ val myPath = File(directory, userBanner)
+ var fos: FileOutputStream? = null
+ try {
+ fos = FileOutputStream(myPath)
+ // Use the compress method on the BitMap object to write image to the OutputStream
+ bitmapImage.compress(Bitmap.CompressFormat.WEBP, 100, fos)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ try {
+ fos?.close()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ return directory.absolutePath
+ }
+
+ companion object {
+
+ private const val PICK_IMAGE_REQUEST = 9002
+ private const val PICK_BANNER_REQUEST = 9004
+ private const val PROFILE_ICON_SIZE = 400
+ }
+}
+
+fun Activity.pickImage(requestCode: Int) {
+ Intent(Intent.ACTION_GET_CONTENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "image/*"
+ startActivityForResult(this, requestCode)
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.java b/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.java
new file mode 100644
index 000000000..176114cbb
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.java
@@ -0,0 +1,93 @@
+package code.name.monkey.retromusic.activities;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.webkit.WebView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.widget.Toolbar;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+import code.name.monkey.appthemehelper.ThemeStore;
+import code.name.monkey.appthemehelper.util.ColorUtil;
+import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper;
+import code.name.monkey.retromusic.R;
+import code.name.monkey.retromusic.activities.base.AbsBaseActivity;
+import code.name.monkey.retromusic.util.PreferenceUtil;
+
+import static code.name.monkey.appthemehelper.util.ATHUtil.INSTANCE;
+
+public class WhatsNewActivity extends AbsBaseActivity {
+ WebView webView;
+ Toolbar toolbar;
+ AppBarLayout appBarLayout;
+
+
+ private static void setChangelogRead(@NonNull Context context) {
+ try {
+ PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+ int currentVersion = pInfo.versionCode;
+ PreferenceUtil.getInstance(context).setLastChangeLogVersion(currentVersion);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static String colorToCSS(int color) {
+ return String.format("rgb(%d, %d, %d)", Color.red(color), Color.green(color), Color.blue(color)); // on API 29, WebView doesn't load with hex colors
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ setDrawUnderStatusBar();
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_whats_new);
+ setStatusbarColorAuto();
+ setNavigationbarColorAuto();
+ setTaskDescriptionColorAuto();
+
+ webView = findViewById(R.id.webView);
+ toolbar = findViewById(R.id.toolbar);
+ appBarLayout = findViewById(R.id.appBarLayout);
+
+ toolbar.setBackgroundColor(INSTANCE.resolveColor(this, R.attr.colorSurface));
+ //setSupportActionBar(toolbar);
+
+ toolbar.setNavigationOnClickListener(v -> onBackPressed());
+ ToolbarContentTintHelper.colorBackButton(toolbar);
+
+ try {
+ StringBuilder buf = new StringBuilder();
+ InputStream json = getAssets().open("retro-changelog.html");
+ BufferedReader in = new BufferedReader(new InputStreamReader(json, StandardCharsets.UTF_8));
+ String str;
+ while ((str = in.readLine()) != null)
+ buf.append(str);
+ in.close();
+
+ // Inject color values for WebView body background and links
+ final boolean isDark = INSTANCE.isWindowBackgroundDark(this);
+ final String backgroundColor = colorToCSS(INSTANCE.resolveColor(this, R.attr.colorSurface, Color.parseColor(isDark ? "#424242" : "#ffffff")));
+ final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000"));
+ final String changeLog = buf.toString()
+ .replace("{style-placeholder}", String.format("body { background-color: %s; color: %s; }", backgroundColor, contentColor))
+ .replace("{link-color}", colorToCSS(ThemeStore.Companion.accentColor(this)))
+ .replace("{link-color-active}", colorToCSS(ColorUtil.INSTANCE.lightenColor(ThemeStore.Companion.accentColor(this))));
+
+ webView.loadData(changeLog, "text/html", "UTF-8");
+ } catch (Throwable e) {
+ webView.loadData("Unable to load " + e.getLocalizedMessage() + "
", "text/html", "UTF-8");
+ }
+ setChangelogRead(this);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewFragment.kt b/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewFragment.kt
deleted file mode 100644
index 48b39ed35..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewFragment.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package code.name.monkey.retromusic.activities
-
-import android.content.Context
-import android.content.Intent
-import android.content.pm.PackageManager
-import android.graphics.Color
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.webkit.WebResourceRequest
-import android.webkit.WebView
-import android.webkit.WebViewClient
-import androidx.core.content.pm.PackageInfoCompat
-import androidx.core.widget.NestedScrollView
-import androidx.fragment.app.FragmentActivity
-import code.name.monkey.appthemehelper.util.ATHUtil.isWindowBackgroundDark
-import code.name.monkey.appthemehelper.util.ColorUtil.isColorLight
-import code.name.monkey.appthemehelper.util.ColorUtil.lightenColor
-import code.name.monkey.appthemehelper.util.MaterialValueHelper.getPrimaryTextColor
-import code.name.monkey.retromusic.BuildConfig
-import code.name.monkey.retromusic.Constants
-import code.name.monkey.retromusic.databinding.FragmentWhatsNewBinding
-import code.name.monkey.retromusic.extensions.accentColor
-import code.name.monkey.retromusic.extensions.openUrl
-import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion
-import com.google.android.material.bottomsheet.BottomSheetDialogFragment
-import java.nio.charset.StandardCharsets
-import java.util.*
-
-class WhatsNewFragment : BottomSheetDialogFragment() {
- private var _binding: FragmentWhatsNewBinding? = null
- val binding get() = _binding!!
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- _binding = FragmentWhatsNewBinding.inflate(inflater, container, false)
- return binding.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- try {
- val buf = StringBuilder()
- val stream = requireContext().assets.open("retro-changelog.html")
- stream.reader(StandardCharsets.UTF_8).buffered().use { br ->
- var str: String?
- while (br.readLine().also { str = it } != null) {
- buf.append(str)
- }
- }
-
- // Inject color values for WebView body background and links
- val isDark = isWindowBackgroundDark(requireContext())
- val accentColor = accentColor()
- binding.webView.setBackgroundColor(0)
- val contentColor = colorToCSS(Color.parseColor(if (isDark) "#ffffff" else "#000000"))
- val textColor = colorToCSS(Color.parseColor(if (isDark) "#60FFFFFF" else "#80000000"))
- val accentColorString = colorToCSS(accentColor())
- val cardBackgroundColor =
- colorToCSS(Color.parseColor(if (isDark) "#353535" else "#ffffff"))
- val accentTextColor = colorToCSS(
- getPrimaryTextColor(
- requireContext(), isColorLight(accentColor)
- )
- )
- val changeLog = buf.toString()
- .replace(
- "{style-placeholder}",
- "body { color: $contentColor; } li {color: $textColor;} h3 {color: $accentColorString;} .tag {background-color: $accentColorString; color: $accentTextColor; } div{background-color: $cardBackgroundColor;}"
- )
- .replace("{link-color}", colorToCSS(accentColor()))
- .replace(
- "{link-color-active}",
- colorToCSS(
- lightenColor(accentColor())
- )
- )
- binding.webView.loadData(changeLog, "text/html", "UTF-8")
- binding.webView.webViewClient = object : WebViewClient() {
- override fun shouldOverrideUrlLoading(
- view: WebView?,
- request: WebResourceRequest?
- ): Boolean {
- val url = request?.url ?: return false
- //you can do checks here e.g. url.host equals to target one
- startActivity(Intent(Intent.ACTION_VIEW, url))
- return true
- }
- }
- } catch (e: Throwable) {
- binding.webView.loadData(
- "Unable to load " + e.localizedMessage + "
", "text/html", "UTF-8"
- )
- }
- setChangelogRead(requireContext())
- binding.tgFab.setOnClickListener {
- openUrl(Constants.TELEGRAM_CHANGE_LOG)
- }
- binding.tgFab.accentColor()
- binding.tgFab.shrink()
- binding.container.setOnScrollChangeListener { _: NestedScrollView?, _: Int, scrollY: Int, _: Int, oldScrollY: Int ->
- val dy = scrollY - oldScrollY
- if (dy > 0) {
- binding.tgFab.shrink()
- } else if (dy < 0) {
- binding.tgFab.extend()
- }
- }
- }
-
- override fun onDestroy() {
- super.onDestroy()
- _binding = null
- }
-
- companion object {
-
- const val TAG = "WhatsNewFragment"
- private fun colorToCSS(color: Int): String {
- return String.format(
- Locale.getDefault(),
- "rgba(%d, %d, %d, %d)",
- Color.red(color),
- Color.green(color),
- Color.blue(color),
- Color.alpha(color)
- ) // on API 29, WebView doesn't load with hex colors
- }
-
- private fun setChangelogRead(context: Context) {
- try {
- val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
- val currentVersion = PackageInfoCompat.getLongVersionCode(pInfo)
- lastVersion = currentVersion
- } catch (e: PackageManager.NameNotFoundException) {
- e.printStackTrace()
- }
- }
-
- fun showChangeLog(activity: FragmentActivity) {
- val pInfo = activity.packageManager.getPackageInfo(activity.packageName, 0)
- val currentVersion = PackageInfoCompat.getLongVersionCode(pInfo)
- if (currentVersion > lastVersion && !BuildConfig.DEBUG) {
- val changelogBottomSheet = WhatsNewFragment()
- changelogBottomSheet.show(activity.supportFragmentManager, TAG)
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsBaseActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsBaseActivity.kt
index 1e0c110d5..3b096f518 100644
--- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsBaseActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsBaseActivity.kt
@@ -1,204 +1,143 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.activities.base
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
-import android.graphics.Rect
import android.media.AudioManager
import android.net.Uri
-import android.os.Bundle
+import android.os.*
import android.provider.Settings
-import android.view.KeyEvent
-import android.view.MotionEvent
-import android.view.View
-import android.view.inputmethod.InputMethodManager
-import android.widget.EditText
+import android.view.*
import androidx.core.app.ActivityCompat
-import androidx.core.content.getSystemService
-import code.name.monkey.appthemehelper.util.VersionUtils
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.extensions.accentColor
-import code.name.monkey.retromusic.extensions.rootView
-import code.name.monkey.retromusic.util.logD
+import code.name.monkey.appthemehelper.ThemeStore
import com.google.android.material.snackbar.Snackbar
abstract class AbsBaseActivity : AbsThemeActivity() {
- private var hadPermissions: Boolean = false
- private lateinit var permissions: Array
- private var permissionDeniedMessage: String? = null
+ private var hadPermissions: Boolean = false
+ private lateinit var permissions: Array
+ private var permissionDeniedMessage: String? = null
- open fun getPermissionsToRequest(): Array {
- return arrayOf()
- }
+ open fun getPermissionsToRequest(): Array {
+ return arrayOf()
+ }
- protected fun setPermissionDeniedMessage(message: String) {
- permissionDeniedMessage = message
- }
+ protected fun setPermissionDeniedMessage(message: String) {
+ permissionDeniedMessage = message
+ }
- fun getPermissionDeniedMessage(): String {
- return if (permissionDeniedMessage == null) getString(R.string.permissions_denied) else permissionDeniedMessage!!
- }
+ fun getPermissionDeniedMessage(): String {
+ return if (permissionDeniedMessage == null) getString(code.name.monkey.retromusic.R.string.permissions_denied) else permissionDeniedMessage!!
+ }
- private val snackBarContainer: View
- get() = rootView
+ private val snackBarContainer: View
+ get() = window.decorView
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- volumeControlStream = AudioManager.STREAM_MUSIC
- permissions = getPermissionsToRequest()
- hadPermissions = hasPermissions()
- permissionDeniedMessage = null
- }
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ volumeControlStream = AudioManager.STREAM_MUSIC
+ permissions = getPermissionsToRequest()
+ hadPermissions = hasPermissions()
+ permissionDeniedMessage = null
+ }
- override fun onResume() {
- super.onResume()
- val hasPermissions = hasPermissions()
- if (hasPermissions != hadPermissions) {
- hadPermissions = hasPermissions
- if (VersionUtils.hasMarshmallow()) {
- onHasPermissionsChanged(hasPermissions)
- }
- }
- }
+ override fun onPostCreate(savedInstanceState: Bundle?) {
+ super.onPostCreate(savedInstanceState)
+ if (!hasPermissions()) {
+ requestPermissions()
+ }
+ }
- protected open fun onHasPermissionsChanged(hasPermissions: Boolean) {
- // implemented by sub classes
- logD(hasPermissions)
- }
+ override fun onResume() {
+ super.onResume()
+ val hasPermissions = hasPermissions()
+ if (hasPermissions != hadPermissions) {
+ hadPermissions = hasPermissions
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ onHasPermissionsChanged(hasPermissions)
+ }
+ }
+ }
- override fun dispatchKeyEvent(event: KeyEvent): Boolean {
- if (event.keyCode == KeyEvent.KEYCODE_MENU && event.action == KeyEvent.ACTION_UP) {
- showOverflowMenu()
- return true
- }
- return super.dispatchKeyEvent(event)
- }
+ protected open fun onHasPermissionsChanged(hasPermissions: Boolean) {
+ // implemented by sub classes
+ }
- private fun showOverflowMenu() {
- }
+ override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+ if (event.keyCode == KeyEvent.KEYCODE_MENU && event.action == KeyEvent.ACTION_UP) {
+ showOverflowMenu()
+ return true
+ }
+ return super.dispatchKeyEvent(event)
+ }
- protected open fun requestPermissions() {
- ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST)
- }
+ protected fun showOverflowMenu() {
- protected fun hasPermissions(): Boolean {
- for (permission in permissions) {
- if (ActivityCompat.checkSelfPermission(this,
- permission) != PackageManager.PERMISSION_GRANTED
- ) {
- return false
- }
- }
- return true
- }
+ }
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray,
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- if (requestCode == PERMISSION_REQUEST) {
- for (grantResult in grantResults) {
- if (grantResult != PackageManager.PERMISSION_GRANTED) {
- if (ActivityCompat.shouldShowRequestPermissionRationale(
- this@AbsBaseActivity, Manifest.permission.READ_EXTERNAL_STORAGE,
- ) || ActivityCompat.shouldShowRequestPermissionRationale(
- this@AbsBaseActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
- )
- ) {
- // User has deny from permission dialog
- Snackbar.make(
- snackBarContainer,
- permissionDeniedMessage!!,
- Snackbar.LENGTH_SHORT
- )
- .setAction(R.string.action_grant) { requestPermissions() }
- .setActionTextColor(accentColor()).show()
- } else {
- // User has deny permission and checked never show permission dialog so you can redirect to Application settings page
- Snackbar.make(
- snackBarContainer,
- permissionDeniedMessage!!,
- Snackbar.LENGTH_INDEFINITE
- )
- .setAction(R.string.action_settings) {
- val intent = Intent()
- intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
- val uri = Uri.fromParts(
- "package",
- this@AbsBaseActivity.packageName,
- null
- )
- intent.data = uri
- startActivity(intent)
- }.setActionTextColor(accentColor()).show()
- }
- return
- }
- }
- hadPermissions = true
- onHasPermissionsChanged(true)
- } else if (requestCode == BLUETOOTH_PERMISSION_REQUEST) {
- for (grantResult in grantResults) {
- if (grantResult != PackageManager.PERMISSION_GRANTED) {
- if (ActivityCompat.shouldShowRequestPermissionRationale(
- this@AbsBaseActivity, Manifest.permission.BLUETOOTH_CONNECT
- )
- ) {
- // User has deny from permission dialog
- Snackbar.make(
- snackBarContainer,
- R.string.permission_bluetooth_denied,
- Snackbar.LENGTH_SHORT
- )
- .setAction(R.string.action_grant) {
- ActivityCompat.requestPermissions(this,
- arrayOf(Manifest.permission.BLUETOOTH_CONNECT),
- BLUETOOTH_PERMISSION_REQUEST)
- }
- .setActionTextColor(accentColor()).show()
- }
- }
- }
- }
- }
+ protected open fun requestPermissions() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ requestPermissions(permissions, PERMISSION_REQUEST)
+ }
+ }
- companion object {
- const val PERMISSION_REQUEST = 100
- const val BLUETOOTH_PERMISSION_REQUEST = 101
- }
+ protected fun hasPermissions(): Boolean {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ for (permission in permissions) {
+ if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+ return false
+ }
+ }
+ }
+ return true
+ }
- // this lets keyboard close when clicked in background
- override fun dispatchTouchEvent(event: MotionEvent): Boolean {
- if (event.action == MotionEvent.ACTION_DOWN) {
- val v = currentFocus
- if (v is EditText) {
- val outRect = Rect()
- v.getGlobalVisibleRect(outRect)
- if (!outRect.contains(event.rawX.toInt(), event.rawY.toInt())) {
- v.clearFocus()
- getSystemService()?.hideSoftInputFromWindow(
- v.windowToken,
- 0
- )
- }
- }
- }
- return super.dispatchTouchEvent(event)
- }
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ if (requestCode == PERMISSION_REQUEST) {
+ for (grantResult in grantResults) {
+ if (grantResult != PackageManager.PERMISSION_GRANTED) {
+ if (ActivityCompat.shouldShowRequestPermissionRationale(
+ this@AbsBaseActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE
+ )) {
+ //User has deny from permission dialog
+ Snackbar.make(
+ snackBarContainer,
+ permissionDeniedMessage!!,
+ Snackbar.LENGTH_INDEFINITE
+ )
+ .setAction(code.name.monkey.retromusic.R.string.action_grant) { 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(
+ snackBarContainer,
+ permissionDeniedMessage!!,
+ Snackbar.LENGTH_INDEFINITE
+ ).setAction(code.name.monkey.retromusic.R.string.action_settings) {
+ val intent = Intent()
+ intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
+ val uri = Uri.fromParts(
+ "package",
+ this@AbsBaseActivity.packageName,
+ null
+ )
+ intent.data = uri
+ startActivity(intent)
+ }.setActionTextColor(ThemeStore.accentColor(this)).show()
+ }
+ return
+ }
+ }
+ hadPermissions = true
+ onHasPermissionsChanged(true)
+ }
+ }
+
+ companion object {
+ const val PERMISSION_REQUEST = 100
+ }
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsMusicServiceActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsMusicServiceActivity.kt
index f9f05c919..30e99735b 100644
--- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsMusicServiceActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsMusicServiceActivity.kt
@@ -1,221 +1,167 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.activities.base
import android.Manifest
import android.content.*
-import android.os.Bundle
-import android.os.IBinder
-import androidx.core.content.ContextCompat
-import androidx.lifecycle.lifecycleScope
-import code.name.monkey.appthemehelper.util.VersionUtils
+import android.os.*
import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.db.toPlayCount
import code.name.monkey.retromusic.helper.MusicPlayerRemote
-import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener
-import code.name.monkey.retromusic.repository.RealRepository
-import code.name.monkey.retromusic.service.MusicService.Companion.FAVORITE_STATE_CHANGED
-import code.name.monkey.retromusic.service.MusicService.Companion.MEDIA_STORE_CHANGED
-import code.name.monkey.retromusic.service.MusicService.Companion.META_CHANGED
-import code.name.monkey.retromusic.service.MusicService.Companion.PLAY_STATE_CHANGED
-import code.name.monkey.retromusic.service.MusicService.Companion.QUEUE_CHANGED
-import code.name.monkey.retromusic.service.MusicService.Companion.REPEAT_MODE_CHANGED
-import code.name.monkey.retromusic.service.MusicService.Companion.SHUFFLE_MODE_CHANGED
-import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.logD
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import org.koin.android.ext.android.inject
+import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
+import code.name.monkey.retromusic.service.MusicService.*
import java.lang.ref.WeakReference
+import java.util.*
-abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventListener {
+abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener {
- private val mMusicServiceEventListeners = ArrayList()
- private val repository: RealRepository by inject()
- private var serviceToken: MusicPlayerRemote.ServiceToken? = null
- private var musicStateReceiver: MusicStateReceiver? = null
- private var receiverRegistered: Boolean = false
+ private val mMusicServiceEventListeners = ArrayList()
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- serviceToken = MusicPlayerRemote.bindToService(this, object : ServiceConnection {
- override fun onServiceConnected(name: ComponentName, service: IBinder) {
- this@AbsMusicServiceActivity.onServiceConnected()
- }
+ private var serviceToken: MusicPlayerRemote.ServiceToken? = null
+ private var musicStateReceiver: MusicStateReceiver? = null
+ private var receiverRegistered: Boolean = false
- override fun onServiceDisconnected(name: ComponentName) {
- this@AbsMusicServiceActivity.onServiceDisconnected()
- }
- })
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ serviceToken = MusicPlayerRemote.bindToService(this, object : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ this@AbsMusicServiceActivity.onServiceConnected()
+ }
- setPermissionDeniedMessage(getString(R.string.permission_external_storage_denied))
- }
+ override fun onServiceDisconnected(name: ComponentName) {
+ this@AbsMusicServiceActivity.onServiceDisconnected()
+ }
+ })
- override fun onDestroy() {
- super.onDestroy()
- MusicPlayerRemote.unbindFromService(serviceToken)
- if (receiverRegistered) {
- unregisterReceiver(musicStateReceiver)
- receiverRegistered = false
- }
- }
+ setPermissionDeniedMessage(getString(R.string.permission_external_storage_denied));
+ }
- fun addMusicServiceEventListener(listenerI: IMusicServiceEventListener?) {
- if (listenerI != null) {
- mMusicServiceEventListeners.add(listenerI)
- }
- }
+ override fun onDestroy() {
+ super.onDestroy()
+ MusicPlayerRemote.unbindFromService(serviceToken)
+ if (receiverRegistered) {
+ unregisterReceiver(musicStateReceiver)
+ receiverRegistered = false
+ }
+ }
- fun removeMusicServiceEventListener(listenerI: IMusicServiceEventListener?) {
- if (listenerI != null) {
- mMusicServiceEventListeners.remove(listenerI)
- }
- }
+ fun addMusicServiceEventListener(listener: MusicServiceEventListener?) {
+ if (listener != null) {
+ mMusicServiceEventListeners.add(listener)
+ }
+ }
- override fun onServiceConnected() {
- if (!receiverRegistered) {
- musicStateReceiver = MusicStateReceiver(this)
+ fun removeMusicServiceEventListener(listener: MusicServiceEventListener?) {
+ if (listener != null) {
+ mMusicServiceEventListeners.remove(listener)
+ }
+ }
- val filter = 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)
- filter.addAction(FAVORITE_STATE_CHANGED)
+ override fun onServiceConnected() {
+ if (!receiverRegistered) {
+ musicStateReceiver = MusicStateReceiver(this)
- ContextCompat.registerReceiver(this, musicStateReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED)
- receiverRegistered = true
- }
+ val filter = 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)
+ filter.addAction(FAVORITE_STATE_CHANGED)
- for (listener in mMusicServiceEventListeners) {
- listener.onServiceConnected()
- }
- }
+ registerReceiver(musicStateReceiver, filter)
- override fun onServiceDisconnected() {
- if (receiverRegistered) {
- unregisterReceiver(musicStateReceiver)
- receiverRegistered = false
- }
+ receiverRegistered = true
+ }
- for (listener in mMusicServiceEventListeners) {
- listener.onServiceDisconnected()
- }
- }
+ for (listener in mMusicServiceEventListeners) {
+ listener.onServiceConnected()
+ }
+ }
- override fun onPlayingMetaChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onPlayingMetaChanged()
- }
- lifecycleScope.launch(Dispatchers.IO) {
- if (!PreferenceUtil.pauseHistory) {
- repository.upsertSongInHistory(MusicPlayerRemote.currentSong)
- }
- val song = repository.findSongExistInPlayCount(MusicPlayerRemote.currentSong.id)
- ?.apply { playCount += 1 }
- ?: MusicPlayerRemote.currentSong.toPlayCount()
+ override fun onServiceDisconnected() {
+ if (receiverRegistered) {
+ unregisterReceiver(musicStateReceiver)
+ receiverRegistered = false
+ }
- repository.upsertSongInPlayCount(song)
- }
- }
+ for (listener in mMusicServiceEventListeners) {
+ listener.onServiceDisconnected()
+ }
+ }
- override fun onQueueChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onQueueChanged()
- }
- }
+ override fun onPlayingMetaChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onPlayingMetaChanged()
+ }
+ }
- override fun onPlayStateChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onPlayStateChanged()
- }
- }
+ override fun onQueueChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onQueueChanged()
+ }
+ }
- override fun onMediaStoreChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onMediaStoreChanged()
- }
- }
+ override fun onPlayStateChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onPlayStateChanged()
+ }
+ }
- override fun onRepeatModeChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onRepeatModeChanged()
- }
- }
+ override fun onMediaStoreChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onMediaStoreChanged()
+ }
+ }
- override fun onShuffleModeChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onShuffleModeChanged()
- }
- }
+ override fun onRepeatModeChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onRepeatModeChanged()
+ }
+ }
- override fun onFavoriteStateChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onFavoriteStateChanged()
- }
- }
+ override fun onShuffleModeChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onShuffleModeChanged()
+ }
+ }
- override fun onHasPermissionsChanged(hasPermissions: Boolean) {
- super.onHasPermissionsChanged(hasPermissions)
- val intent = Intent(MEDIA_STORE_CHANGED)
- intent.putExtra(
- "from_permissions_changed",
- true
- ) // just in case we need to know this at some point
- sendBroadcast(intent)
- logD("sendBroadcast $hasPermissions")
- }
+ override fun onHasPermissionsChanged(hasPermissions: Boolean) {
+ super.onHasPermissionsChanged(hasPermissions)
+ val intent = Intent(MEDIA_STORE_CHANGED)
+ intent.putExtra(
+ "from_permissions_changed",
+ true
+ ) // just in case we need to know this at some point
+ sendBroadcast(intent)
+ }
- override fun getPermissionsToRequest(): Array {
- return mutableListOf().apply {
- if (VersionUtils.hasT()) {
- add(Manifest.permission.READ_MEDIA_AUDIO)
- add(Manifest.permission.POST_NOTIFICATIONS)
- } else {
- add(Manifest.permission.READ_EXTERNAL_STORAGE)
- }
- if (!VersionUtils.hasR()) {
- add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- }
- }.toTypedArray()
- }
+ override fun getPermissionsToRequest(): Array {
+ return arrayOf(
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE
+ )
+ }
- private class MusicStateReceiver(activity: AbsMusicServiceActivity) : BroadcastReceiver() {
+ private class MusicStateReceiver(activity: AbsMusicServiceActivity) : BroadcastReceiver() {
- private val reference: WeakReference = WeakReference(activity)
+ private val reference: WeakReference = WeakReference(activity)
- override fun onReceive(context: Context, intent: Intent) {
- val action = intent.action
- val activity = reference.get()
- if (activity != null && action != null) {
- when (action) {
- FAVORITE_STATE_CHANGED -> activity.onFavoriteStateChanged()
- META_CHANGED -> activity.onPlayingMetaChanged()
- QUEUE_CHANGED -> activity.onQueueChanged()
- PLAY_STATE_CHANGED -> activity.onPlayStateChanged()
- REPEAT_MODE_CHANGED -> activity.onRepeatModeChanged()
- SHUFFLE_MODE_CHANGED -> activity.onShuffleModeChanged()
- MEDIA_STORE_CHANGED -> activity.onMediaStoreChanged()
- }
- }
- }
- }
+ override fun onReceive(context: Context, intent: Intent) {
+ val action = intent.action
+ val activity = reference.get()
+ if (activity != null && action != null) {
+ when (action) {
+ FAVORITE_STATE_CHANGED, META_CHANGED -> activity.onPlayingMetaChanged()
+ QUEUE_CHANGED -> activity.onQueueChanged()
+ PLAY_STATE_CHANGED -> activity.onPlayStateChanged()
+ REPEAT_MODE_CHANGED -> activity.onRepeatModeChanged()
+ SHUFFLE_MODE_CHANGED -> activity.onShuffleModeChanged()
+ MEDIA_STORE_CHANGED -> activity.onMediaStoreChanged()
+ }
+ }
+ }
+ }
- companion object {
- val TAG: String = AbsMusicServiceActivity::class.java.simpleName
- }
+ companion object {
+ val TAG: String = AbsMusicServiceActivity::class.java.simpleName
+ }
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt
index 2a81ca9b4..cc72372dc 100644
--- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt
@@ -1,226 +1,110 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.activities.base
-import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
-import android.content.Intent
-import android.content.SharedPreferences
-import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
-import android.view.animation.PathInterpolator
-import android.widget.FrameLayout
-import androidx.activity.OnBackPressedCallback
-import androidx.core.animation.doOnEnd
-import androidx.core.view.*
-import androidx.fragment.app.commit
-import code.name.monkey.appthemehelper.util.VersionUtils
-import code.name.monkey.retromusic.ADAPTIVE_COLOR_APP
-import code.name.monkey.retromusic.ALBUM_COVER_STYLE
-import code.name.monkey.retromusic.ALBUM_COVER_TRANSFORM
-import code.name.monkey.retromusic.CAROUSEL_EFFECT
-import code.name.monkey.retromusic.CIRCLE_PLAY_BUTTON
-import code.name.monkey.retromusic.EXTRA_SONG_INFO
-import code.name.monkey.retromusic.KEEP_SCREEN_ON
-import code.name.monkey.retromusic.LIBRARY_CATEGORIES
-import code.name.monkey.retromusic.NOW_PLAYING_SCREEN_ID
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+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.SCREEN_ON_LYRICS
-import code.name.monkey.retromusic.SWIPE_ANYWHERE_NOW_PLAYING
-import code.name.monkey.retromusic.SWIPE_DOWN_DISMISS
-import code.name.monkey.retromusic.TAB_TEXT_MODE
-import code.name.monkey.retromusic.TOGGLE_ADD_CONTROLS
-import code.name.monkey.retromusic.TOGGLE_FULL_SCREEN
-import code.name.monkey.retromusic.TOGGLE_VOLUME
-import code.name.monkey.retromusic.activities.PermissionActivity
-import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding
-import code.name.monkey.retromusic.extensions.*
-import code.name.monkey.retromusic.fragments.LibraryViewModel
+import code.name.monkey.retromusic.extensions.hide
+import code.name.monkey.retromusic.extensions.show
+import code.name.monkey.retromusic.fragments.MiniPlayerFragment
import code.name.monkey.retromusic.fragments.NowPlayingScreen
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
-import code.name.monkey.retromusic.fragments.other.MiniPlayerFragment
import code.name.monkey.retromusic.fragments.player.adaptive.AdaptiveFragment
import code.name.monkey.retromusic.fragments.player.blur.BlurPlayerFragment
import code.name.monkey.retromusic.fragments.player.card.CardFragment
import code.name.monkey.retromusic.fragments.player.cardblur.CardBlurFragment
-import code.name.monkey.retromusic.fragments.player.circle.CirclePlayerFragment
-import code.name.monkey.retromusic.fragments.player.classic.ClassicPlayerFragment
import code.name.monkey.retromusic.fragments.player.color.ColorFragment
import code.name.monkey.retromusic.fragments.player.fit.FitFragment
import code.name.monkey.retromusic.fragments.player.flat.FlatPlayerFragment
import code.name.monkey.retromusic.fragments.player.full.FullPlayerFragment
-import code.name.monkey.retromusic.fragments.player.gradient.GradientPlayerFragment
import code.name.monkey.retromusic.fragments.player.material.MaterialFragment
-import code.name.monkey.retromusic.fragments.player.md3.MD3PlayerFragment
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
-import code.name.monkey.retromusic.fragments.player.peek.PeekPlayerFragment
+import code.name.monkey.retromusic.fragments.player.peak.PeakPlayerFragment
import code.name.monkey.retromusic.fragments.player.plain.PlainPlayerFragment
import code.name.monkey.retromusic.fragments.player.simple.SimplePlayerFragment
import code.name.monkey.retromusic.fragments.player.tiny.TinyPlayerFragment
-import code.name.monkey.retromusic.fragments.queue.PlayingQueueFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.CategoryInfo
+import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.ViewUtil
-import code.name.monkey.retromusic.util.logD
-import com.google.android.material.bottomnavigation.BottomNavigationView
+import code.name.monkey.retromusic.views.BottomNavigationBarTinted
import com.google.android.material.bottomsheet.BottomSheetBehavior
-import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
-import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED
-import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_DRAGGING
-import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
-import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
-import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_SETTLING
-import com.google.android.material.bottomsheet.BottomSheetBehavior.from
-import org.koin.androidx.viewmodel.ext.android.viewModel
+import com.google.android.material.card.MaterialCardView
+import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
-
-abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
- SharedPreferences.OnSharedPreferenceChangeListener {
+abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlayerFragment.Callbacks {
companion object {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
}
- var fromNotification = false
- private var windowInsets: WindowInsetsCompat? = null
- protected val libraryViewModel by viewModel()
- private lateinit var bottomSheetBehavior: BottomSheetBehavior
- private lateinit var playerFragment: AbsPlayerFragment
+ private lateinit var bottomSheetBehavior: BottomSheetBehavior
private var miniPlayerFragment: MiniPlayerFragment? = null
- private var nowPlayingScreen: NowPlayingScreen? = null
+ private var playerFragment: AbsPlayerFragment? = null
+ private var currentNowPlayingScreen: NowPlayingScreen? = null
+ private var navigationBarColor: Int = 0
private var taskColor: Int = 0
- private var paletteColor: Int = Color.WHITE
- private var navigationBarColor = 0
-
+ private var lightStatusBar: Boolean = false
+ private var lightNavigationBar: Boolean = false
+ private var navigationBarColorAnimator: ValueAnimator? = null
+ protected abstract fun createContentView(): View
private val panelState: Int
get() = bottomSheetBehavior.state
- private lateinit var binding: SlidingMusicPanelLayoutBinding
- private var isInOneTabMode = false
- private var navigationBarColorAnimator: ValueAnimator? = null
- private val argbEvaluator: ArgbEvaluator = ArgbEvaluator()
+ private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
- private val onBackPressedCallback = object : OnBackPressedCallback(true) {
- override fun handleOnBackPressed() {
- println("Handle back press ${bottomSheetBehavior.state}")
- if (!handleBackPress()) {
- remove()
- onBackPressedDispatcher.onBackPressed()
- }
+ override fun onSlide(bottomSheet: View, slideOffset: Float) {
+ setMiniPlayerAlphaProgress(slideOffset)
+ dimBackground.show()
+ dimBackground.alpha = slideOffset
}
- }
- private val bottomSheetCallbackList by lazy {
- object : BottomSheetCallback() {
+ override fun onStateChanged(bottomSheet: View, newState: Int) {
+ when (newState) {
+ BottomSheetBehavior.STATE_EXPANDED -> {
+ onPanelExpanded()
+ }
+ BottomSheetBehavior.STATE_COLLAPSED -> {
+ onPanelCollapsed()
+ dimBackground.hide()
+ }
+ else -> {
- override fun onSlide(bottomSheet: View, slideOffset: Float) {
- setMiniPlayerAlphaProgress(slideOffset)
- navigationBarColorAnimator?.cancel()
- setNavigationBarColorPreOreo(
- argbEvaluator.evaluate(
- slideOffset,
- surfaceColor(),
- navigationBarColor
- ) as Int
- )
- }
-
- override fun onStateChanged(bottomSheet: View, newState: Int) {
- onBackPressedCallback.isEnabled = newState == STATE_EXPANDED
- when (newState) {
- STATE_EXPANDED -> {
- onPanelExpanded()
- if (PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics) {
- keepScreenOn(true)
- }
- }
-
- STATE_COLLAPSED -> {
- onPanelCollapsed()
- if ((PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics) || !PreferenceUtil.isScreenOnEnabled) {
- keepScreenOn(false)
- }
- }
-
- STATE_SETTLING, STATE_DRAGGING -> {
- if (fromNotification) {
- binding.navigationView.bringToFront()
- fromNotification = false
- }
- }
-
- STATE_HIDDEN -> {
- MusicPlayerRemote.clearQueue()
- }
-
- else -> {
- logD("Do a flip")
- }
}
}
}
}
- fun getBottomSheetBehavior() = bottomSheetBehavior
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- if (!hasPermissions()) {
- startActivity(Intent(this, PermissionActivity::class.java))
- finish()
- }
- binding = SlidingMusicPanelLayoutBinding.inflate(layoutInflater)
- setContentView(binding.root)
- binding.root.setOnApplyWindowInsetsListener { _, insets ->
- windowInsets = WindowInsetsCompat.toWindowInsetsCompat(insets)
- insets
- }
+ setContentView(createContentView())
+
chooseFragmentForTheme()
setupSlidingUpPanel()
- setupBottomSheet()
- updateColor()
- if (!PreferenceUtil.materialYou) {
- binding.slidingPanel.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
- navigationView.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
- }
- navigationBarColor = surfaceColor()
+ updateTabs()
- onBackPressedDispatcher.addCallback(onBackPressedCallback)
- }
+ bottomSheetBehavior = BottomSheetBehavior.from(slidingPanel)
- private fun setupBottomSheet() {
- bottomSheetBehavior = from(binding.slidingPanel)
- bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
- bottomSheetBehavior.isHideable = PreferenceUtil.swipeDownToDismiss
- bottomSheetBehavior.significantVelocityThreshold = 300
- setMiniPlayerAlphaProgress(0F)
+ val themeColor = ATHUtil.resolveColor(this, android.R.attr.windowBackground, Color.GRAY)
+ dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
}
override fun onResume() {
super.onResume()
- PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
- if (nowPlayingScreen != PreferenceUtil.nowPlayingScreen) {
+ if (currentNowPlayingScreen != PreferenceUtil.getInstance(this).nowPlayingScreen) {
postRecreate()
}
- if (bottomSheetBehavior.state == STATE_EXPANDED) {
+ bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
+
+ if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) {
setMiniPlayerAlphaProgress(1f)
}
}
@@ -228,354 +112,246 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
override fun onDestroy() {
super.onDestroy()
bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList)
- PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)
+ if (navigationBarColorAnimator != null) navigationBarColorAnimator?.cancel() // just in case
}
- override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
- when (key) {
- SWIPE_DOWN_DISMISS -> {
- bottomSheetBehavior.isHideable = PreferenceUtil.swipeDownToDismiss
- }
-
- TOGGLE_ADD_CONTROLS -> {
- miniPlayerFragment?.setUpButtons()
- }
-
- NOW_PLAYING_SCREEN_ID -> {
- chooseFragmentForTheme()
- binding.slidingPanel.updateLayoutParams {
- height = if (nowPlayingScreen != Peek) {
- ViewGroup.LayoutParams.MATCH_PARENT
- } else {
- ViewGroup.LayoutParams.WRAP_CONTENT
- }
- onServiceConnected()
- }
- }
-
- ALBUM_COVER_TRANSFORM, CAROUSEL_EFFECT,
- ALBUM_COVER_STYLE, TOGGLE_VOLUME, EXTRA_SONG_INFO, CIRCLE_PLAY_BUTTON,
- -> {
- chooseFragmentForTheme()
- onServiceConnected()
- }
-
- SWIPE_ANYWHERE_NOW_PLAYING -> {
- playerFragment.addSwipeDetector()
- }
-
- ADAPTIVE_COLOR_APP -> {
- if (PreferenceUtil.nowPlayingScreen in listOf(Normal, Material, Flat)) {
- chooseFragmentForTheme()
- onServiceConnected()
- }
- }
-
- LIBRARY_CATEGORIES -> {
- updateTabs()
- }
-
- TAB_TEXT_MODE -> {
- navigationView.labelVisibilityMode = PreferenceUtil.tabTitleMode
- }
-
- TOGGLE_FULL_SCREEN -> {
- recreate()
- }
-
- SCREEN_ON_LYRICS -> {
- keepScreenOn(bottomSheetBehavior.state == STATE_EXPANDED && PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics || PreferenceUtil.isScreenOnEnabled)
- }
-
- KEEP_SCREEN_ON -> {
- maybeSetScreenOn()
- }
- }
+ protected fun wrapSlidingMusicPanel(@LayoutRes resId: Int): View {
+ val slidingMusicPanelLayout = layoutInflater.inflate(R.layout.sliding_music_panel_layout, null)
+ val contentContainer = slidingMusicPanelLayout.findViewById(R.id.mainContentFrame)
+ layoutInflater.inflate(resId, contentContainer)
+ return slidingMusicPanelLayout
}
- fun collapsePanel() {
- bottomSheetBehavior.state = STATE_COLLAPSED
+ private fun collapsePanel() {
+ bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
fun expandPanel() {
- bottomSheetBehavior.state = STATE_EXPANDED
+ bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
+ setMiniPlayerAlphaProgress(1f)
}
private fun setMiniPlayerAlphaProgress(progress: Float) {
- if (progress < 0) return
+ if (miniPlayerFragment?.view == null) return
val alpha = 1 - progress
- miniPlayerFragment?.view?.alpha = 1 - (progress / 0.2F)
- miniPlayerFragment?.view?.isGone = alpha == 0f
- if (!isLandscape) {
- binding.navigationView.translationY = progress * 500
- binding.navigationView.alpha = alpha
- }
- binding.playerFragmentContainer.alpha = (progress - 0.2F) / 0.2F
- }
+ miniPlayerFragment?.view?.alpha = alpha
+ // necessary to make the views below clickable
+ miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE
- private fun animateNavigationBarColor(color: Int) {
- if (VersionUtils.hasOreo()) return
- navigationBarColorAnimator?.cancel()
- navigationBarColorAnimator = ValueAnimator
- .ofArgb(window.navigationBarColor, color).apply {
- duration = ViewUtil.RETRO_MUSIC_ANIM_TIME.toLong()
- interpolator = PathInterpolator(0.4f, 0f, 1f, 1f)
- addUpdateListener { animation: ValueAnimator ->
- setNavigationBarColorPreOreo(
- animation.animatedValue as Int
- )
- }
- start()
- }
+ bottomNavigationView.translationY = progress * 500
+ //bottomNavigationView.alpha = alpha
}
open fun onPanelCollapsed() {
- setMiniPlayerAlphaProgress(0F)
// restore values
- animateNavigationBarColor(surfaceColor())
- setLightStatusBarAuto()
- setLightNavigationBarAuto()
- setTaskDescriptionColor(taskColor)
- //playerFragment?.onHide()
+ super.setLightStatusbar(lightStatusBar)
+ super.setTaskDescriptionColor(taskColor)
+ super.setNavigationbarColor(navigationBarColor)
+ super.setLightNavigationBar(lightNavigationBar)
+
+
+ playerFragment?.setMenuVisibility(false)
+ playerFragment?.userVisibleHint = false
+ playerFragment?.onHide()
}
open fun onPanelExpanded() {
- setMiniPlayerAlphaProgress(1F)
+ val playerFragmentColor = playerFragment!!.paletteColor
+ super.setTaskDescriptionColor(playerFragmentColor)
+
+ playerFragment?.setMenuVisibility(true)
+ playerFragment?.userVisibleHint = true
+ playerFragment?.onShow()
onPaletteColorChanged()
- //playerFragment?.onShow()
}
private fun setupSlidingUpPanel() {
- binding.slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object :
- ViewTreeObserver.OnGlobalLayoutListener {
+ slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
- binding.slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
- if (nowPlayingScreen != Peek) {
- binding.slidingPanel.updateLayoutParams {
- height = ViewGroup.LayoutParams.MATCH_PARENT
- }
+ slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
+ if (currentNowPlayingScreen != PEAK) {
+ val params = slidingPanel.layoutParams as ViewGroup.LayoutParams
+ params.height = ViewGroup.LayoutParams.MATCH_PARENT
+ slidingPanel.layoutParams = params
}
when (panelState) {
- STATE_EXPANDED -> onPanelExpanded()
- STATE_COLLAPSED -> onPanelCollapsed()
- else -> {
- // playerFragment!!.onHide()
- }
+ BottomSheetBehavior.STATE_EXPANDED -> onPanelExpanded()
+ BottomSheetBehavior.STATE_COLLAPSED -> onPanelCollapsed()
+ else -> playerFragment!!.onHide()
}
}
})
}
- val navigationView get() = binding.navigationView
+ fun toggleBottomNavigationView(toggle: Boolean) {
+ bottomNavigationView.visibility = if (toggle) View.GONE else View.VISIBLE
+ }
- val slidingPanel get() = binding.slidingPanel
+ fun getBottomNavigationView(): BottomNavigationBarTinted {
+ return bottomNavigationView
+ }
- val isBottomNavVisible get() = navigationView.isVisible && navigationView is BottomNavigationView
+ private fun hideBottomBar(hide: Boolean) {
+ val heightOfBar = resources.getDimensionPixelSize(R.dimen.mini_player_height)
+ val heightOfBarWithTabs = resources.getDimensionPixelSize(R.dimen.mini_player_height_expanded)
+
+ if (hide) {
+ bottomSheetBehavior.isHideable = true
+ bottomSheetBehavior.peekHeight = 0
+ collapsePanel()
+ bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat()
+ } else {
+ if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
+ slidingPanel.cardElevation = DensityUtil.dip2px(this, 10f).toFloat()
+ bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat()
+ bottomSheetBehavior.isHideable = false
+ bottomSheetBehavior.peekHeight = if (bottomNavigationView.visibility == View.VISIBLE) heightOfBarWithTabs else heightOfBar
+ }
+ }
+ }
+
+ fun setBottomBarVisibility(gone: Int) {
+ bottomNavigationView.visibility = gone
+ hideBottomBar(false)
+ }
+
+ private fun chooseFragmentForTheme() {
+ currentNowPlayingScreen = PreferenceUtil.getInstance(this).nowPlayingScreen
+
+ val fragment: Fragment = when (currentNowPlayingScreen) {
+ BLUR -> BlurPlayerFragment()
+ ADAPTIVE -> AdaptiveFragment()
+ NORMAL -> PlayerFragment()
+ CARD -> CardFragment()
+ BLUR_CARD -> CardBlurFragment()
+ FIT -> FitFragment()
+ FLAT -> FlatPlayerFragment()
+ FULL -> FullPlayerFragment()
+ PLAIN -> PlainPlayerFragment()
+ SIMPLE -> SimplePlayerFragment()
+ MATERIAL -> MaterialFragment()
+ COLOR -> ColorFragment()
+ TINY -> TinyPlayerFragment()
+ PEAK -> PeakPlayerFragment()
+ else -> PlayerFragment()
+ } // must implement AbsPlayerFragment
+ supportFragmentManager.beginTransaction().replace(R.id.playerFragmentContainer, fragment)
+ .commit()
+ supportFragmentManager.executePendingTransactions()
+
+ playerFragment = supportFragmentManager.findFragmentById(R.id.playerFragmentContainer) as AbsPlayerFragment
+ miniPlayerFragment = supportFragmentManager.findFragmentById(R.id.miniPlayerFragment) as MiniPlayerFragment
+ miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
+ }
override fun onServiceConnected() {
super.onServiceConnected()
- hideBottomSheet(false)
+ if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
+ slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
+ override fun onGlobalLayout() {
+ slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
+ hideBottomBar(false)
+ }
+ })
+ } // don't call hideBottomBar(true) here as it causes a bug with the SlidingUpPanelLayout
}
override fun onQueueChanged() {
super.onQueueChanged()
- // Mini player should be hidden in Playing Queue
- // it may pop up if hideBottomSheet is called
- if (currentFragment(R.id.fragment_container) !is PlayingQueueFragment) {
- hideBottomSheet(MusicPlayerRemote.playingQueue.isEmpty())
- }
+ hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
}
- private fun handleBackPress(): Boolean {
- if (panelState == STATE_EXPANDED) {
+ override fun onBackPressed() {
+ if (!handleBackPress()) super.onBackPressed()
+ }
+
+ open fun handleBackPress(): Boolean {
+ if (bottomSheetBehavior.peekHeight != 0 && playerFragment!!.onBackPressed()) return true
+ if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
collapsePanel()
return true
}
return false
}
- private fun onPaletteColorChanged() {
- if (panelState == STATE_EXPANDED) {
- navigationBarColor = surfaceColor()
- setTaskDescColor(paletteColor)
- val isColorLight = paletteColor.isColorLight
- if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat || nowPlayingScreen == Material)) {
- setLightNavigationBar(true)
- setLightStatusBar(isColorLight)
- } else if (nowPlayingScreen == Card || nowPlayingScreen == Blur || nowPlayingScreen == BlurCard) {
- animateNavigationBarColor(Color.BLACK)
- navigationBarColor = Color.BLACK
- setLightStatusBar(false)
- setLightNavigationBar(true)
- } else if (nowPlayingScreen == Color || nowPlayingScreen == Tiny || nowPlayingScreen == Gradient) {
- animateNavigationBarColor(paletteColor)
- navigationBarColor = paletteColor
- setLightNavigationBar(isColorLight)
- setLightStatusBar(isColorLight)
- } else if (nowPlayingScreen == Full) {
- animateNavigationBarColor(paletteColor)
- navigationBarColor = paletteColor
- setLightNavigationBar(isColorLight)
- setLightStatusBar(false)
- } else if (nowPlayingScreen == Classic) {
- setLightStatusBar(false)
- } else if (nowPlayingScreen == Fit) {
- setLightStatusBar(false)
+ override fun onPaletteColorChanged() {
+ if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
+ val paletteColor = playerFragment!!.paletteColor
+ super.setTaskDescriptionColor(paletteColor)
+
+ val isColorLight = ColorUtil.isColorLight(paletteColor)
+
+ if (PreferenceUtil.getInstance(this).adaptiveColor && (currentNowPlayingScreen == NORMAL || currentNowPlayingScreen == FLAT)) {
+ super.setLightNavigationBar(true)
+ super.setLightStatusbar(isColorLight)
+ } else if (currentNowPlayingScreen == FULL || currentNowPlayingScreen == CARD || currentNowPlayingScreen == FIT || currentNowPlayingScreen == BLUR || currentNowPlayingScreen == BLUR_CARD) {
+ super.setLightStatusbar(false)
+ super.setLightNavigationBar(true)
+ } else if (currentNowPlayingScreen == COLOR || currentNowPlayingScreen == TINY) {
+ super.setNavigationbarColor(paletteColor)
+ super.setLightNavigationBar(isColorLight)
+ super.setLightStatusbar(isColorLight)
+ } else {
+ super.setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, android.R.attr.windowBackground)))
+ super.setLightNavigationBar(true)
}
}
}
- private fun setTaskDescColor(color: Int) {
- taskColor = color
- if (panelState == STATE_COLLAPSED) {
- setTaskDescriptionColor(color)
+ override fun setLightStatusbar(enabled: Boolean) {
+ lightStatusBar = enabled
+ if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
+ super.setLightStatusbar(enabled)
}
}
- fun updateTabs() {
- binding.navigationView.menu.clear()
- val currentTabs: List = PreferenceUtil.libraryCategory
+ override fun setLightNavigationBar(enabled: Boolean) {
+ lightNavigationBar = enabled
+ if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
+ super.setLightNavigationBar(enabled)
+ }
+ }
+
+ override fun setNavigationbarColor(color: Int) {
+ navigationBarColor = color
+ if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
+ if (navigationBarColorAnimator != null) navigationBarColorAnimator!!.cancel()
+ super.setNavigationbarColor(color)
+ }
+ }
+
+ override fun setTaskDescriptionColor(color: Int) {
+ taskColor = color
+ if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
+ super.setTaskDescriptionColor(color)
+ }
+ }
+
+ private fun updateTabs() {
+ bottomNavigationView.menu.clear()
+ val currentTabs: List = PreferenceUtil.getInstance(this).libraryCategoryInfos
for (tab in currentTabs) {
if (tab.visible) {
val menu = tab.category
- binding.navigationView.menu.add(0, menu.id, 0, menu.stringRes)
- .setIcon(menu.icon)
+ bottomNavigationView.menu.add(0, menu.id, 0, menu.stringRes).setIcon(menu.icon)
}
}
- if (binding.navigationView.menu.size() == 1) {
- isInOneTabMode = true
- binding.navigationView.isVisible = false
- } else {
- isInOneTabMode = false
+ print("Tabs -> ${currentTabs.size}")
+ if (currentTabs.size <= 1) {
+ toggleBottomNavigationView(true)
}
}
- private fun updateColor() {
- libraryViewModel.paletteColor.observe(this) { color ->
- this.paletteColor = color
- onPaletteColorChanged()
- }
- }
-
- fun setBottomNavVisibility(
- visible: Boolean,
- animate: Boolean = false,
- hideBottomSheet: Boolean = MusicPlayerRemote.playingQueue.isEmpty(),
- ) {
- if (!ViewCompat.isLaidOut(navigationView)) {
- return
- }
- if (isInOneTabMode) {
- hideBottomSheet(
- hide = hideBottomSheet,
- animate = animate,
- isBottomNavVisible = false
- )
- return
- }
- if (visible xor navigationView.isVisible) {
- val mAnimate = animate && bottomSheetBehavior.state == STATE_COLLAPSED
- if (mAnimate) {
- if (visible) {
- binding.navigationView.bringToFront()
- binding.navigationView.show()
- } else {
- binding.navigationView.hide()
- }
- } else {
- binding.navigationView.isVisible = visible
- if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
- binding.navigationView.bringToFront()
+ /*override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
+ if (ev?.action == MotionEvent.ACTION_DOWN) {
+ if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
+ val outRect = Rect()
+ slidingPanel.getGlobalVisibleRect(outRect)
+ if (!outRect.contains(ev.rawX.toInt(), ev.rawY.toInt())) {
+ bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
}
- hideBottomSheet(
- hide = hideBottomSheet,
- animate = animate,
- isBottomNavVisible = visible && navigationView is BottomNavigationView
- )
- }
-
- fun hideBottomSheet(
- hide: Boolean,
- animate: Boolean = false,
- isBottomNavVisible: Boolean = navigationView.isVisible && navigationView is BottomNavigationView,
- ) {
- val heightOfBar = windowInsets.getBottomInsets() + dip(R.dimen.mini_player_height)
- val heightOfBarWithTabs = heightOfBar + dip(R.dimen.bottom_nav_height)
- if (hide) {
- bottomSheetBehavior.peekHeight = -windowInsets.getBottomInsets()
- bottomSheetBehavior.state = STATE_COLLAPSED
- libraryViewModel.setFabMargin(
- this,
- if (isBottomNavVisible) dip(R.dimen.bottom_nav_height) else 0
- )
- } else {
- if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
- binding.slidingPanel.elevation = 0F
- binding.navigationView.elevation = 5F
- if (isBottomNavVisible) {
- logD("List")
- if (animate) {
- bottomSheetBehavior.peekHeightAnimate(heightOfBarWithTabs)
- } else {
- bottomSheetBehavior.peekHeight = heightOfBarWithTabs
- }
- libraryViewModel.setFabMargin(
- this,
- dip(R.dimen.bottom_nav_mini_player_height)
- )
- } else {
- logD("Details")
- if (animate) {
- bottomSheetBehavior.peekHeightAnimate(heightOfBar).doOnEnd {
- binding.slidingPanel.bringToFront()
- }
- } else {
- bottomSheetBehavior.peekHeight = heightOfBar
- binding.slidingPanel.bringToFront()
- }
- libraryViewModel.setFabMargin(this, dip(R.dimen.mini_player_height))
- }
- }
- }
- }
-
- fun setAllowDragging(allowDragging: Boolean) {
- bottomSheetBehavior.isDraggable = allowDragging
- hideBottomSheet(false)
- }
-
- private fun chooseFragmentForTheme() {
- nowPlayingScreen = PreferenceUtil.nowPlayingScreen
-
- val fragment: AbsPlayerFragment = when (nowPlayingScreen) {
- Blur -> BlurPlayerFragment()
- Adaptive -> AdaptiveFragment()
- Normal -> PlayerFragment()
- Card -> CardFragment()
- BlurCard -> CardBlurFragment()
- Fit -> FitFragment()
- Flat -> FlatPlayerFragment()
- Full -> FullPlayerFragment()
- Plain -> PlainPlayerFragment()
- Simple -> SimplePlayerFragment()
- Material -> MaterialFragment()
- Color -> ColorFragment()
- Gradient -> GradientPlayerFragment()
- Tiny -> TinyPlayerFragment()
- Peek -> PeekPlayerFragment()
- Circle -> CirclePlayerFragment()
- Classic -> ClassicPlayerFragment()
- MD3 -> MD3PlayerFragment()
- else -> PlayerFragment()
- } // must extend AbsPlayerFragment
- supportFragmentManager.commit {
- replace(R.id.playerFragmentContainer, fragment)
- }
- supportFragmentManager.executePendingTransactions()
- playerFragment = whichFragment(R.id.playerFragmentContainer)
- miniPlayerFragment = whichFragment(R.id.miniPlayerFragment)
- miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
- }
-}
+ return super.dispatchTouchEvent(ev)
+ }*/
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt
index 32b025f01..96bace4d9 100644
--- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt
@@ -1,69 +1,44 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.activities.base
-import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Handler
-import android.os.Looper
import android.view.KeyEvent
-import androidx.appcompat.app.AppCompatDelegate
-import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
-import androidx.core.os.LocaleListCompat
+import android.view.View
+import android.view.WindowManager
+import androidx.annotation.ColorInt
+import androidx.core.content.ContextCompat
+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.TintHelper
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.theme.getNightMode
-import code.name.monkey.retromusic.util.theme.getThemeResValue
+import code.name.monkey.retromusic.util.RetroUtil
+import code.name.monkey.retromusic.util.ThemeManager
abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
- private val handler = Handler(Looper.getMainLooper())
+ private val handler = Handler()
override fun onCreate(savedInstanceState: Bundle?) {
- updateLocale()
- updateTheme()
+ setTheme(ThemeManager.getThemeResValue(this))
hideStatusBar()
super.onCreate(savedInstanceState)
- setEdgeToEdgeOrImmersive()
- maybeSetScreenOn()
- setLightNavigationBarAuto()
- setLightStatusBarAuto(surfaceColor())
- if (VersionUtils.hasQ()) {
- window.decorView.isForceDarkAllowed = false
- }
+ setImmersiveFullscreen()
+ registerSystemUiVisibility()
+ toggleScreenOn()
}
- private fun updateTheme() {
- setTheme(getThemeResValue())
- if (PreferenceUtil.materialYou) {
- setDefaultNightMode(getNightMode())
- }
-
- if (PreferenceUtil.isCustomFont) {
- setTheme(R.style.FontThemeOverlay)
- }
- }
-
- private fun updateLocale() {
- val localeCode = PreferenceUtil.languageCode
- if (PreferenceUtil.isLocaleAutoStorageEnabled) {
- AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(localeCode))
- PreferenceUtil.isLocaleAutoStorageEnabled = true
+ private fun toggleScreenOn() {
+ if (PreferenceUtil.getInstance(this).isScreenOnEnabled) {
+ window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+ } else {
+ window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
@@ -78,6 +53,122 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
}
}
+ fun hideStatusBar() {
+ hideStatusBar(PreferenceUtil.getInstance(this).fullScreenMode)
+ }
+
+ private fun hideStatusBar(fullscreen: Boolean) {
+ val statusBar = window.decorView.rootView.findViewById(R.id.status_bar)
+ if (statusBar != null) {
+ statusBar.visibility = if (fullscreen) View.GONE else View.VISIBLE
+ }
+ }
+
+ private fun changeBackgroundShape() {
+ var background: Drawable? = if (PreferenceUtil.getInstance(this).isRoundCorners)
+ ContextCompat.getDrawable(this, R.drawable.round_window)
+ else ContextCompat.getDrawable(this, R.drawable.square_window)
+ background = TintHelper.createTintedDrawable(background, ATHUtil.resolveColor(this, android.R.attr.windowBackground))
+ window.setBackgroundDrawable(background)
+ }
+
+ fun setDrawUnderStatusBar() {
+ RetroUtil.setAllowDrawUnderStatusBar(window)
+ }
+
+ fun setDrawUnderNavigationBar() {
+ RetroUtil.setAllowDrawUnderNavigationBar(window)
+ }
+
+ /**
+ * 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)
+ */
+ fun setStatusbarColor(color: Int) {
+ val statusBar = window.decorView.rootView.findViewById(R.id.status_bar)
+ if (statusBar != null) {
+ when {
+ VersionUtils.hasMarshmallow() -> statusBar.setBackgroundColor(color)
+ VersionUtils.hasLollipop() -> statusBar.setBackgroundColor(ColorUtil.darkenColor(color))
+ else -> statusBar.setBackgroundColor(color)
+ }
+ } else {
+ when {
+ VersionUtils.hasMarshmallow() -> window.statusBarColor = color
+ else -> window.statusBarColor = ColorUtil.darkenColor(color)
+ }
+ }
+ setLightStatusbarAuto(ATHUtil.resolveColor(this, R.attr.colorSurface))
+ }
+
+ fun setStatusbarColorAuto() {
+ // we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat
+ setStatusbarColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
+ setLightStatusbarAuto(ATHUtil.resolveColor(this, R.attr.colorSurface))
+ }
+
+ open fun setTaskDescriptionColor(@ColorInt color: Int) {
+ ATH.setTaskDescriptionColor(this, color)
+ }
+
+ fun setTaskDescriptionColorAuto() {
+ setTaskDescriptionColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
+ }
+
+ open fun setNavigationbarColor(color: Int) {
+ if (ThemeStore.coloredNavigationBar(this)) {
+ ATH.setNavigationbarColor(this, color)
+ } else {
+ ATH.setNavigationbarColor(this, Color.BLACK)
+ }
+ }
+
+ fun setNavigationbarColorAuto() {
+ setNavigationbarColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
+ }
+
+ open fun setLightStatusbar(enabled: Boolean) {
+ ATH.setLightStatusbar(this, enabled)
+ }
+
+ fun setLightStatusbarAuto(bgColor: Int) {
+ setLightStatusbar(ColorUtil.isColorLight(bgColor))
+ }
+
+ open fun setLightNavigationBar(enabled: Boolean) {
+ if (!ATHUtil.isWindowBackgroundDark(this) and ThemeStore.coloredNavigationBar(this)) {
+ ATH.setLightNavigationbar(this, enabled)
+ }
+ }
+
+ private fun registerSystemUiVisibility() {
+ val decorView = window.decorView
+ decorView.setOnSystemUiVisibilityChangeListener { visibility ->
+ if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
+ setImmersiveFullscreen()
+ }
+ }
+ }
+
+ private fun unregisterSystemUiVisibility() {
+ val decorView = window.decorView
+ decorView.setOnSystemUiVisibilityChangeListener(null)
+ }
+
+ private fun setImmersiveFullscreen() {
+ val flags = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
+
+ if (PreferenceUtil.getInstance(this).fullScreenMode) {
+ window.decorView.systemUiVisibility = flags
+ }
+ }
+
+ private fun exitFullscreen() {
+ window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
+ }
+
override fun run() {
setImmersiveFullscreen()
}
@@ -89,6 +180,7 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
public override fun onDestroy() {
super.onDestroy()
+ unregisterSystemUiVisibility()
exitFullscreen()
}
@@ -98,9 +190,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
handler.postDelayed(this, 500)
}
return super.onKeyDown(keyCode, event)
- }
- override fun attachBaseContext(newBase: Context?) {
- super.attachBaseContext(newBase)
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt
index e99881953..a8a578094 100644
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt
@@ -1,91 +1,331 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.activities.bugreport
+import android.app.Activity
+import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
+import android.content.Context
import android.content.Intent
+import android.net.Uri
import android.os.Bundle
+import android.text.TextUtils
import android.view.MenuItem
-import androidx.core.content.getSystemService
-import androidx.core.net.toUri
+import android.view.inputmethod.EditorInfo
+import android.widget.Toast
+import androidx.annotation.StringDef
+import androidx.annotation.StringRes
+import androidx.appcompat.app.AlertDialog
+import code.name.monkey.appthemehelper.ThemeStore
+import code.name.monkey.appthemehelper.util.ATHUtil
+import code.name.monkey.appthemehelper.util.MaterialUtil
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.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.activities.bugreport.model.DeviceInfo
-import code.name.monkey.retromusic.databinding.ActivityBugReportBinding
-import code.name.monkey.retromusic.extensions.accentColor
-import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
-import code.name.monkey.retromusic.extensions.showToast
+import code.name.monkey.retromusic.activities.bugreport.model.Report
+import code.name.monkey.retromusic.activities.bugreport.model.github.ExtraInfo
+import code.name.monkey.retromusic.activities.bugreport.model.github.GithubLogin
+import code.name.monkey.retromusic.activities.bugreport.model.github.GithubTarget
+import code.name.monkey.retromusic.misc.DialogAsyncTask
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.callbacks.onCancel
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+import com.google.android.material.textfield.TextInputLayout
+import kotlinx.android.synthetic.main.activity_bug_report.*
+import kotlinx.android.synthetic.main.bug_report_card_device_info.*
+import kotlinx.android.synthetic.main.bug_report_card_report.*
+import org.eclipse.egit.github.core.Issue
+import org.eclipse.egit.github.core.client.GitHubClient
+import org.eclipse.egit.github.core.client.RequestException
+import org.eclipse.egit.github.core.service.IssueService
+import java.io.IOException
+
+private const val RESULT_SUCCESS = "RESULT_OK"
+private const val RESULT_BAD_CREDENTIALS = "RESULT_BAD_CREDENTIALS"
+private const val RESULT_INVALID_TOKEN = "RESULT_INVALID_TOKEN"
+private const val RESULT_ISSUES_NOT_ENABLED = "RESULT_ISSUES_NOT_ENABLED"
+private const val RESULT_UNKNOWN = "RESULT_UNKNOWN"
+
+@StringDef(
+ RESULT_SUCCESS,
+ RESULT_BAD_CREDENTIALS,
+ RESULT_INVALID_TOKEN,
+ RESULT_ISSUES_NOT_ENABLED,
+ RESULT_UNKNOWN
+)
+@Retention(AnnotationRetention.SOURCE)
+private annotation class Result
open class BugReportActivity : AbsThemeActivity() {
- private lateinit var binding: ActivityBugReportBinding
private var deviceInfo: DeviceInfo? = null
override fun onCreate(savedInstanceState: Bundle?) {
+ setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
- binding = ActivityBugReportBinding.inflate(layoutInflater)
- setContentView(binding.root)
+ setContentView(R.layout.activity_bug_report)
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
initViews()
- if (title.isNullOrEmpty()) setTitle(R.string.report_an_issue)
+ if (TextUtils.isEmpty(title)) setTitle(R.string.report_an_issue)
deviceInfo = DeviceInfo(this)
- binding.cardDeviceInfo.airTextDeviceInfo.text = deviceInfo.toString()
+ airTextDeviceInfo.text = deviceInfo.toString()
}
private fun initViews() {
- val accentColor = accentColor()
- setSupportActionBar(binding.toolbar)
- ToolbarContentTintHelper.colorBackButton(binding.toolbar)
+ val accentColor = ThemeStore.accentColor(this)
+ val primaryColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
+ toolbar.setBackgroundColor(primaryColor)
+ setSupportActionBar(toolbar)
+ ToolbarContentTintHelper.colorBackButton(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ TintHelper.setTintAuto(optionUseAccount, accentColor, false)
+ optionUseAccount?.setOnClickListener {
+ inputTitle.isEnabled = true
+ inputDescription.isEnabled = true
+ inputUsername.isEnabled = true
+ inputPassword.isEnabled = true
- binding.cardDeviceInfo.airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() }
+ optionAnonymous.isChecked = false
+ sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
+ override fun onHidden(fab: FloatingActionButton?) {
+ super.onHidden(fab)
+ sendFab.setImageResource(R.drawable.ic_send_white_24dp)
+ sendFab.show()
+ }
+ })
+ }
+ TintHelper.setTintAuto(optionAnonymous, accentColor, false)
+ optionAnonymous.setOnClickListener {
+ inputTitle.isEnabled = false
+ inputDescription.isEnabled = false
+ inputUsername.isEnabled = false
+ inputPassword.isEnabled = false
- TintHelper.setTintAuto(binding.sendFab, accentColor, true)
- binding.sendFab.setOnClickListener { reportIssue() }
+ optionUseAccount.isChecked = false
+ sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
+ override fun onHidden(fab: FloatingActionButton?) {
+ super.onHidden(fab)
+ sendFab.setImageResource(R.drawable.ic_open_in_browser_white_24dp)
+ sendFab.show()
+ }
+ })
+ }
+
+ inputPassword.setOnEditorActionListener { _, actionId, _ ->
+ if (actionId == EditorInfo.IME_ACTION_SEND) {
+ reportIssue()
+ return@setOnEditorActionListener true
+ }
+ false
+ }
+
+ airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() }
+
+ TintHelper.setTintAuto(sendFab, accentColor, true)
+ sendFab.setOnClickListener { reportIssue() }
+
+ MaterialUtil.setTint(inputLayoutTitle, false)
+ MaterialUtil.setTint(inputLayoutDescription, false)
+ MaterialUtil.setTint(inputLayoutUsername, false)
+ MaterialUtil.setTint(inputLayoutPassword, false)
}
private fun reportIssue() {
- copyDeviceInfoToClipBoard()
- val i = Intent(Intent.ACTION_VIEW)
- i.data = ISSUE_TRACKER_LINK.toUri()
- i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
- startActivity(i)
+ if (optionUseAccount.isChecked) {
+ if (!validateInput()) return
+ val username = inputUsername.text.toString()
+ val password = inputPassword.text.toString()
+ sendBugReport(GithubLogin(username, password))
+ } else {
+ copyDeviceInfoToClipBoard()
+
+ val i = Intent(Intent.ACTION_VIEW)
+ i.data = Uri.parse(ISSUE_TRACKER_LINK)
+ i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ startActivity(i)
+ }
}
private fun copyDeviceInfoToClipBoard() {
- val clipboard = getSystemService()
+ val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.device_info), deviceInfo?.toMarkdown())
- clipboard?.setPrimaryClip(clip)
- showToast(R.string.copied_device_info_to_clipboard)
+ clipboard.setPrimaryClip(clip)
+ Toast.makeText(
+ this@BugReportActivity,
+ R.string.copied_device_info_to_clipboard,
+ Toast.LENGTH_LONG
+ ).show()
}
+ private fun validateInput(): Boolean {
+ var hasErrors = false
+
+ if (optionUseAccount.isChecked) {
+ if (TextUtils.isEmpty(inputUsername.text)) {
+ setError(inputLayoutUsername, R.string.bug_report_no_username)
+ hasErrors = true
+ } else {
+ removeError(inputLayoutUsername)
+ }
+
+ if (TextUtils.isEmpty(inputPassword.text)) {
+ setError(inputLayoutPassword, R.string.bug_report_no_password)
+ hasErrors = true
+ } else {
+ removeError(inputLayoutPassword)
+ }
+ }
+
+ if (TextUtils.isEmpty(inputTitle.text)) {
+ setError(inputLayoutTitle, R.string.bug_report_no_title)
+ hasErrors = true
+ } else {
+ removeError(inputLayoutTitle)
+ }
+
+ if (TextUtils.isEmpty(inputDescription.text)) {
+ setError(inputLayoutDescription, R.string.bug_report_no_description)
+ hasErrors = true
+ } else {
+ removeError(inputLayoutDescription)
+ }
+
+ return !hasErrors
+ }
+
+ private fun setError(editTextLayout: TextInputLayout, @StringRes errorRes: Int) {
+ editTextLayout.error = getString(errorRes)
+ }
+
+ private fun removeError(editTextLayout: TextInputLayout) {
+ editTextLayout.error = null
+ }
+
+ private fun sendBugReport(login: GithubLogin) {
+ if (!validateInput()) return
+
+ val bugTitle = inputTitle.text.toString()
+ val bugDescription = inputDescription.text.toString()
+
+ val extraInfo = ExtraInfo()
+ onSaveExtraInfo()
+
+ val report = Report(bugTitle, bugDescription, deviceInfo, extraInfo)
+ val target = GithubTarget("h4h13", "RetroMusicPlayer")
+
+ ReportIssueAsyncTask.report(this, report, target, login)
+ }
+
+ private fun onSaveExtraInfo() {}
+
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
- onBackPressedDispatcher.onBackPressed()
+ onBackPressed()
}
return super.onOptionsItemSelected(item)
}
+ private class ReportIssueAsyncTask private constructor(
+ activity: Activity,
+ private val report: Report,
+ private val target: GithubTarget,
+ private val login: GithubLogin
+ ) : DialogAsyncTask(activity) {
+ override fun createDialog(context: Context): Dialog {
+ return AlertDialog.Builder(context).show()
+ }
+
+ @Result
+ override fun doInBackground(vararg params: Void): String {
+ val client: GitHubClient = if (login.shouldUseApiToken()) {
+ GitHubClient().setOAuth2Token(login.apiToken)
+ } else {
+ GitHubClient().setCredentials(login.username, login.password)
+ }
+
+ val issue = Issue().setTitle(report.title).setBody(report.description)
+ try {
+ IssueService(client).createIssue(target.username, target.repository, issue)
+ return RESULT_SUCCESS
+ } catch (e: RequestException) {
+ return when (e.status) {
+ STATUS_BAD_CREDENTIALS -> {
+ if (login.shouldUseApiToken()) RESULT_INVALID_TOKEN else RESULT_BAD_CREDENTIALS
+ }
+ STATUS_ISSUES_NOT_ENABLED -> RESULT_ISSUES_NOT_ENABLED
+ else -> {
+ e.printStackTrace()
+ RESULT_UNKNOWN
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ return RESULT_UNKNOWN
+ }
+
+ }
+
+ override fun onPostExecute(@Result result: String) {
+ super.onPostExecute(result)
+
+ val context = context ?: return
+
+ when (result) {
+ RESULT_SUCCESS -> tryToFinishActivity()
+ RESULT_BAD_CREDENTIALS -> MaterialDialog(context).show {
+ title(R.string.bug_report_failed)
+ message(R.string.bug_report_failed_wrong_credentials)
+ positiveButton(android.R.string.ok)
+ }
+ RESULT_INVALID_TOKEN -> MaterialDialog(context).show {
+ title(R.string.bug_report_failed)
+ message(R.string.bug_report_failed_invalid_token)
+ positiveButton(android.R.string.ok)
+ }
+ RESULT_ISSUES_NOT_ENABLED -> MaterialDialog(context).show {
+ title(R.string.bug_report_failed)
+ message(R.string.bug_report_failed_issues_not_available)
+ positiveButton(android.R.string.ok)
+ }
+ else -> MaterialDialog(context).show {
+ title(R.string.bug_report_failed)
+ message(R.string.bug_report_failed_unknown)
+ positiveButton(android.R.string.ok) { tryToFinishActivity() }
+ onCancel { tryToFinishActivity() }
+ }
+ }
+ }
+
+ private fun tryToFinishActivity() {
+ val context = context
+ if (context is Activity && !context.isFinishing) {
+ context.finish()
+ }
+ }
+
+ companion object {
+
+ fun report(
+ activity: Activity,
+ report: Report,
+ target: GithubTarget,
+ login: GithubLogin
+ ) {
+ ReportIssueAsyncTask(activity, report, target, login).execute()
+ }
+ }
+ }
+
companion object {
- private const val ISSUE_TRACKER_LINK =
- "https://github.com/MuntashirAkon/Metro/issues/new"
+
+ private const val STATUS_BAD_CREDENTIALS = 401
+ private const val STATUS_ISSUES_NOT_ENABLED = 410
+ private const val ISSUE_TRACKER_LINK = "https://github.com/h4h13/RetroMusicPlayer"
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.java b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.java
new file mode 100644
index 000000000..4e7ea77eb
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.java
@@ -0,0 +1,106 @@
+package code.name.monkey.retromusic.activities.bugreport.model;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import androidx.annotation.IntRange;
+
+import java.util.Arrays;
+
+import code.name.monkey.retromusic.util.PreferenceUtil;
+
+public class DeviceInfo {
+ private final int versionCode;
+ private final String versionName;
+ private final String buildVersion = Build.VERSION.INCREMENTAL;
+ private final String releaseVersion = Build.VERSION.RELEASE;
+ @IntRange(from = 0)
+ private final int sdkVersion = Build.VERSION.SDK_INT;
+ private final String buildID = Build.DISPLAY;
+ private final String brand = Build.BRAND;
+ private final String manufacturer = Build.MANUFACTURER;
+ private final String device = Build.DEVICE;
+ private final String model = Build.MODEL;
+ private final String product = Build.PRODUCT;
+ private final String hardware = Build.HARDWARE;
+ private final String baseTheme;
+ private final String nowPlayingTheme;
+ private final boolean isAdaptive;
+ @SuppressLint("NewApi")
+ @SuppressWarnings("deprecation")
+ private final String[] abis = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
+ Build.SUPPORTED_ABIS : new String[]{Build.CPU_ABI, Build.CPU_ABI2};
+ @SuppressLint("NewApi")
+ private final String[] abis32Bits = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
+ Build.SUPPORTED_32_BIT_ABIS : null;
+ @SuppressLint("NewApi")
+ private final String[] abis64Bits = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
+ Build.SUPPORTED_64_BIT_ABIS : null;
+
+ public DeviceInfo(Context context) {
+ PackageInfo packageInfo;
+ try {
+ packageInfo = context.getPackageManager()
+ .getPackageInfo(context.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ packageInfo = null;
+ }
+ if (packageInfo != null) {
+ versionCode = packageInfo.versionCode;
+ versionName = packageInfo.versionName;
+ } else {
+ versionCode = -1;
+ versionName = null;
+ }
+ baseTheme = PreferenceUtil.getInstance(context).getBaseTheme();
+ nowPlayingTheme = context.getString(PreferenceUtil.getInstance(context).getNowPlayingScreen().getTitleRes());
+ isAdaptive = PreferenceUtil.getInstance(context).getAdaptiveColor();
+ }
+
+ public String toMarkdown() {
+ return "Device info:\n"
+ + "---\n"
+ + "\n"
+ + "App version " + versionName + " \n"
+ + "App version code " + versionCode + " \n"
+ + "Android build version " + buildVersion + " \n"
+ + "Android release version " + releaseVersion + " \n"
+ + "Android SDK version " + sdkVersion + " \n"
+ + "Android build ID " + buildID + " \n"
+ + "Device brand " + brand + " \n"
+ + "Device manufacturer " + manufacturer + " \n"
+ + "Device name " + device + " \n"
+ + "Device model " + model + " \n"
+ + "Device product name " + product + " \n"
+ + "Device hardware name " + hardware + " \n"
+ + "ABIs " + Arrays.toString(abis) + " \n"
+ + "ABIs (32bit) " + Arrays.toString(abis32Bits) + " \n"
+ + "ABIs (64bit) " + Arrays.toString(abis64Bits) + " \n"
+ + "
\n";
+ }
+
+ @Override
+ public String toString() {
+ return "App version: " + versionName + "\n"
+ + "App version code: " + versionCode + "\n"
+ + "Android build version: " + buildVersion + "\n"
+ + "Android release version: " + releaseVersion + "\n"
+ + "Android SDK version: " + sdkVersion + "\n"
+ + "Android build ID: " + buildID + "\n"
+ + "Device brand: " + brand + "\n"
+ + "Device manufacturer: " + manufacturer + "\n"
+ + "Device name: " + device + "\n"
+ + "Device model: " + model + "\n"
+ + "Device product name: " + product + "\n"
+ + "Device hardware name: " + hardware + "\n"
+ + "ABIs: " + Arrays.toString(abis) + "\n"
+ + "ABIs (32bit): " + Arrays.toString(abis32Bits) + "\n"
+ + "ABIs (64bit): " + Arrays.toString(abis64Bits) + "\n"
+ + "Base theme: " + baseTheme + "\n"
+ + "Now playing theme: " + nowPlayingTheme + "\n"
+ + "Adaptive: " + isAdaptive;
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.kt b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.kt
deleted file mode 100644
index 19aff73a2..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-package code.name.monkey.retromusic.activities.bugreport.model
-
-import android.annotation.SuppressLint
-import android.content.Context
-import android.content.pm.PackageManager
-import android.os.Build
-import androidx.annotation.IntRange
-import androidx.appcompat.app.AppCompatDelegate
-import androidx.core.content.pm.PackageInfoCompat
-import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.PreferenceUtil.isAdaptiveColor
-import code.name.monkey.retromusic.util.PreferenceUtil.nowPlayingScreen
-import java.util.*
-
-class DeviceInfo(context: Context) {
- @SuppressLint("NewApi")
- private val abis = Build.SUPPORTED_ABIS
-
- @SuppressLint("NewApi")
- private val abis32Bits = Build.SUPPORTED_32_BIT_ABIS
-
- @SuppressLint("NewApi")
- private val abis64Bits = Build.SUPPORTED_64_BIT_ABIS
- private val baseTheme: String
- private val brand = Build.BRAND
- private val buildID = Build.DISPLAY
- private val buildVersion = Build.VERSION.INCREMENTAL
- private val device = Build.DEVICE
- private val hardware = Build.HARDWARE
- private val isAdaptive: Boolean
- private val manufacturer = Build.MANUFACTURER
- private val model = Build.MODEL
- private val nowPlayingTheme: String
- private val product = Build.PRODUCT
- private val releaseVersion = Build.VERSION.RELEASE
-
- @IntRange(from = 0)
- private val sdkVersion = Build.VERSION.SDK_INT
- private var versionCode = 0L
- private var versionName: String? = null
- private val selectedLang: String
- fun toMarkdown(): String {
- return """
- Device info:
- ---
-
- App version $versionName
- App version code $versionCode
- Android build version $buildVersion
- Android release version $releaseVersion
- Android SDK version $sdkVersion
- Android build ID $buildID
- Device brand $brand
- Device manufacturer $manufacturer
- Device name $device
- Device model $model
- Device product name $product
- Device hardware name $hardware
- ABIs ${Arrays.toString(abis)}
- ABIs (32bit) ${Arrays.toString(abis32Bits)}
- ABIs (64bit) ${Arrays.toString(abis64Bits)}
- Language $selectedLang
-
-
- """.trimIndent()
- }
-
- override fun toString(): String {
- return """
- App version: $versionName
- App version code: $versionCode
- Android build version: $buildVersion
- Android release version: $releaseVersion
- Android SDK version: $sdkVersion
- Android build ID: $buildID
- Device brand: $brand
- Device manufacturer: $manufacturer
- Device name: $device
- Device model: $model
- Device product name: $product
- Device hardware name: $hardware
- ABIs: ${Arrays.toString(abis)}
- ABIs (32bit): ${Arrays.toString(abis32Bits)}
- ABIs (64bit): ${Arrays.toString(abis64Bits)}
- Base theme: $baseTheme
- Now playing theme: $nowPlayingTheme
- Adaptive: $isAdaptive
- System language: ${Locale.getDefault().toLanguageTag()}
- In-App Language: $selectedLang
- """.trimIndent()
- }
-
- init {
- val packageInfo = try {
- context.packageManager.getPackageInfo(context.packageName, 0)
- } catch (e: PackageManager.NameNotFoundException) {
- null
- }
- if (packageInfo != null) {
- versionCode = PackageInfoCompat.getLongVersionCode(packageInfo)
- versionName = packageInfo.versionName
- } else {
- versionCode = -1
- versionName = null
- }
- baseTheme = PreferenceUtil.baseTheme
- nowPlayingTheme = context.getString(nowPlayingScreen.titleRes)
- isAdaptive = isAdaptiveColor
- selectedLang = AppCompatDelegate.getApplicationLocales().toLanguageTags()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/Report.java b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/Report.java
new file mode 100644
index 000000000..4549693f4
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/Report.java
@@ -0,0 +1,32 @@
+package code.name.monkey.retromusic.activities.bugreport.model;
+
+
+import code.name.monkey.retromusic.activities.bugreport.model.github.ExtraInfo;
+
+public class Report {
+ private final String title;
+
+ private final String description;
+
+ private final DeviceInfo deviceInfo;
+
+ private final ExtraInfo extraInfo;
+
+ public Report(String title, String description, DeviceInfo deviceInfo, ExtraInfo extraInfo) {
+ this.title = title;
+ this.description = description;
+ this.deviceInfo = deviceInfo;
+ this.extraInfo = extraInfo;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getDescription() {
+ return description + "\n\n"
+ + "-\n\n"
+ + deviceInfo.toMarkdown() + "\n\n"
+ + extraInfo.toMarkdown();
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/ExtraInfo.java b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/ExtraInfo.java
new file mode 100644
index 000000000..c9bedfa63
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/ExtraInfo.java
@@ -0,0 +1,59 @@
+package code.name.monkey.retromusic.activities.bugreport.model.github;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class ExtraInfo {
+ private final Map extraInfo = new LinkedHashMap<>();
+
+ public void put(String key, String value) {
+ extraInfo.put(key, value);
+ }
+
+ public void put(String key, boolean value) {
+ extraInfo.put(key, Boolean.toString(value));
+ }
+
+ public void put(String key, double value) {
+ extraInfo.put(key, Double.toString(value));
+ }
+
+ public void put(String key, float value) {
+ extraInfo.put(key, Float.toString(value));
+ }
+
+ public void put(String key, long value) {
+ extraInfo.put(key, Long.toString(value));
+ }
+
+ public void put(String key, int value) {
+ extraInfo.put(key, Integer.toString(value));
+ }
+
+ public void put(String key, Object value) {
+ extraInfo.put(key, String.valueOf(value));
+ }
+
+ public void remove(String key) {
+ extraInfo.remove(key);
+ }
+
+ public String toMarkdown() {
+ if (extraInfo.isEmpty()) return "";
+
+ StringBuilder output = new StringBuilder();
+ output.append("Extra info:\n"
+ + "---\n"
+ + "\n");
+ for (String key : extraInfo.keySet()) {
+ output.append("")
+ .append(key)
+ .append(" ")
+ .append(extraInfo.get(key))
+ .append(" \n");
+ }
+ output.append("
\n");
+
+ return output.toString();
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/GithubLogin.java b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/GithubLogin.java
new file mode 100644
index 000000000..a2d147eea
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/GithubLogin.java
@@ -0,0 +1,40 @@
+package code.name.monkey.retromusic.activities.bugreport.model.github;
+
+import android.text.TextUtils;
+
+public class GithubLogin {
+ private final String username;
+
+ private final String password;
+
+ private final String apiToken;
+
+ public GithubLogin(String username, String password) {
+ this.username = username;
+ this.password = password;
+ this.apiToken = null;
+ }
+
+ public GithubLogin(String apiToken) {
+ this.username = null;
+ this.password = null;
+ this.apiToken = apiToken;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public boolean shouldUseApiToken() {
+ return TextUtils.isEmpty(username) || TextUtils.isEmpty(password);
+ }
+
+ public String getApiToken() {
+ return apiToken;
+ }
+
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/GithubTarget.java b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/GithubTarget.java
new file mode 100644
index 000000000..4bea98be7
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/GithubTarget.java
@@ -0,0 +1,20 @@
+package code.name.monkey.retromusic.activities.bugreport.model.github;
+
+public class GithubTarget {
+ private final String username;
+
+ private final String repository;
+
+ public GithubTarget(String username, String repository) {
+ this.username = username;
+ this.repository = repository;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getRepository() {
+ return repository;
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/saf/SAFGuideActivity.java b/app/src/main/java/code/name/monkey/retromusic/activities/saf/SAFGuideActivity.java
index efd56210e..4ba6c9902 100644
--- a/app/src/main/java/code/name/monkey/retromusic/activities/saf/SAFGuideActivity.java
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/saf/SAFGuideActivity.java
@@ -24,53 +24,47 @@ import com.heinrichreimersoftware.materialintro.slide.SimpleSlide;
import code.name.monkey.retromusic.R;
-/** Created by hemanths on 2019-07-31. */
+/**
+ * Created by hemanths on 2019-07-31.
+ */
public class SAFGuideActivity extends IntroActivity {
+ public static final int REQUEST_CODE_SAF_GUIDE = 98;
- public static final int REQUEST_CODE_SAF_GUIDE = 98;
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ setButtonCtaVisible(false);
+ setButtonNextVisible(false);
+ setButtonBackVisible(false);
- setButtonCtaVisible(false);
- setButtonNextVisible(false);
- setButtonBackVisible(false);
+ setButtonCtaTintMode(BUTTON_CTA_TINT_MODE_TEXT);
- setButtonCtaTintMode(BUTTON_CTA_TINT_MODE_TEXT);
+ String title = String.format(getString(R.string.saf_guide_slide1_title), getString(R.string.app_name));
- String title =
- String.format(getString(R.string.saf_guide_slide1_title), getString(R.string.app_name));
-
- addSlide(
- new SimpleSlide.Builder()
- .title(title)
- .description(
- Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
- ? R.string.saf_guide_slide1_description_before_o
- : R.string.saf_guide_slide1_description)
- .image(R.drawable.saf_guide_1)
- .background(code.name.monkey.appthemehelper.R.color.md_deep_purple_300)
- .backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_400)
- .layout(R.layout.fragment_simple_slide_large_image)
- .build());
- addSlide(
- new SimpleSlide.Builder()
- .title(R.string.saf_guide_slide2_title)
- .description(R.string.saf_guide_slide2_description)
- .image(R.drawable.saf_guide_2)
- .background(code.name.monkey.appthemehelper.R.color.md_deep_purple_500)
- .backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_600)
- .layout(R.layout.fragment_simple_slide_large_image)
- .build());
- addSlide(
- new SimpleSlide.Builder()
- .title(R.string.saf_guide_slide3_title)
- .description(R.string.saf_guide_slide3_description)
- .image(R.drawable.saf_guide_3)
- .background(code.name.monkey.appthemehelper.R.color.md_deep_purple_700)
- .backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_800)
- .layout(R.layout.fragment_simple_slide_large_image)
- .build());
- }
+ addSlide(new SimpleSlide.Builder()
+ .title(title)
+ .description(Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1 ? R.string.saf_guide_slide1_description_before_o : R.string.saf_guide_slide1_description)
+ .image(R.drawable.saf_guide_1)
+ .background(R.color.md_deep_purple_300)
+ .backgroundDark(R.color.md_deep_purple_400)
+ .layout(R.layout.fragment_simple_slide_large_image)
+ .build());
+ addSlide(new SimpleSlide.Builder()
+ .title(R.string.saf_guide_slide2_title)
+ .description(R.string.saf_guide_slide2_description)
+ .image(R.drawable.saf_guide_2)
+ .background(R.color.md_deep_purple_500)
+ .backgroundDark(R.color.md_deep_purple_600)
+ .layout(R.layout.fragment_simple_slide_large_image)
+ .build());
+ addSlide(new SimpleSlide.Builder()
+ .title(R.string.saf_guide_slide3_title)
+ .description(R.string.saf_guide_slide3_description)
+ .image(R.drawable.saf_guide_3)
+ .background(R.color.md_deep_purple_700)
+ .backgroundDark(R.color.md_deep_purple_800)
+ .layout(R.layout.fragment_simple_slide_large_image)
+ .build());
+ }
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/saf/SAFRequestActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/saf/SAFRequestActivity.kt
deleted file mode 100644
index 1b389b9d2..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/saf/SAFRequestActivity.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2021 Bartlomiej Uliasz.
- *
- * 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.activities.saf
-
-import android.app.Activity
-import android.content.Intent
-import android.os.Bundle
-import code.name.monkey.retromusic.activities.saf.SAFGuideActivity.REQUEST_CODE_SAF_GUIDE
-import code.name.monkey.retromusic.util.SAFUtil
-
-/** Created by buliasz on 2021-02-07. */
-class SAFRequestActivity : Activity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- val intent = Intent(this, code.name.monkey.retromusic.activities.saf.SAFGuideActivity::class.java)
- startActivityForResult(intent, REQUEST_CODE_SAF_GUIDE)
- }
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
- super.onActivityResult(requestCode, resultCode, intent)
- when (requestCode) {
- REQUEST_CODE_SAF_GUIDE -> {
- SAFUtil.openTreePicker(this)
- }
- SAFUtil.REQUEST_SAF_PICK_TREE -> {
- if (resultCode == RESULT_OK) {
- SAFUtil.saveTreeUri(this, intent)
- }
- finish()
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt
index 3a9ca4e4b..df8cbe297 100755
--- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt
@@ -1,457 +1,416 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.activities.tageditor
-import android.app.Activity
-import android.app.SearchManager
+import android.app.*
import android.content.Intent
-import android.graphics.Bitmap
-import android.graphics.BitmapFactory
+import android.content.res.ColorStateList
+import android.graphics.*
import android.net.Uri
-import android.os.Bundle
-import android.provider.MediaStore
+import android.os.*
import android.util.Log
-import android.view.LayoutInflater
-import android.view.MenuItem
+import android.view.*
import android.view.animation.OvershootInterpolator
-import android.widget.ImageView
-import androidx.activity.result.ActivityResultLauncher
-import androidx.activity.result.IntentSenderRequest
-import androidx.activity.result.PickVisualMediaRequest
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.appcompat.app.AlertDialog
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import code.name.monkey.appthemehelper.util.VersionUtils
+import code.name.monkey.appthemehelper.ThemeStore
+import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
-import code.name.monkey.retromusic.extensions.accentColor
-import code.name.monkey.retromusic.extensions.colorButtons
-import code.name.monkey.retromusic.extensions.hideSoftKeyboard
-import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
-import code.name.monkey.retromusic.model.ArtworkInfo
-import code.name.monkey.retromusic.model.AudioTagInfo
-import code.name.monkey.retromusic.repository.Repository
-import code.name.monkey.retromusic.util.logD
-import code.name.monkey.retromusic.util.logE
+import code.name.monkey.retromusic.activities.saf.SAFGuideActivity
+import code.name.monkey.retromusic.util.*
+import com.afollestad.materialdialogs.*
+import com.afollestad.materialdialogs.bottomsheets.BottomSheet
+import com.afollestad.materialdialogs.list.listItems
import com.google.android.material.button.MaterialButton
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
-import org.jaudiotagger.audio.AudioFile
-import org.jaudiotagger.audio.AudioFileIO
+import kotlinx.android.synthetic.main.activity_album_tag_editor.*
+import org.jaudiotagger.audio.*
import org.jaudiotagger.tag.FieldKey
-import org.koin.android.ext.android.inject
import java.io.File
+import java.util.*
-abstract class AbsTagEditorActivity : AbsBaseActivity() {
- abstract val editorImage: ImageView
- val repository by inject()
+abstract class AbsTagEditorActivity : AbsBaseActivity() {
- lateinit var saveFab: MaterialButton
- protected var id: Long = 0
- private set
- private var paletteColorPrimary: Int = 0
- private var songPaths: List? = null
- private var savedSongPaths: List? = null
- private val currentSongPath: String? = null
- private var savedTags: Map? = null
- private var savedArtworkInfo: ArtworkInfo? = null
- private var _binding: VB? = null
- protected val binding: VB get() = _binding!!
- private var cacheFiles = listOf()
+ protected var id: Int = 0
+ private set
+ private var paletteColorPrimary: Int = 0
+ private var isInNoImageMode: Boolean = false
+ private var songPaths: List? = null
+ lateinit var saveFab: MaterialButton
- abstract val bindingInflater: (LayoutInflater) -> VB
+ private var savedSongPaths: List? = null
+ private val currentSongPath: String? = null
+ private var savedTags: Map? = null
+ private var savedArtworkInfo: ArtworkInfo? = null
- private lateinit var launcher: ActivityResultLauncher
+ protected val show: MaterialDialog
+ get() = MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
+ cornerRadius(PreferenceUtil.getInstance(this@AbsTagEditorActivity).dialogCorner)
+ title(R.string.update_image)
+ listItems(items = items) { _, position, _ ->
+ when (position) {
+ 0 -> startImagePicker()
+ 1 -> searchImageOnWeb()
+ 2 -> deleteImage()
+ }
+ }
+ }
+ protected abstract val contentViewLayout: Int
- protected abstract fun loadImageFromFile(selectedFile: Uri?)
+ internal val albumArtist: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
+ } catch (ignored: Exception) {
+ null
+ }
- protected val show: AlertDialog
- get() =
- MaterialAlertDialogBuilder(this)
- .setTitle(R.string.update_image)
- .setItems(items.toTypedArray()) { _, position ->
- when (position) {
- 0 -> startImagePicker()
- 1 -> searchImageOnWeb()
- 2 -> deleteImage()
- }
- }
- .setNegativeButton(R.string.action_cancel, null)
- .show()
- .colorButtons()
+ }
- internal val albumArtist: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
+ protected val songTitle: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TITLE)
+ } catch (ignored: Exception) {
+ null
+ }
- protected val songTitle: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TITLE)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
- protected val composer: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.COMPOSER)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
+ }
+ protected val composer: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.COMPOSER)
+ } catch (ignored: Exception) {
+ null
+ }
- protected val albumTitle: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
+ }
- protected val artistName: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ARTIST)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
+ protected val albumTitle: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM)
+ } catch (ignored: Exception) {
+ null
+ }
- protected val albumArtistName: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
+ }
- protected val genreName: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.GENRE)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
+ protected val artistName: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ARTIST)
+ } catch (ignored: Exception) {
+ null
+ }
- protected val songYear: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.YEAR)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
+ }
- protected val trackNumber: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TRACK)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
+ protected val albumArtistName: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
+ } catch (ignored: Exception) {
+ null
+ }
- protected val discNumber: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.DISC_NO)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
+ }
- protected val lyrics: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.LYRICS)
- } catch (e: Exception) {
- logE(e)
- null
- }
- }
+ protected val genreName: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.GENRE)
+ } catch (ignored: Exception) {
+ null
+ }
- protected val albumArt: Bitmap?
- get() {
- try {
- val artworkTag = getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.firstArtwork
- if (artworkTag != null) {
- val artworkBinaryData = artworkTag.binaryData
- return BitmapFactory.decodeByteArray(
- artworkBinaryData,
- 0,
- artworkBinaryData.size
- )
- }
- return null
- } catch (e: Exception) {
- logE(e)
- return null
- }
- }
+ }
- private val pickArtworkImage =
- registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
- loadImageFromFile(uri)
- }
+ protected val songYear: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.YEAR)
+ } catch (ignored: Exception) {
+ null
+ }
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- _binding = bindingInflater.invoke(layoutInflater)
- setContentView(binding.root)
- setTaskDescriptionColorAuto()
+ }
- saveFab = findViewById(R.id.saveTags)
- getIntentExtras()
+ protected val trackNumber: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TRACK)
+ } catch (ignored: Exception) {
+ null
+ }
- songPaths = getSongPaths()
- logD(songPaths?.size)
- if (songPaths!!.isEmpty()) {
- finish()
- }
- setUpViews()
- launcher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) {
- if (it.resultCode == Activity.RESULT_OK) {
- writeToFiles(getSongUris(), cacheFiles)
- }
- }
- }
+ }
- private fun setUpViews() {
- setUpFab()
- setUpImageView()
- }
+ protected val lyrics: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.LYRICS)
+ } catch (ignored: Exception) {
+ null
+ }
- private lateinit var items: List
+ }
- private fun setUpImageView() {
- loadCurrentImage()
- items = listOf(
- getString(R.string.pick_from_local_storage),
- getString(R.string.web_search),
- getString(R.string.remove_cover)
- )
- editorImage.setOnClickListener { show }
- }
+ protected val albumArt: Bitmap?
+ get() {
+ try {
+ val artworkTag = getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.firstArtwork
+ if (artworkTag != null) {
+ val artworkBinaryData = artworkTag.binaryData
+ return BitmapFactory.decodeByteArray(
+ artworkBinaryData,
+ 0,
+ artworkBinaryData.size
+ )
+ }
+ return null
+ } catch (ignored: Exception) {
+ return null
+ }
- private fun startImagePicker() {
- pickArtworkImage.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
- }
+ }
- protected abstract fun loadCurrentImage()
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(contentViewLayout)
- protected abstract fun searchImageOnWeb()
+ saveFab = findViewById(R.id.saveTags)
+ getIntentExtras()
- protected abstract fun deleteImage()
+ songPaths = getSongPaths()
+ if (songPaths!!.isEmpty()) {
+ finish()
+ return
+ }
- private fun setUpFab() {
- saveFab.accentColor()
- saveFab.apply {
- scaleX = 0f
- scaleY = 0f
- isEnabled = false
- setOnClickListener { save() }
- }
- }
+ setUpViews()
- protected abstract fun save()
- private fun getIntentExtras() {
- val intentExtras = intent.extras
- if (intentExtras != null) {
- id = intentExtras.getLong(EXTRA_ID)
- }
- }
+ setNavigationbarColorAuto()
+ setTaskDescriptionColorAuto()
+ }
- protected abstract fun getSongPaths(): List
+ private fun setUpViews() {
+ setUpScrollView()
+ setUpFab()
+ setUpImageView()
+ }
- protected abstract fun getSongUris(): List
+ private fun setUpScrollView() {
+ //observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
+ }
- protected fun searchWebFor(vararg keys: String) {
- val stringBuilder = StringBuilder()
- for (key in keys) {
- stringBuilder.append(key)
- stringBuilder.append(" ")
- }
- val intent = Intent(Intent.ACTION_WEB_SEARCH)
- intent.putExtra(SearchManager.QUERY, stringBuilder.toString())
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ private lateinit var items: List
- startActivity(intent)
- }
+ private fun setUpImageView() {
+ loadCurrentImage()
+ items = listOf(
+ getString(code.name.monkey.retromusic.R.string.pick_from_local_storage),
+ getString(code.name.monkey.retromusic.R.string.web_search),
+ getString(code.name.monkey.retromusic.R.string.remove_cover)
+ )
+ editorImage?.setOnClickListener { show }
+ }
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- android.R.id.home -> {
- onBackPressedDispatcher.onBackPressed()
- return true
- }
- }
- return super.onOptionsItemSelected(item)
- }
+ private fun startImagePicker() {
+ val intent = Intent(Intent.ACTION_GET_CONTENT)
+ intent.type = "image/*"
+ startActivityForResult(
+ Intent.createChooser(
+ intent,
+ getString(code.name.monkey.retromusic.R.string.pick_from_local_storage)
+ ), REQUEST_CODE_SELECT_IMAGE
+ )
+ }
- protected fun dataChanged() {
- showFab()
- }
+ protected abstract fun loadCurrentImage()
- private fun showFab() {
- saveFab.animate().setDuration(500).setInterpolator(OvershootInterpolator()).scaleX(1f)
- .scaleY(1f).start()
- saveFab.isEnabled = true
- }
+ protected abstract fun searchImageOnWeb()
- private fun hideFab() {
- saveFab.animate().setDuration(500).setInterpolator(OvershootInterpolator()).scaleX(0.0f)
- .scaleY(0.0f).start()
- saveFab.isEnabled = false
- }
+ protected abstract fun deleteImage()
- protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) {
- if (bitmap == null) {
- editorImage.setImageResource(R.drawable.default_audio_art)
- } else {
- editorImage.setImageBitmap(bitmap)
- }
- setColors(bgColor)
- }
+ private fun setUpFab() {
+ saveFab.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
+ ColorStateList.valueOf(
+ MaterialValueHelper.getPrimaryTextColor(
+ this,
+ ColorUtil.isColorLight(
+ ThemeStore.accentColor(
+ this
+ )
+ )
+ )
+ ).apply {
+ saveFab.setTextColor(this)
+ saveFab.iconTint = this
+ }
+ saveFab.apply {
+ scaleX = 0f
+ scaleY = 0f
+ isEnabled = false
+ setOnClickListener { save() }
+ TintHelper.setTintAuto(this, ThemeStore.accentColor(this@AbsTagEditorActivity), true)
+ }
+ }
- protected open fun setColors(color: Int) {
- paletteColorPrimary = color
- }
+ protected abstract fun save()
- protected fun writeValuesToFiles(
- fieldKeyValueMap: Map,
- artworkInfo: ArtworkInfo?
- ) {
- hideSoftKeyboard()
+ private fun getIntentExtras() {
+ val intentExtras = intent.extras
+ if (intentExtras != null) {
+ id = intentExtras.getInt(EXTRA_ID)
+ }
+ }
- hideFab()
- logD(fieldKeyValueMap)
- GlobalScope.launch {
- if (VersionUtils.hasR()) {
- cacheFiles = TagWriter.writeTagsToFilesR(
- this@AbsTagEditorActivity, AudioTagInfo(
- songPaths,
- fieldKeyValueMap,
- artworkInfo
- )
- )
+ protected abstract fun getSongPaths(): List
- if (cacheFiles.isNotEmpty()) {
- val pendingIntent =
- MediaStore.createWriteRequest(contentResolver, getSongUris())
- launcher.launch(IntentSenderRequest.Builder(pendingIntent).build())
- }
- } else {
- TagWriter.writeTagsToFiles(
- this@AbsTagEditorActivity, AudioTagInfo(
- songPaths,
- fieldKeyValueMap,
- artworkInfo
- )
- )
- }
- }
- }
+ protected fun searchWebFor(vararg keys: String) {
+ val stringBuilder = StringBuilder()
+ for (key in keys) {
+ stringBuilder.append(key)
+ stringBuilder.append(" ")
+ }
+ val intent = Intent(Intent.ACTION_WEB_SEARCH)
+ intent.putExtra(SearchManager.QUERY, stringBuilder.toString())
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- private fun writeTags(paths: List?) {
- GlobalScope.launch {
- if (VersionUtils.hasR()) {
- cacheFiles = TagWriter.writeTagsToFilesR(
- this@AbsTagEditorActivity, AudioTagInfo(
- paths,
- savedTags,
- savedArtworkInfo
- )
- )
- val pendingIntent = MediaStore.createWriteRequest(contentResolver, getSongUris())
+ startActivity(intent)
+ }
- launcher.launch(IntentSenderRequest.Builder(pendingIntent).build())
- } else {
- TagWriter.writeTagsToFiles(
- this@AbsTagEditorActivity, AudioTagInfo(
- paths,
- savedTags,
- savedArtworkInfo
- )
- )
- }
- }
- }
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ android.R.id.home -> {
+ super.onBackPressed()
+ return true
+ }
+ }
+ return super.onOptionsItemSelected(item)
+ }
- private lateinit var audioFile: AudioFile
+ protected fun setNoImageMode() {
+ isInNoImageMode = true
+ imageContainer?.visibility = View.GONE
+ editorImage?.visibility = View.GONE
+ editorImage?.isEnabled = false
- private fun getAudioFile(path: String): AudioFile {
- return try {
- if (!this::audioFile.isInitialized) {
- audioFile = AudioFileIO.read(File(path))
- }
- audioFile
- } catch (e: Exception) {
- Log.e(TAG, "Could not read audio file $path", e)
- AudioFile()
- }
- }
+ setColors(
+ intent.getIntExtra(
+ EXTRA_PALETTE,
+ ATHUtil.resolveColor(this, R.attr.colorPrimary)
+ )
+ )
+ }
- private fun writeToFiles(songUris: List, cacheFiles: List) {
- if (cacheFiles.size == songUris.size) {
- for (i in cacheFiles.indices) {
- contentResolver.openOutputStream(songUris[i])?.use { output ->
- cacheFiles[i].inputStream().use { input ->
- input.copyTo(output)
- }
- }
- }
- }
- lifecycleScope.launch {
- TagWriter.scan(this@AbsTagEditorActivity, getSongPaths())
- }
- }
+ protected fun dataChanged() {
+ showFab()
+ }
- override fun onDestroy() {
- super.onDestroy()
- // Delete Cache Files
- cacheFiles.forEach { file ->
- file.delete()
- }
- }
+ private fun showFab() {
+ saveFab.animate().setDuration(500).setInterpolator(OvershootInterpolator()).scaleX(1f)
+ .scaleY(1f).start()
+ saveFab.isEnabled = true
+ }
- companion object {
- const val EXTRA_ID = "extra_id"
- const val EXTRA_PALETTE = "extra_palette"
- private val TAG = AbsTagEditorActivity::class.java.simpleName
- private const val REQUEST_CODE_SELECT_IMAGE = 1000
- }
+ private fun hideFab() {
+ saveFab.animate().setDuration(500).setInterpolator(OvershootInterpolator()).scaleX(0.0f)
+ .scaleY(0.0f).start()
+ saveFab.isEnabled = false
+ }
+
+ protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) {
+ if (bitmap == null) {
+ editorImage.setImageResource(code.name.monkey.retromusic.R.drawable.default_album_art)
+ } else {
+ editorImage.setImageBitmap(bitmap)
+ }
+ setColors(bgColor)
+ }
+
+ protected open fun setColors(color: Int) {
+ paletteColorPrimary = color
+ }
+
+ protected fun writeValuesToFiles(
+ fieldKeyValueMap: Map, artworkInfo: ArtworkInfo?
+ ) {
+ RetroUtil.hideSoftKeyboard(this)
+
+ hideFab()
+
+ savedSongPaths = getSongPaths()
+ savedTags = fieldKeyValueMap
+ savedArtworkInfo = artworkInfo
+
+ if (!SAFUtil.isSAFRequired(savedSongPaths)) {
+ writeTags(savedSongPaths)
+ } else {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (SAFUtil.isSDCardAccessGranted(this)) {
+ writeTags(savedSongPaths)
+ } else {
+ startActivityForResult(
+ Intent(this, SAFGuideActivity::class.java),
+ SAFGuideActivity.REQUEST_CODE_SAF_GUIDE
+ )
+ }
+ }
+ }
+ }
+
+ private fun writeTags(paths: List?) {
+ WriteTagsAsyncTask(this).execute(
+ WriteTagsAsyncTask.LoadingInfo(
+ paths,
+ savedTags,
+ savedArtworkInfo
+ )
+ )
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
+ super.onActivityResult(requestCode, resultCode, intent)
+ when (requestCode) {
+ REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
+ intent?.data?.let {
+ loadImageFromFile(it)
+ }
+ }
+ SAFGuideActivity.REQUEST_CODE_SAF_GUIDE -> {
+ SAFUtil.openTreePicker(this)
+ }
+ SAFUtil.REQUEST_SAF_PICK_TREE -> {
+ if (resultCode == Activity.RESULT_OK) {
+ SAFUtil.saveTreeUri(this, intent)
+ writeTags(savedSongPaths)
+ }
+ }
+ SAFUtil.REQUEST_SAF_PICK_FILE -> {
+ if (resultCode == Activity.RESULT_OK) {
+ writeTags(Collections.singletonList(currentSongPath + SAFUtil.SEPARATOR + intent!!.dataString))
+ }
+ }
+ }
+ }
+
+ protected abstract fun loadImageFromFile(selectedFile: Uri?)
+
+ private fun getAudioFile(path: String): AudioFile {
+ return try {
+ AudioFileIO.read(File(path))
+ } catch (e: Exception) {
+ Log.e(TAG, "Could not read audio file $path", e)
+ AudioFile()
+ }
+ }
+
+ class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?)
+
+ companion object {
+
+ const val EXTRA_ID = "extra_id"
+ const val EXTRA_PALETTE = "extra_palette"
+ private val TAG = AbsTagEditorActivity::class.java.simpleName
+ private const val REQUEST_CODE_SELECT_IMAGE = 1000
+ }
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt
index 2c9013657..c96990322 100755
--- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt
@@ -1,17 +1,3 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.activities.tageditor
import android.app.Activity
@@ -22,198 +8,241 @@ import android.graphics.Color
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
-import android.transition.Slide
-import android.view.LayoutInflater
-import android.widget.ImageView
+import android.text.Editable
+import android.text.TextUtils
+import android.text.TextWatcher
import android.widget.Toast
-import androidx.core.widget.doAfterTextChanged
-import code.name.monkey.appthemehelper.util.MaterialValueHelper
+import code.name.monkey.appthemehelper.util.ATHUtil
+import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding
-import code.name.monkey.retromusic.extensions.*
-import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
+import code.name.monkey.retromusic.extensions.appHandleColor
+import code.name.monkey.retromusic.extensions.applyToolbar
+import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
-import code.name.monkey.retromusic.model.ArtworkInfo
-import code.name.monkey.retromusic.model.Song
+import code.name.monkey.retromusic.loaders.AlbumLoader
+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.MusicUtil
+import code.name.monkey.retromusic.util.LastFMUtil
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
import code.name.monkey.retromusic.util.RetroColorUtil.getColor
-import code.name.monkey.retromusic.util.logD
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
-import com.bumptech.glide.request.target.ImageViewTarget
-import com.bumptech.glide.request.transition.Transition
-import com.google.android.material.shape.MaterialShapeDrawable
+import com.bumptech.glide.request.animation.GlideAnimation
+import com.bumptech.glide.request.target.SimpleTarget
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.tag.FieldKey
import java.util.*
-class AlbumTagEditorActivity : AbsTagEditorActivity() {
+class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
+ override val contentViewLayout: Int
+ get() = R.layout.activity_album_tag_editor
- override val bindingInflater: (LayoutInflater) -> ActivityAlbumTagEditorBinding =
- ActivityAlbumTagEditorBinding::inflate
+ override fun loadImageFromFile(selectedFileUri: Uri?) {
- private fun windowEnterTransition() {
- val slide = Slide()
- slide.excludeTarget(R.id.appBarLayout, true)
- slide.excludeTarget(R.id.status_bar, true)
- slide.excludeTarget(android.R.id.statusBarBackground, true)
- slide.excludeTarget(android.R.id.navigationBarBackground, true)
+ Glide.with(this@AlbumTagEditorActivity).load(selectedFileUri).asBitmap()
+ .transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
+ .diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
+ .into(object : SimpleTarget() {
+ override fun onResourceReady(
+ resource: BitmapPaletteWrapper?,
+ glideAnimation: GlideAnimation?
+ ) {
+ getColor(resource?.palette, Color.TRANSPARENT)
+ albumArtBitmap = resource?.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
+ setImageBitmap(albumArtBitmap, getColor(resource?.palette, ATHUtil.resolveColor(this@AlbumTagEditorActivity, R.attr.defaultFooterColor)))
+ deleteAlbumArt = false
+ dataChanged()
+ setResult(Activity.RESULT_OK)
+ }
- window.enterTransition = slide
- }
+ override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
+ super.onLoadFailed(e, errorDrawable)
+ Toast.makeText(this@AlbumTagEditorActivity, e.toString(), Toast.LENGTH_LONG)
+ .show()
+ }
+ })
+ }
- private var albumArtBitmap: Bitmap? = null
- private var deleteAlbumArt: Boolean = false
+ private var albumArtBitmap: Bitmap? = null
+ private var deleteAlbumArt: Boolean = false
+ private var lastFMRestClient: LastFMRestClient? = null
+ private val disposable = CompositeDisposable()
- private fun setupToolbar() {
- setSupportActionBar(binding.toolbar)
- binding.appBarLayout?.statusBarForeground =
- MaterialShapeDrawable.createWithElevationOverlay(this)
- }
+ private fun setupToolbar() {
+ applyToolbar(toolbar)
+ supportActionBar?.setDisplayShowHomeEnabled(true)
+ }
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- window.sharedElementsUseOverlay = true
- binding.imageContainer.transitionName = getString(R.string.transition_album_art)
- windowEnterTransition()
- setUpViews()
- setupToolbar()
- }
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setDrawUnderStatusBar()
+ super.onCreate(savedInstanceState)
+ lastFMRestClient = LastFMRestClient(this)
- private fun setUpViews() {
- fillViewsWithFileTags()
+ setUpViews()
+ setupToolbar()
+ }
- binding.yearContainer.setTint(false)
- binding.genreContainer.setTint(false)
- binding.albumTitleContainer.setTint(false)
- binding.albumArtistContainer.setTint(false)
+ private fun setUpViews() {
+ fillViewsWithFileTags()
- binding.albumText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.albumArtistText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.genreTitle.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.yearTitle.appHandleColor().doAfterTextChanged { dataChanged() }
- }
+ MaterialUtil.setTint(yearContainer, false)
+ MaterialUtil.setTint(genreContainer, false)
+ MaterialUtil.setTint(albumTitleContainer, false)
+ MaterialUtil.setTint(albumArtistContainer, false)
- private fun fillViewsWithFileTags() {
- binding.albumText.setText(albumTitle)
- binding.albumArtistText.setText(albumArtistName)
- binding.genreTitle.setText(genreName)
- binding.yearTitle.setText(songYear)
- logD(albumTitle + albumArtistName)
- }
+ albumText.appHandleColor().addTextChangedListener(this)
+ albumArtistText.appHandleColor().addTextChangedListener(this)
+ genreTitle.appHandleColor().addTextChangedListener(this)
+ yearTitle.appHandleColor().addTextChangedListener(this)
+ }
- override fun loadCurrentImage() {
- val bitmap = albumArt
- setImageBitmap(
- bitmap,
- getColor(
- generatePalette(bitmap),
- defaultFooterColor()
- )
- )
- deleteAlbumArt = false
- }
+ private fun fillViewsWithFileTags() {
+ albumText.setText(albumTitle)
+ albumArtistText.setText(albumArtistName)
+ genreTitle.setText(genreName)
+ yearTitle.setText(songYear)
+ }
- private fun toastLoadingFailed() {
- showToast(R.string.could_not_download_album_cover)
- }
+ override fun loadCurrentImage() {
+ val bitmap = albumArt
+ setImageBitmap(
+ bitmap,
+ getColor(
+ generatePalette(bitmap),
+ ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
+ )
+ )
+ deleteAlbumArt = false
+ }
- override fun searchImageOnWeb() {
- searchWebFor(binding.albumText.text.toString(), binding.albumArtistText.text.toString())
- }
+ override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ }
- override fun deleteImage() {
- setImageBitmap(
- BitmapFactory.decodeResource(resources, R.drawable.default_audio_art),
- defaultFooterColor()
- )
- deleteAlbumArt = true
- dataChanged()
- }
+ private fun extractDetails(lastFmAlbum: LastFmAlbum) {
+ if (lastFmAlbum.album != null) {
- override fun loadImageFromFile(selectedFile: Uri?) {
- Glide.with(this@AlbumTagEditorActivity)
- .asBitmapPalette()
- .load(selectedFile)
- .diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
- .into(object : ImageViewTarget(binding.editorImage) {
- override fun onResourceReady(
- resource: BitmapPaletteWrapper,
- transition: Transition?
- ) {
- getColor(resource.palette, Color.TRANSPARENT)
- albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
- setImageBitmap(
- albumArtBitmap,
- getColor(
- resource.palette,
- defaultFooterColor()
- )
- )
- deleteAlbumArt = false
- dataChanged()
- setResult(Activity.RESULT_OK)
- }
+ val url = LastFMUtil.getLargestAlbumImageUrl(lastFmAlbum.album.image)
- override fun onLoadFailed(errorDrawable: Drawable?) {
- super.onLoadFailed(errorDrawable)
- showToast(R.string.error_load_failed, Toast.LENGTH_LONG)
- }
+ if (!TextUtils.isEmpty(url) && url.trim { it <= ' ' }.isNotEmpty()) {
+ Glide.with(this@AlbumTagEditorActivity).load(url).asBitmap()
+ .transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
+ .diskCacheStrategy(DiskCacheStrategy.SOURCE).error(R.drawable.default_album_art)
+ .into(object : SimpleTarget() {
+ override fun onLoadFailed(
+ e: java.lang.Exception?,
+ errorDrawable: Drawable?
+ ) {
+ super.onLoadFailed(e, errorDrawable)
+ Toast.makeText(
+ this@AlbumTagEditorActivity,
+ e.toString(),
+ Toast.LENGTH_LONG
+ ).show()
+ }
- override fun setResource(resource: BitmapPaletteWrapper?) {}
- })
- }
+ override fun onResourceReady(
+ resource: BitmapPaletteWrapper?,
+ glideAnimation: GlideAnimation?
+ ) {
+ albumArtBitmap = resource?.bitmap?.let {
+ ImageUtil.resizeBitmap(
+ it,
+ 2048
+ )
+ }
+ setImageBitmap(
+ albumArtBitmap,
+ getColor(
+ resource?.palette,
+ ATHUtil.resolveColor(
+ this@AlbumTagEditorActivity,
+ R.attr.defaultFooterColor
+ )
+ )
+ )
+ deleteAlbumArt = false
+ dataChanged()
+ setResult(RESULT_OK)
+ }
+ })
+ return
+ }
+ if (lastFmAlbum.album.tags.tag.size > 0) {
+ genreTitle.setText(lastFmAlbum.album.tags.tag[0].name)
+ }
- override fun save() {
- val fieldKeyValueMap = EnumMap(FieldKey::class.java)
- fieldKeyValueMap[FieldKey.ALBUM] = binding.albumText.text.toString()
- // android seems not to recognize album_artist field so we additionally write the normal artist field
- fieldKeyValueMap[FieldKey.ARTIST] = binding.albumArtistText.text.toString()
- fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = binding.albumArtistText.text.toString()
- fieldKeyValueMap[FieldKey.GENRE] = binding.genreTitle.text.toString()
- fieldKeyValueMap[FieldKey.YEAR] = binding.yearTitle.text.toString()
+ }
+ toastLoadingFailed()
+ }
- writeValuesToFiles(
- fieldKeyValueMap,
- when {
- deleteAlbumArt -> ArtworkInfo(id, null)
- albumArtBitmap == null -> null
- else -> ArtworkInfo(id, albumArtBitmap!!)
- }
- )
- }
+ private fun toastLoadingFailed() {
+ Toast.makeText(
+ this@AlbumTagEditorActivity,
+ R.string.could_not_download_album_cover,
+ Toast.LENGTH_SHORT
+ ).show()
+ }
- override fun getSongPaths(): List {
- return repository.albumById(id).songs
- .map(Song::data)
- }
+ override fun searchImageOnWeb() {
+ searchWebFor(albumText.text.toString(), albumArtistText.text.toString())
+ }
- override fun getSongUris(): List = repository.albumById(id).songs.map {
- MusicUtil.getSongFileUri(it.id)
- }
+ override fun deleteImage() {
+ setImageBitmap(
+ BitmapFactory.decodeResource(resources, R.drawable.default_album_art),
+ ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
+ )
+ deleteAlbumArt = true
+ dataChanged()
+ }
- override fun setColors(color: Int) {
- super.setColors(color)
- saveFab.backgroundTintList = ColorStateList.valueOf(color)
- saveFab.backgroundTintList = ColorStateList.valueOf(color)
- ColorStateList.valueOf(
- MaterialValueHelper.getPrimaryTextColor(
- this,
- color.isColorLight
- )
- ).also {
- saveFab.iconTint = it
- saveFab.setTextColor(it)
- }
- }
+ override fun save() {
+ val fieldKeyValueMap = EnumMap(FieldKey::class.java)
+ fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
+ //android seems not to recognize album_artist field so we additionally write the normal artist field
+ fieldKeyValueMap[FieldKey.ARTIST] = albumArtistText.text.toString()
+ fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString()
+ fieldKeyValueMap[FieldKey.GENRE] = genreTitle.text.toString()
+ fieldKeyValueMap[FieldKey.YEAR] = yearTitle.text.toString()
+ writeValuesToFiles(
+ fieldKeyValueMap, if (deleteAlbumArt) ArtworkInfo(id, null)
+ else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)
+ )
+ }
- override val editorImage: ImageView
- get() = binding.editorImage
+ override fun getSongPaths(): List {
+ val songs = AlbumLoader.getAlbum(this, id).songs
+ val paths = ArrayList(songs!!.size)
+ for (song in songs) {
+ paths.add(song.data)
+ }
+ return paths
+ }
- companion object {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
- val TAG: String = AlbumTagEditorActivity::class.java.simpleName
- }
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ dataChanged()
+ }
+
+ override fun setColors(color: Int) {
+ super.setColors(color)
+ saveFab.backgroundTintList = ColorStateList.valueOf(color)
+ }
+
+ companion object {
+
+ val TAG: String = AlbumTagEditorActivity::class.java.simpleName
+ }
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt
index 93dd8a44f..fb1dbb50b 100755
--- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt
@@ -1,214 +1,119 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.activities.tageditor
-import android.annotation.SuppressLint
-import android.app.Activity
-import android.content.res.ColorStateList
-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.view.LayoutInflater
-import android.widget.ImageView
-import android.widget.Toast
-import androidx.core.widget.doAfterTextChanged
-import code.name.monkey.appthemehelper.util.MaterialValueHelper
+import android.text.Editable
+import android.text.TextWatcher
+import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.databinding.ActivitySongTagEditorBinding
-import code.name.monkey.retromusic.extensions.*
-import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
-import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
-import code.name.monkey.retromusic.model.ArtworkInfo
-import code.name.monkey.retromusic.repository.SongRepository
-import code.name.monkey.retromusic.util.ImageUtil
-import code.name.monkey.retromusic.util.MusicUtil
-import code.name.monkey.retromusic.util.RetroColorUtil
-import code.name.monkey.retromusic.util.logD
-import com.bumptech.glide.Glide
-import com.bumptech.glide.load.engine.DiskCacheStrategy
-import com.bumptech.glide.request.target.ImageViewTarget
-import com.bumptech.glide.request.transition.Transition
-import com.google.android.material.shape.MaterialShapeDrawable
+import code.name.monkey.retromusic.extensions.appHandleColor
+import code.name.monkey.retromusic.extensions.applyToolbar
+import code.name.monkey.retromusic.loaders.SongLoader
+import kotlinx.android.synthetic.main.activity_song_tag_editor.*
import org.jaudiotagger.tag.FieldKey
-import org.koin.android.ext.android.inject
import java.util.*
-class SongTagEditorActivity : AbsTagEditorActivity() {
+class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
- override val bindingInflater: (LayoutInflater) -> ActivitySongTagEditorBinding =
- ActivitySongTagEditorBinding::inflate
+ override val contentViewLayout: Int
+ get() = R.layout.activity_song_tag_editor
- private val songRepository by inject()
-
- private var albumArtBitmap: Bitmap? = null
- private var deleteAlbumArt: Boolean = false
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+
+ setNoImageMode()
setUpViews()
- setSupportActionBar(binding.toolbar)
- binding.appBarLayout?.statusBarForeground =
- MaterialShapeDrawable.createWithElevationOverlay(this)
+ applyToolbar(toolbar)
+ setStatusbarColorAuto()
}
- @SuppressLint("ClickableViewAccessibility")
private fun setUpViews() {
fillViewsWithFileTags()
- binding.songTextContainer.setTint(false)
- binding.composerContainer.setTint(false)
- binding.albumTextContainer.setTint(false)
- binding.artistContainer.setTint(false)
- binding.albumArtistContainer.setTint(false)
- binding.yearContainer.setTint(false)
- binding.genreContainer.setTint(false)
- binding.trackNumberContainer.setTint(false)
- binding.discNumberContainer.setTint(false)
- binding.lyricsContainer.setTint(false)
+ MaterialUtil.setTint(songTextContainer, false)
+ MaterialUtil.setTint(composerContainer, false)
+ MaterialUtil.setTint(albumTextContainer, false)
+ MaterialUtil.setTint(artistContainer, false)
+ MaterialUtil.setTint(albumArtistContainer, false)
+ MaterialUtil.setTint(yearContainer, false)
+ MaterialUtil.setTint(genreContainer, false)
+ MaterialUtil.setTint(trackNumberContainer, false)
+ MaterialUtil.setTint(lyricsContainer, false)
- binding.songText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.albumText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.albumArtistText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.artistText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.genreText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.yearText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.trackNumberText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.discNumberText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.lyricsText.appHandleColor().doAfterTextChanged { dataChanged() }
- binding.songComposerText.appHandleColor().doAfterTextChanged { dataChanged() }
+ songText.appHandleColor().addTextChangedListener(this)
+ albumText.appHandleColor().addTextChangedListener(this)
+ albumArtistText.appHandleColor().addTextChangedListener(this)
+ artistText.appHandleColor().addTextChangedListener(this)
+ genreText.appHandleColor().addTextChangedListener(this)
+ yearText.appHandleColor().addTextChangedListener(this)
+ trackNumberText.appHandleColor().addTextChangedListener(this)
+ lyricsText.appHandleColor().addTextChangedListener(this)
+ songComposerText.appHandleColor().addTextChangedListener(this)
}
private fun fillViewsWithFileTags() {
- binding.songText.setText(songTitle)
- binding.albumArtistText.setText(albumArtist)
- binding.albumText.setText(albumTitle)
- binding.artistText.setText(artistName)
- binding.genreText.setText(genreName)
- binding.yearText.setText(songYear)
- binding.trackNumberText.setText(trackNumber)
- binding.discNumberText.setText(discNumber)
- binding.lyricsText.setText(lyrics)
- binding.songComposerText.setText(composer)
- logD(songTitle + songYear)
+ songText.setText(songTitle)
+ albumArtistText.setText(albumArtist)
+ albumText.setText(albumTitle)
+ artistText.setText(artistName)
+ genreText.setText(genreName)
+ yearText.setText(songYear)
+ trackNumberText.setText(trackNumber)
+ lyricsText.setText(lyrics)
+ songComposerText.setText(composer)
}
override fun loadCurrentImage() {
- val bitmap = albumArt
- setImageBitmap(
- bitmap,
- RetroColorUtil.getColor(
- RetroColorUtil.generatePalette(bitmap),
- defaultFooterColor()
- )
- )
- deleteAlbumArt = false
+
}
override fun searchImageOnWeb() {
- searchWebFor(binding.songText.text.toString(), binding.artistText.text.toString())
+
}
override fun deleteImage() {
- setImageBitmap(
- BitmapFactory.decodeResource(resources, R.drawable.default_audio_art),
- defaultFooterColor()
- )
- deleteAlbumArt = true
- dataChanged()
- }
- override fun setColors(color: Int) {
- super.setColors(color)
- saveFab.backgroundTintList = ColorStateList.valueOf(color)
- ColorStateList.valueOf(
- MaterialValueHelper.getPrimaryTextColor(
- this,
- color.isColorLight
- )
- ).also {
- saveFab.iconTint = it
- saveFab.setTextColor(it)
- }
}
override fun save() {
val fieldKeyValueMap = EnumMap(FieldKey::class.java)
- fieldKeyValueMap[FieldKey.TITLE] = binding.songText.text.toString()
- fieldKeyValueMap[FieldKey.ALBUM] = binding.albumText.text.toString()
- fieldKeyValueMap[FieldKey.ARTIST] = binding.artistText.text.toString()
- fieldKeyValueMap[FieldKey.GENRE] = binding.genreText.text.toString()
- fieldKeyValueMap[FieldKey.YEAR] = binding.yearText.text.toString()
- fieldKeyValueMap[FieldKey.TRACK] = binding.trackNumberText.text.toString()
- fieldKeyValueMap[FieldKey.DISC_NO] = binding.discNumberText.text.toString()
- fieldKeyValueMap[FieldKey.LYRICS] = binding.lyricsText.text.toString()
- fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = binding.albumArtistText.text.toString()
- fieldKeyValueMap[FieldKey.COMPOSER] = binding.songComposerText.text.toString()
- writeValuesToFiles(
- fieldKeyValueMap, when {
- deleteAlbumArt -> ArtworkInfo(id, null)
- albumArtBitmap == null -> null
- else -> ArtworkInfo(id, albumArtBitmap!!)
- }
- )
+ fieldKeyValueMap[FieldKey.TITLE] = songText.text.toString()
+ fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
+ fieldKeyValueMap[FieldKey.ARTIST] = artistText.text.toString()
+ fieldKeyValueMap[FieldKey.GENRE] = genreText.text.toString()
+ fieldKeyValueMap[FieldKey.YEAR] = yearText.text.toString()
+ fieldKeyValueMap[FieldKey.TRACK] = trackNumberText.text.toString()
+ fieldKeyValueMap[FieldKey.LYRICS] = lyricsText.text.toString()
+ fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString()
+ fieldKeyValueMap[FieldKey.COMPOSER] = songComposerText.text.toString()
+ writeValuesToFiles(fieldKeyValueMap, null)
}
- override fun getSongPaths(): List = listOf(songRepository.song(id).data)
-
- override fun getSongUris(): List = listOf(MusicUtil.getSongFileUri(id))
+ override fun getSongPaths(): List {
+ val paths = ArrayList(1)
+ paths.add(SongLoader.getSong(this, id).data)
+ return paths
+ }
override fun loadImageFromFile(selectedFile: Uri?) {
- Glide.with(this@SongTagEditorActivity)
- .asBitmapPalette()
- .load(selectedFile)
- .diskCacheStrategy(DiskCacheStrategy.NONE)
- .skipMemoryCache(true)
- .into(object : ImageViewTarget(binding.editorImage) {
- override fun onResourceReady(
- resource: BitmapPaletteWrapper,
- transition: Transition?
- ) {
- RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT)
- albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
- setImageBitmap(
- albumArtBitmap,
- RetroColorUtil.getColor(
- resource.palette,
- defaultFooterColor()
- )
- )
- deleteAlbumArt = false
- dataChanged()
- setResult(Activity.RESULT_OK)
- }
- override fun onLoadFailed(errorDrawable: Drawable?) {
- super.onLoadFailed(errorDrawable)
- showToast(R.string.error_load_failed, Toast.LENGTH_LONG)
- }
+ }
- override fun setResource(resource: BitmapPaletteWrapper?) {}
- })
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ dataChanged()
}
companion object {
val TAG: String = SongTagEditorActivity::class.java.simpleName
}
-
- override val editorImage: ImageView
- get() = binding.editorImage
}
+
+
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt
deleted file mode 100644
index b9d5f28dd..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt
+++ /dev/null
@@ -1,204 +0,0 @@
-package code.name.monkey.retromusic.activities.tageditor
-
-import android.app.Activity
-import android.content.Context
-import android.graphics.Bitmap
-import android.media.MediaScannerConnection
-import android.os.Build
-import android.util.Log
-import androidx.annotation.RequiresApi
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.extensions.showToast
-import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener
-import code.name.monkey.retromusic.model.AudioTagInfo
-import code.name.monkey.retromusic.util.MusicUtil.createAlbumArtFile
-import code.name.monkey.retromusic.util.MusicUtil.deleteAlbumArt
-import code.name.monkey.retromusic.util.MusicUtil.insertAlbumArt
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-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.FieldDataInvalidException
-import org.jaudiotagger.tag.TagException
-import org.jaudiotagger.tag.images.AndroidArtwork
-import org.jaudiotagger.tag.images.Artwork
-import java.io.File
-import java.io.IOException
-
-class TagWriter {
-
- companion object {
-
- suspend fun scan(context: Context, toBeScanned: List?) {
- if (toBeScanned.isNullOrEmpty()) {
- Log.i("scan", "scan: Empty")
- context.showToast("Scan file from folder")
- return
- }
- MediaScannerConnection.scanFile(
- context,
- toBeScanned.toTypedArray(),
- null,
- withContext(Dispatchers.Main) {
- if (context is Activity) UpdateToastMediaScannerCompletionListener(
- context, toBeScanned
- ) else null
- }
- )
- }
-
- suspend fun writeTagsToFiles(context: Context, info: AudioTagInfo) {
- withContext(Dispatchers.IO) {
- var artwork: Artwork? = null
- var albumArtFile: File? = null
- if (info.artworkInfo?.artwork != null) {
- try {
- albumArtFile = createAlbumArtFile(context).canonicalFile
- info.artworkInfo.artwork.compress(
- Bitmap.CompressFormat.JPEG,
- 100,
- albumArtFile.outputStream()
- )
- artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- var wroteArtwork = false
- var deletedArtwork = false
- for (filePath in info.filePaths!!) {
- try {
- val audioFile = AudioFileIO.read(File(filePath))
- val tag = audioFile.tagOrCreateAndSetDefault
- if (info.fieldKeyValueMap != null) {
- for ((key, value) in info.fieldKeyValueMap) {
- try {
- tag.setField(key, value)
- } catch (e: FieldDataInvalidException) {
- withContext(Dispatchers.Main) {
- context.showToast(R.string.could_not_write_tags_to_file)
- }
- return@withContext listOf()
- } catch (e: Exception) {
- 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 (e: CannotReadException) {
- e.printStackTrace()
- } catch (e: IOException) {
- e.printStackTrace()
- } catch (e: CannotWriteException) {
- e.printStackTrace()
- } catch (e: TagException) {
- e.printStackTrace()
- } catch (e: ReadOnlyFileException) {
- e.printStackTrace()
- } catch (e: InvalidAudioFrameException) {
- e.printStackTrace()
- }
- }
- if (wroteArtwork) {
- insertAlbumArt(context, info.artworkInfo!!.albumId, albumArtFile!!.path)
- } else if (deletedArtwork) {
- deleteAlbumArt(context, info.artworkInfo!!.albumId)
- }
- scan(context, info.filePaths)
- }
- }
-
- @RequiresApi(Build.VERSION_CODES.R)
- suspend fun writeTagsToFilesR(context: Context, info: AudioTagInfo): List =
- withContext(Dispatchers.IO) {
- val cacheFiles = mutableListOf()
- var artwork: Artwork? = null
- var albumArtFile: File? = null
- if (info.artworkInfo?.artwork != null) {
- try {
- albumArtFile = createAlbumArtFile(context).canonicalFile
- info.artworkInfo.artwork.compress(
- Bitmap.CompressFormat.JPEG,
- 100,
- albumArtFile.outputStream()
- )
- artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- var wroteArtwork = false
- var deletedArtwork = false
- for (filePath in info.filePaths!!) {
- try {
- val originFile = File(filePath)
- val cacheFile = File(context.cacheDir, originFile.name)
- cacheFiles.add(cacheFile)
- originFile.inputStream().use { input ->
- cacheFile.outputStream().use { output ->
- input.copyTo(output)
- }
- }
- val audioFile = AudioFileIO.read(cacheFile)
- val tag = audioFile.tagOrCreateAndSetDefault
- if (info.fieldKeyValueMap != null) {
- for ((key, value) in info.fieldKeyValueMap) {
- try {
- tag.setField(key, value)
- } catch (e: FieldDataInvalidException) {
- withContext(Dispatchers.Main) {
- context.showToast(R.string.could_not_write_tags_to_file)
- }
- return@withContext listOf()
- } catch (e: Exception) {
- 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 (e: CannotReadException) {
- e.printStackTrace()
- } catch (e: IOException) {
- e.printStackTrace()
- } catch (e: CannotWriteException) {
- e.printStackTrace()
- } catch (e: TagException) {
- e.printStackTrace()
- } catch (e: ReadOnlyFileException) {
- e.printStackTrace()
- } catch (e: InvalidAudioFrameException) {
- e.printStackTrace()
- }
- }
- if (wroteArtwork) {
- insertAlbumArt(context, info.artworkInfo!!.albumId, albumArtFile!!.path)
- } else if (deletedArtwork) {
- deleteAlbumArt(context, info.artworkInfo!!.albumId)
- }
- cacheFiles
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/WriteTagsAsyncTask.java b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/WriteTagsAsyncTask.java
new file mode 100644
index 000000000..d9bfb86af
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/WriteTagsAsyncTask.java
@@ -0,0 +1,188 @@
+package code.name.monkey.retromusic.activities.tageditor;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
+import org.jaudiotagger.audio.AudioFile;
+import org.jaudiotagger.audio.AudioFileIO;
+import org.jaudiotagger.tag.FieldKey;
+import org.jaudiotagger.tag.Tag;
+import org.jaudiotagger.tag.images.Artwork;
+import org.jaudiotagger.tag.images.ArtworkFactory;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+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 code.name.monkey.retromusic.util.SAFUtil;
+
+public class WriteTagsAsyncTask extends
+ DialogAsyncTask {
+
+ private WeakReference activity;
+
+ public WriteTagsAsyncTask(@NonNull Activity activity) {
+ super(activity);
+ this.activity = new WeakReference<>(activity);
+ }
+
+ @Override
+ protected String[] doInBackground(LoadingInfo... params) {
+ try {
+ LoadingInfo info = params[0];
+
+ Artwork artwork = null;
+ File albumArtFile = null;
+ if (info.artworkInfo != null && info.artworkInfo.getArtwork() != null) {
+ try {
+ albumArtFile = MusicUtil.createAlbumArtFile().getCanonicalFile();
+ info.artworkInfo.getArtwork()
+ .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 {
+ Uri safUri = null;
+ if (filePath.contains(SAFUtil.SEPARATOR)) {
+ String[] fragments = filePath.split(SAFUtil.SEPARATOR);
+ filePath = fragments[0];
+ safUri = Uri.parse(fragments[1]);
+ }
+
+ AudioFile audioFile = AudioFileIO.read(new File(filePath));
+ Tag tag = audioFile.getTagOrCreateAndSetDefault();
+
+ if (info.fieldKeyValueMap != null) {
+ for (Map.Entry entry : info.fieldKeyValueMap.entrySet()) {
+ try {
+ tag.setField(entry.getKey(), entry.getValue());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ if (info.artworkInfo != null) {
+ if (info.artworkInfo.getArtwork() == null) {
+ tag.deleteArtworkField();
+ deletedArtwork = true;
+ } else if (artwork != null) {
+ tag.deleteArtworkField();
+ tag.setField(artwork);
+ wroteArtwork = true;
+ }
+ }
+
+ Activity activity = this.activity.get();
+ SAFUtil.write(activity, audioFile, safUri);
+
+ } catch (@NonNull Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ Context context = getContext();
+ if (context != null) {
+ if (wroteArtwork) {
+ MusicUtil.insertAlbumArt(context, info.artworkInfo.getAlbumId(), albumArtFile.getPath());
+ } else if (deletedArtwork) {
+ MusicUtil.deleteAlbumArt(context, info.artworkInfo.getAlbumId());
+ }
+ }
+
+ Collection paths = info.filePaths;
+ if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
+ paths = new ArrayList<>(info.filePaths.size());
+ for (String path : info.filePaths) {
+ if (path.contains(SAFUtil.SEPARATOR))
+ path = path.split(SAFUtil.SEPARATOR)[0];
+ paths.add(path);
+ }
+ }
+
+ return paths.toArray(new String[paths.size()]);
+ } 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) {
+ Activity activity = this.activity.get();
+ if (activity != null) {
+ MediaScannerConnection.scanFile(activity, toBeScanned, null, new UpdateToastMediaScannerCompletionListener(activity, toBeScanned));
+ }
+ }
+
+ @NonNull
+ @Override
+ protected Dialog createDialog(@NonNull Context context) {
+ return new MaterialAlertDialogBuilder(context)
+ .setTitle(R.string.saving_changes)
+ .setCancelable(false)
+ .setView(R.layout.loading)
+ .create();
+ }
+
+ @Override
+ 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/adapter/CategoryInfoAdapter.java b/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java
new file mode 100644
index 000000000..83273edc9
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2019 Hemanth Savarala.
+ *
+ * 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.adapter;
+
+import android.annotation.SuppressLint;
+import android.content.res.ColorStateList;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.ItemTouchHelper;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.checkbox.MaterialCheckBox;
+
+import java.util.List;
+
+import code.name.monkey.appthemehelper.ThemeStore;
+import code.name.monkey.retromusic.R;
+import code.name.monkey.retromusic.model.CategoryInfo;
+import code.name.monkey.retromusic.util.SwipeAndDragHelper;
+
+public class CategoryInfoAdapter extends RecyclerView.Adapter implements SwipeAndDragHelper.ActionCompletionContract {
+ private List categoryInfos;
+ private ItemTouchHelper touchHelper;
+
+ public CategoryInfoAdapter(@NonNull List categoryInfos) {
+ this.categoryInfos = categoryInfos;
+ SwipeAndDragHelper swipeAndDragHelper = new SwipeAndDragHelper(this);
+ touchHelper = new ItemTouchHelper(swipeAndDragHelper);
+ }
+
+ @Override
+ @NonNull
+ public CategoryInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.preference_dialog_library_categories_listitem, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
+ CategoryInfo categoryInfo = categoryInfos.get(position);
+
+ holder.checkBox.setChecked(categoryInfo.visible);
+ holder.title.setText(holder.title.getResources().getString(categoryInfo.category.stringRes));
+
+ holder.itemView.setOnClickListener(v -> {
+ if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) {
+ categoryInfo.visible = !categoryInfo.visible;
+ holder.checkBox.setChecked(categoryInfo.visible);
+ } else {
+ Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category, Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ holder.dragView.setOnTouchListener((view, event) -> {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ touchHelper.startDrag(holder);
+ }
+ return false;
+ }
+ );
+ }
+
+ @Override
+ public int getItemCount() {
+ return categoryInfos.size();
+ }
+
+ @Override
+ public void onViewMoved(int oldPosition, int newPosition) {
+ CategoryInfo categoryInfo = categoryInfos.get(oldPosition);
+ categoryInfos.remove(oldPosition);
+ categoryInfos.add(newPosition, categoryInfo);
+ notifyItemMoved(oldPosition, newPosition);
+ }
+
+ public void attachToRecyclerView(RecyclerView recyclerView) {
+ touchHelper.attachToRecyclerView(recyclerView);
+ }
+
+ @NonNull
+ public List getCategoryInfos() {
+ return categoryInfos;
+ }
+
+ public void setCategoryInfos(@NonNull List categoryInfos) {
+ this.categoryInfos = categoryInfos;
+ notifyDataSetChanged();
+ }
+
+ private boolean isLastCheckedCategory(CategoryInfo categoryInfo) {
+ if (categoryInfo.visible) {
+ for (CategoryInfo c : categoryInfos) {
+ if (c != categoryInfo && c.visible) return false;
+ }
+ }
+ return true;
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ MaterialCheckBox checkBox;
+ TextView title;
+ View dragView;
+
+ ViewHolder(View view) {
+ super(view);
+ checkBox = view.findViewById(R.id.checkbox);
+ checkBox.setButtonTintList(ColorStateList.valueOf(ThemeStore.Companion.accentColor(checkBox.getContext())));
+ title = view.findViewById(R.id.title);
+ dragView = view.findViewById(R.id.drag_view);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.kt
deleted file mode 100644
index dd5cda1d3..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 2019 Hemanth Savarala.
- *
- * 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.adapter
-
-import android.annotation.SuppressLint
-import android.content.res.ColorStateList
-import android.view.LayoutInflater
-import android.view.MotionEvent
-import android.view.View
-import android.view.ViewGroup
-import androidx.recyclerview.widget.ItemTouchHelper
-import androidx.recyclerview.widget.RecyclerView
-import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.databinding.PreferenceDialogLibraryCategoriesListitemBinding
-import code.name.monkey.retromusic.extensions.showToast
-import code.name.monkey.retromusic.model.CategoryInfo
-import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.SwipeAndDragHelper
-import code.name.monkey.retromusic.util.SwipeAndDragHelper.ActionCompletionContract
-
-class CategoryInfoAdapter : RecyclerView.Adapter(),
- ActionCompletionContract {
- var categoryInfos: MutableList =
- PreferenceUtil.libraryCategory.toMutableList()
- @SuppressLint("NotifyDataSetChanged")
- set(value) {
- field = value
- notifyDataSetChanged()
- }
- private val touchHelper: ItemTouchHelper
- fun attachToRecyclerView(recyclerView: RecyclerView?) {
- touchHelper.attachToRecyclerView(recyclerView)
- }
-
- override fun getItemCount(): Int {
- return categoryInfos.size
- }
-
- @SuppressLint("ClickableViewAccessibility")
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val categoryInfo = categoryInfos[position]
- holder.binding.checkbox.isChecked = categoryInfo.visible
- holder.binding.title.text =
- holder.binding.title.resources.getString(categoryInfo.category.stringRes)
- holder.itemView.setOnClickListener {
- if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) {
- categoryInfo.visible = !categoryInfo.visible
- holder.binding.checkbox.isChecked = categoryInfo.visible
- } else {
- holder.itemView.context.showToast(R.string.you_have_to_select_at_least_one_category)
- }
- }
- holder.binding.dragView.setOnTouchListener { _: View?, event: MotionEvent ->
- if (event.actionMasked == MotionEvent.ACTION_DOWN) {
- touchHelper.startDrag(holder)
- }
- false
- }
- }
-
- override fun onCreateViewHolder(
- parent: ViewGroup, viewType: Int
- ): ViewHolder {
- return ViewHolder(
- PreferenceDialogLibraryCategoriesListitemBinding.inflate(
- LayoutInflater.from(
- parent.context
- ), parent, false
- )
- )
- }
-
- override fun onViewMoved(oldPosition: Int, newPosition: Int) {
- val categoryInfo = categoryInfos[oldPosition]
- categoryInfos.removeAt(oldPosition)
- categoryInfos.add(newPosition, categoryInfo)
- notifyItemMoved(oldPosition, newPosition)
- }
-
- private fun isLastCheckedCategory(categoryInfo: CategoryInfo): Boolean {
- if (categoryInfo.visible) {
- for (c in categoryInfos) {
- if (c !== categoryInfo && c.visible) {
- return false
- }
- }
- }
- return true
- }
-
- class ViewHolder(val binding: PreferenceDialogLibraryCategoriesListitemBinding) :
- RecyclerView.ViewHolder(binding.root) {
-
- init {
- binding.checkbox.buttonTintList =
- ColorStateList.valueOf(accentColor(binding.checkbox.context))
- }
- }
-
- init {
- val swipeAndDragHelper = SwipeAndDragHelper(this)
- touchHelper = ItemTouchHelper(swipeAndDragHelper)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt
new file mode 100644
index 000000000..df7fec524
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt
@@ -0,0 +1,74 @@
+package code.name.monkey.retromusic.adapter
+
+import android.app.Activity
+import android.view.*
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.model.Contributor
+import code.name.monkey.retromusic.util.RetroUtil.openUrl
+import code.name.monkey.retromusic.views.CircularImageView
+import com.bumptech.glide.Glide
+
+class ContributorAdapter(
+ private var contributors: List
+) : RecyclerView.Adapter() {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ return if (viewType == HEADER) {
+ ViewHolder(
+ LayoutInflater.from(parent.context).inflate(
+ R.layout.item_contributor_header,
+ parent,
+ false
+ )
+ )
+ } else ViewHolder(
+ LayoutInflater.from(parent.context).inflate(
+ R.layout.item_contributor,
+ parent,
+ false
+ )
+ )
+ }
+
+ companion object {
+ const val HEADER: Int = 0
+ const val ITEM: Int = 1
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return if (position == 0) {
+ HEADER
+ } else {
+ ITEM
+ }
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val contributor = contributors[position]
+ holder.bindData(contributor)
+ holder.itemView.setOnClickListener {
+ openUrl(it?.context as Activity, contributors[position].link)
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return contributors.size
+ }
+
+ inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ val title: TextView = itemView.findViewById(R.id.title)
+ val text: TextView = itemView.findViewById(R.id.text)
+ val image: CircularImageView = itemView.findViewById(R.id.icon)
+
+ internal fun bindData(contributor: Contributor) {
+ title.text = contributor.name
+ text.text = contributor.summary
+ println(contributor.profileImage)
+ Glide.with(image.context).load(contributor.profileImage)
+ .error(R.drawable.ic_account_white_24dp)
+ .placeholder(R.drawable.ic_account_white_24dp).dontAnimate().into(image)
+ }
+ }
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/GenreAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/GenreAdapter.kt
index b139a0af8..d8166e4f1 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/GenreAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/GenreAdapter.kt
@@ -1,37 +1,14 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.adapter
-import android.annotation.SuppressLint
+import android.app.Activity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.view.ViewOutlineProvider
-import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.databinding.ItemGenreBinding
-import code.name.monkey.retromusic.glide.RetroGlideExtension
-import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
-import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions
-import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
-import code.name.monkey.retromusic.interfaces.IGenreClickListener
+import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.model.Genre
-import code.name.monkey.retromusic.util.MusicUtil
-import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
-import com.bumptech.glide.Glide
+import code.name.monkey.retromusic.util.NavigationUtil
import java.util.*
/**
@@ -39,74 +16,39 @@ import java.util.*
*/
class GenreAdapter(
- private val activity: FragmentActivity,
- var dataSet: List,
- private val listener: IGenreClickListener
+ private val activity: Activity, dataSet: ArrayList, private val mItemLayoutRes: Int
) : RecyclerView.Adapter() {
+ var dataSet = ArrayList()
+ private set
init {
- this.setHasStableIds(true)
- }
-
- override fun getItemId(position: Int): Long {
- return dataSet[position].id
+ this.dataSet = dataSet
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- return ViewHolder(ItemGenreBinding.inflate(LayoutInflater.from(activity), parent, false))
+ return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val genre = dataSet[position]
- holder.binding.title.text = genre.name
- holder.binding.text.text = String.format(
- Locale.getDefault(),
- "%d %s",
- genre.songCount,
- if (genre.songCount > 1) activity.getString(R.string.songs) else activity.getString(R.string.song)
- )
- loadGenreImage(genre, holder)
- }
-
- private fun loadGenreImage(genre: Genre, holder: GenreAdapter.ViewHolder) {
- val genreSong = MusicUtil.songByGenre(genre.id)
- Glide.with(activity)
- .asBitmapPalette()
- .songCoverOptions(genreSong)
- .load(RetroGlideExtension.getSongModel(genreSong))
- .into(object : RetroMusicColoredTarget(holder.binding.image) {
- override fun onColorReady(colors: MediaNotificationProcessor) {
- setColors(holder, colors)
- }
- })
- // Just for a bit of shadow around image
- holder.binding.image.outlineProvider = ViewOutlineProvider.BOUNDS
- }
-
- private fun setColors(holder: ViewHolder, color: MediaNotificationProcessor) {
- holder.binding.imageContainerCard.setCardBackgroundColor(color.backgroundColor)
- holder.binding.title.setTextColor(color.primaryTextColor)
- holder.binding.text.setTextColor(color.secondaryTextColor)
+ holder.title?.text = genre.name
+ holder.text?.text = String.format(Locale.getDefault(), "%d %s", genre.songCount, if (genre.songCount > 1) activity.getString(R.string.songs) else activity.getString(R.string.song))
}
override fun getItemCount(): Int {
return dataSet.size
}
- @SuppressLint("NotifyDataSetChanged")
- fun swapDataSet(list: List) {
+ fun swapDataSet(list: ArrayList) {
dataSet = list
notifyDataSetChanged()
}
- inner class ViewHolder(val binding: ItemGenreBinding) : RecyclerView.ViewHolder(binding.root),
- View.OnClickListener {
+ inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
override fun onClick(v: View?) {
- listener.onClickGenre(dataSet[layoutPosition], itemView)
- }
-
- init {
- itemView.setOnClickListener(this)
+ super.onClick(v)
+ val genre = dataSet[adapterPosition]
+ NavigationUtil.goToGenre(activity, genre)
}
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt
index e3f809b5f..4ce778201 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt
@@ -1,124 +1,70 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.adapter
-import android.annotation.SuppressLint
+import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.annotation.IntDef
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatTextView
-import androidx.core.os.bundleOf
-import androidx.fragment.app.findFragment
-import androidx.navigation.findNavController
-import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.recyclerview.widget.GridLayoutManager
-import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import code.name.monkey.retromusic.*
-import code.name.monkey.retromusic.adapter.album.AlbumAdapter
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.album.album.AlbumFullWidthAdapter
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
import code.name.monkey.retromusic.adapter.song.SongAdapter
-import code.name.monkey.retromusic.fragments.home.HomeFragment
-import code.name.monkey.retromusic.interfaces.IAlbumClickListener
-import code.name.monkey.retromusic.interfaces.IArtistClickListener
+import code.name.monkey.retromusic.extensions.show
+import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Home
-import code.name.monkey.retromusic.model.Song
+import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.util.PreferenceUtil
-class HomeAdapter(private val activity: AppCompatActivity) :
- RecyclerView.Adapter(), IArtistClickListener, IAlbumClickListener {
+class HomeAdapter(
+ private val activity: AppCompatActivity, private val displayMetrics: DisplayMetrics
+) : RecyclerView.Adapter() {
- private var list = listOf()
+ private var list = ArrayList()
override fun getItemViewType(position: Int): Int {
return list[position].homeSection
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
- val layout =
- LayoutInflater.from(activity).inflate(R.layout.section_recycler_view, parent, false)
+ val layout = LayoutInflater.from(activity)
+ .inflate(R.layout.section_recycler_view, parent, false)
return when (viewType) {
RECENT_ARTISTS, TOP_ARTISTS -> ArtistViewHolder(layout)
- FAVOURITES -> PlaylistViewHolder(layout)
- TOP_ALBUMS, RECENT_ALBUMS -> AlbumViewHolder(layout)
+ PLAYLISTS -> PlaylistViewHolder(layout)
else -> {
- ArtistViewHolder(layout)
+ AlbumViewHolder(LayoutInflater.from(activity).inflate(R.layout.metal_section_recycler_view, parent, false))
}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- val home = list[position]
+ println("ViewType ${getItemViewType(position)}")
when (getItemViewType(position)) {
RECENT_ALBUMS -> {
val viewHolder = holder as AlbumViewHolder
- viewHolder.bindView(home)
- viewHolder.clickableArea.setOnClickListener {
- it.findFragment().setSharedAxisXTransitions()
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.detailListFragment,
- bundleOf("type" to RECENT_ALBUMS)
- )
- }
+ viewHolder.bindView(list[position].arrayList.toAlbums(), R.string.recent_albums)
}
TOP_ALBUMS -> {
val viewHolder = holder as AlbumViewHolder
- viewHolder.bindView(home)
- viewHolder.clickableArea.setOnClickListener {
- it.findFragment().setSharedAxisXTransitions()
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.detailListFragment,
- bundleOf("type" to TOP_ALBUMS)
- )
- }
+ viewHolder.bindView(list[position].arrayList.toAlbums(), R.string.top_albums)
}
RECENT_ARTISTS -> {
val viewHolder = holder as ArtistViewHolder
- viewHolder.bindView(home)
- viewHolder.clickableArea.setOnClickListener {
- it.findFragment().setSharedAxisXTransitions()
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.detailListFragment,
- bundleOf("type" to RECENT_ARTISTS)
- )
- }
+ viewHolder.bindView(list[position].arrayList.toArtists(), R.string.recent_artists)
}
TOP_ARTISTS -> {
val viewHolder = holder as ArtistViewHolder
- viewHolder.bindView(home)
- viewHolder.clickableArea.setOnClickListener {
- it.findFragment().setSharedAxisXTransitions()
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.detailListFragment,
- bundleOf("type" to TOP_ARTISTS)
- )
- }
+ viewHolder.bindView(list[position].arrayList.toArtists(), R.string.top_artists)
}
- FAVOURITES -> {
+ PLAYLISTS -> {
val viewHolder = holder as PlaylistViewHolder
- viewHolder.bindView(home)
- viewHolder.clickableArea.setOnClickListener {
- it.findFragment().setSharedAxisXTransitions()
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.detailListFragment,
- bundleOf("type" to FAVOURITES)
- )
- }
+ viewHolder.bindView(list[position].arrayList.toPlaylist(), R.string.favorites)
}
}
}
@@ -127,87 +73,108 @@ class HomeAdapter(private val activity: AppCompatActivity) :
return list.size
}
- @SuppressLint("NotifyDataSetChanged")
- fun swapData(sections: List) {
+ fun swapData(sections: ArrayList) {
list = sections
notifyDataSetChanged()
}
- @Suppress("UNCHECKED_CAST")
+ companion object {
+
+ @IntDef(RECENT_ALBUMS, TOP_ALBUMS, RECENT_ARTISTS, TOP_ARTISTS, PLAYLISTS)
+ @Retention(AnnotationRetention.SOURCE)
+ annotation class HomeSection
+
+ const val RECENT_ALBUMS = 3
+ const val TOP_ALBUMS = 1
+ const val RECENT_ARTISTS = 2
+ const val TOP_ARTISTS = 0
+ const val PLAYLISTS = 4
+
+ }
+
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
- fun bindView(home: Home) {
- title.setText(home.titleRes)
- recyclerView.apply {
- adapter = albumAdapter(home.arrayList as List)
- layoutManager = gridLayoutManager()
+ fun bindView(list: ArrayList, titleRes: Int) {
+ if (list.isNotEmpty()) {
+ recyclerView.apply {
+ show()
+ adapter = AlbumFullWidthAdapter(activity, list, displayMetrics)
+ }
+ title.text = activity.getString(titleRes)
}
}
}
- @Suppress("UNCHECKED_CAST")
- private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
- fun bindView(home: Home) {
- title.setText(home.titleRes)
- recyclerView.apply {
- layoutManager = linearLayoutManager()
- adapter = artistsAdapter(home.arrayList as List)
+ inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
+ fun bindView(list: ArrayList, titleRes: Int) {
+ if (list.isNotEmpty()) {
+ recyclerView.apply {
+ show()
+ layoutManager = GridLayoutManager(
+ activity, 1, GridLayoutManager.HORIZONTAL, false
+ )
+ val artistAdapter = ArtistAdapter(
+ activity,
+ list,
+ PreferenceUtil.getInstance(activity).getHomeGridStyle(activity),
+ false,
+ null
+ )
+ adapter = artistAdapter
+ }
+ title.text = activity.getString(titleRes)
}
}
}
- @Suppress("UNCHECKED_CAST")
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
- fun bindView(home: Home) {
- title.setText(home.titleRes)
- recyclerView.apply {
- val songAdapter = SongAdapter(
- activity,
- home.arrayList as MutableList,
- R.layout.item_favourite_card
- )
- layoutManager = linearLayoutManager()
- adapter = songAdapter
+ fun bindView(arrayList: ArrayList, titleRes: Int) {
+ if (arrayList.isNotEmpty()) {
+ val songs = PlaylistSongsLoader.getPlaylistSongList(activity, arrayList[0])
+ if (songs.isNotEmpty()) {
+ recyclerView.apply {
+ show()
+ val songAdapter = SongAdapter(
+ activity, songs, R.layout.item_album_card, false, null
+ )
+ layoutManager = GridLayoutManager(
+ activity, 1, GridLayoutManager.HORIZONTAL, false
+ )
+ adapter = songAdapter
+
+ }
+ title.text = activity.getString(titleRes)
+ }
}
}
}
- open class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ open inner class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView)
val title: AppCompatTextView = itemView.findViewById(R.id.title)
- val clickableArea: ViewGroup = itemView.findViewById(R.id.clickable_area)
- }
-
- private fun artistsAdapter(artists: List) =
- ArtistAdapter(activity, artists, PreferenceUtil.homeArtistGridStyle, this)
-
- private fun albumAdapter(albums: List) =
- AlbumAdapter(activity, albums, PreferenceUtil.homeAlbumGridStyle, this)
-
- private fun gridLayoutManager() =
- GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
-
- private fun linearLayoutManager() =
- LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
-
- override fun onArtist(artistId: Long, view: View) {
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.artistDetailsFragment,
- bundleOf(EXTRA_ARTIST_ID to artistId),
- null,
- FragmentNavigatorExtras(
- view to artistId.toString()
- )
- )
- }
-
- override fun onAlbumClick(albumId: Long, view: View) {
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.albumDetailsFragment,
- bundleOf(EXTRA_ALBUM_ID to albumId),
- null,
- FragmentNavigatorExtras(
- view to albumId.toString()
- )
- )
}
}
+
+private fun ArrayList.toAlbums(): ArrayList {
+ val arrayList = ArrayList()
+ for (x in this) {
+ arrayList.add(x as Album)
+ }
+ return arrayList;
+}
+
+private fun ArrayList.toArtists(): ArrayList {
+ val arrayList = ArrayList()
+ for (x in this) {
+ arrayList.add(x as Artist)
+ }
+ return arrayList;
+}
+
+private fun ArrayList.toPlaylist(): ArrayList {
+ val arrayList = ArrayList()
+ for (x in this) {
+ arrayList.add(x as Playlist)
+ }
+ return arrayList;
+}
+
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt
index 22a60bd95..dc5c066d4 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt
@@ -1,38 +1,16 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.adapter
-import android.annotation.SuppressLint
+import android.app.ActivityOptions
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.core.os.bundleOf
-import androidx.core.view.isGone
-import androidx.core.view.isInvisible
-import androidx.core.view.isVisible
-import androidx.fragment.app.FragmentActivity
-import androidx.navigation.findNavController
+import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore
-import code.name.monkey.retromusic.*
+import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
-import code.name.monkey.retromusic.db.PlaylistWithSongs
-import code.name.monkey.retromusic.glide.RetroGlideExtension
-import code.name.monkey.retromusic.glide.RetroGlideExtension.albumCoverOptions
-import code.name.monkey.retromusic.glide.RetroGlideExtension.artistImageOptions
-import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions
+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.model.Album
@@ -40,137 +18,80 @@ import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
+import code.name.monkey.retromusic.util.NavigationUtil
import com.bumptech.glide.Glide
-import java.util.*
+import android.util.Pair as UtilPair
class SearchAdapter(
- private val activity: FragmentActivity,
- private var dataSet: List
+ private val activity: AppCompatActivity, private var dataSet: List?
) : RecyclerView.Adapter() {
- @SuppressLint("NotifyDataSetChanged")
- fun swapDataSet(dataSet: List) {
+ fun swapDataSet(dataSet: MutableList) {
this.dataSet = dataSet
notifyDataSetChanged()
}
override fun getItemViewType(position: Int): Int {
- if (dataSet[position] is Album) return ALBUM
- if (dataSet[position] is Artist) return if ((dataSet[position] as Artist).isAlbumArtist) ALBUM_ARTIST else ARTIST
- if (dataSet[position] is Genre) return GENRE
- if (dataSet[position] is PlaylistWithSongs) return PLAYLIST
- return if (dataSet[position] is Song) SONG else HEADER
+ if (dataSet!![position] is Album) return ALBUM
+ if (dataSet!![position] is Artist) return ARTIST
+ if (dataSet!![position] is Genre) return GENRE
+ return if (dataSet!![position] is Song) SONG else HEADER
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- return when (viewType) {
- HEADER -> ViewHolder(
- LayoutInflater.from(activity).inflate(
- R.layout.sub_header,
- parent,
- false
- ), viewType
- )
-
- ALBUM, ARTIST, ALBUM_ARTIST -> ViewHolder(
- LayoutInflater.from(activity).inflate(
- R.layout.item_list_big,
- parent,
- false
- ), viewType
- )
-
- else -> ViewHolder(
- LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false),
- viewType
- )
- }
+ return if (viewType == HEADER) ViewHolder(LayoutInflater.from(activity).inflate(R.layout.sub_header, parent, false), viewType)
+ else
+ ViewHolder(LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false), viewType)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (getItemViewType(position)) {
ALBUM -> {
- holder.imageTextContainer?.isVisible = true
- val album = dataSet[position] as Album
+ val album = dataSet?.get(position) as Album
holder.title?.text = album.title
holder.text?.text = album.artistName
- Glide.with(activity).asDrawable().albumCoverOptions(album.safeGetFirstSong())
- .load(RetroGlideExtension.getSongModel(album.safeGetFirstSong()))
- .into(holder.image!!)
+ SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
+ .checkIgnoreMediaStore(activity).build().into(holder.image)
}
-
ARTIST -> {
- holder.imageTextContainer?.isVisible = true
- val artist = dataSet[position] as Artist
+ val artist = dataSet?.get(position) as Artist
holder.title?.text = artist.name
holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
- Glide.with(activity).asDrawable().artistImageOptions(artist).load(
- RetroGlideExtension.getArtistModel(artist)
- ).into(holder.image!!)
+ ArtistGlideRequest.Builder.from(Glide.with(activity), artist).build()
+ .into(holder.image)
}
-
SONG -> {
- holder.imageTextContainer?.isVisible = true
- val song = dataSet[position] as Song
+ val song = dataSet?.get(position) as Song
holder.title?.text = song.title
holder.text?.text = song.albumName
- Glide.with(activity).asDrawable().songCoverOptions(song)
- .load(RetroGlideExtension.getSongModel(song)).into(holder.image!!)
}
-
GENRE -> {
- val genre = dataSet[position] as Genre
+ val genre = dataSet?.get(position) as Genre
holder.title?.text = genre.name
- holder.text?.text = String.format(
- Locale.getDefault(),
- "%d %s",
- genre.songCount,
- if (genre.songCount > 1) activity.getString(R.string.songs) else activity.getString(
- R.string.song
- )
- )
}
-
- PLAYLIST -> {
- val playlist = dataSet[position] as PlaylistWithSongs
- holder.title?.text = playlist.playlistEntity.playlistName
- //holder.text?.text = MusicUtil.playlistInfoString(activity, playlist.songs)
- }
-
- ALBUM_ARTIST -> {
- holder.imageTextContainer?.isVisible = true
- val artist = dataSet[position] as Artist
- holder.title?.text = artist.name
- holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
- Glide.with(activity).asDrawable().artistImageOptions(artist).load(
- RetroGlideExtension.getArtistModel(artist)
- ).into(holder.image!!)
- }
-
else -> {
- holder.title?.text = dataSet[position].toString()
+ holder.title?.text = dataSet?.get(position).toString()
holder.title?.setTextColor(ThemeStore.accentColor(activity))
}
}
}
override fun getItemCount(): Int {
- return dataSet.size
+ return dataSet!!.size
}
inner class ViewHolder(itemView: View, itemViewType: Int) : MediaEntryViewHolder(itemView) {
init {
itemView.setOnLongClickListener(null)
- imageTextContainer?.isInvisible = true
+
if (itemViewType == SONG) {
- imageTextContainer?.isGone = true
- menu?.isVisible = true
+ menu?.visibility = View.VISIBLE
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
override val song: Song
- get() = dataSet[layoutPosition] as Song
+ get() = dataSet!![adapterPosition] as Song
})
} else {
- menu?.isVisible = false
+ menu?.visibility = View.GONE
}
when (itemViewType) {
@@ -178,52 +99,29 @@ class SearchAdapter(
ARTIST -> setImageTransitionName(activity.getString(R.string.transition_artist_image))
else -> {
val container = itemView.findViewById(R.id.imageContainer)
- container?.isVisible = false
+ container?.visibility = View.GONE
}
}
}
override fun onClick(v: View?) {
- val item = dataSet[layoutPosition]
+ val item = dataSet!![adapterPosition]
when (itemViewType) {
ALBUM -> {
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.albumDetailsFragment,
- bundleOf(EXTRA_ALBUM_ID to (item as Album).id)
- )
+ val options = ActivityOptions.makeSceneTransitionAnimation(activity, UtilPair.create(image, activity.getString(R.string.transition_album_art)))
+ NavigationUtil.goToAlbumOptions(activity, (item as Album).id, options)
}
-
ARTIST -> {
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.artistDetailsFragment,
- bundleOf(EXTRA_ARTIST_ID to (item as Artist).id)
- )
+ val options = ActivityOptions.makeSceneTransitionAnimation(activity, UtilPair.create(image, activity.getString(R.string.transition_artist_image)))
+ NavigationUtil.goToArtistOptions(activity, (item as Artist).id, options)
}
-
- ALBUM_ARTIST -> {
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.albumArtistDetailsFragment,
- bundleOf(EXTRA_ARTIST_NAME to (item as Artist).name)
- )
- }
-
GENRE -> {
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.genreDetailsFragment,
- bundleOf(EXTRA_GENRE to (item as Genre))
- )
+ NavigationUtil.goToGenre(activity, item as Genre)
}
-
- PLAYLIST -> {
- activity.findNavController(R.id.fragment_container).navigate(
- R.id.playlistDetailsFragment,
- bundleOf(EXTRA_PLAYLIST_ID to (item as PlaylistWithSongs).playlistEntity.playListId)
- )
- }
-
SONG -> {
- MusicPlayerRemote.playNext(item as Song)
- MusicPlayerRemote.playNextSong()
+ val playList = ArrayList()
+ playList.add(item as Song)
+ MusicPlayerRemote.openQueue(playList, 0, true)
}
}
}
@@ -235,7 +133,5 @@ class SearchAdapter(
private const val ARTIST = 2
private const val SONG = 3
private const val GENRE = 4
- private const val PLAYLIST = 5
- private const val ALBUM_ARTIST = 6
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt
index 4005c6e6c..60d2d8551 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt
@@ -1,17 +1,3 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.adapter
import android.graphics.PorterDuff
@@ -20,43 +6,43 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.isVisible
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
-import code.name.monkey.retromusic.extensions.getTintedDrawable
-import code.name.monkey.retromusic.glide.RetroGlideExtension
+import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.audiocover.AudioFileCover
-import code.name.monkey.retromusic.interfaces.ICallbacks
-import code.name.monkey.retromusic.util.MusicUtil
+import code.name.monkey.retromusic.interfaces.CabHolder
+import code.name.monkey.retromusic.util.RetroUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.MediaStoreSignature
-import me.zhanghai.android.fastscroll.PopupTextProvider
+import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
import java.io.File
import java.text.DecimalFormat
+import java.util.*
import kotlin.math.log10
import kotlin.math.pow
class SongFileAdapter(
- override val activity: AppCompatActivity,
- private var dataSet: List,
- private val itemLayoutRes: Int,
- private val iCallbacks: ICallbacks?
+ private val activity: AppCompatActivity,
+ private var dataSet: List?,
+ private val itemLayoutRes: Int,
+ private val callbacks: Callbacks?,
+ cabHolder: CabHolder?
) : AbsMultiSelectAdapter(
- activity, R.menu.menu_media_selection
-), PopupTextProvider {
+ activity, cabHolder, R.menu.menu_media_selection
+), FastScrollRecyclerView.SectionedAdapter {
init {
this.setHasStableIds(true)
}
override fun getItemViewType(position: Int): Int {
- return if (dataSet[position].isDirectory) FOLDER else FILE
+ return if (dataSet!![position].isDirectory) FOLDER else FILE
}
override fun getItemId(position: Int): Long {
- return dataSet[position].hashCode().toLong()
+ return dataSet!![position].hashCode().toLong()
}
fun swapDataSet(songFiles: List) {
@@ -69,14 +55,14 @@ class SongFileAdapter(
}
override fun onBindViewHolder(holder: ViewHolder, index: Int) {
- val file = dataSet[index]
+ val file = dataSet!![index]
holder.itemView.isActivated = isChecked(file)
holder.title?.text = getFileTitle(file)
if (holder.text != null) {
if (holder.itemViewType == FILE) {
holder.text?.text = getFileText(file)
} else {
- holder.text?.isVisible = false
+ holder.text?.visibility = View.GONE
}
}
@@ -94,64 +80,62 @@ class SongFileAdapter(
}
private fun loadFileImage(file: File, holder: ViewHolder) {
- val iconColor = ATHUtil.resolveColor(activity, androidx.appcompat.R.attr.colorControlNormal)
+ val iconColor = ATHUtil.resolveColor(activity, R.attr.colorControlNormal)
if (file.isDirectory) {
holder.image?.let {
it.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN)
- it.setImageResource(R.drawable.ic_folder)
+ it.setImageResource(R.drawable.ic_folder_white_24dp)
}
- holder.imageTextContainer?.setCardBackgroundColor(
- ATHUtil.resolveColor(
- activity,
- com.google.android.material.R.attr.colorSurface
- )
- )
+ holder.imageTextContainer?.setCardBackgroundColor(ATHUtil.resolveColor(activity, R.attr.colorSurface))
+
} else {
- val error = activity.getTintedDrawable(R.drawable.ic_audio_file, iconColor)
- Glide.with(activity)
- .load(AudioFileCover(file.path))
- .diskCacheStrategy(DiskCacheStrategy.NONE)
- .error(error)
- .placeholder(error)
- .transition(RetroGlideExtension.getDefaultTransition())
- .signature(MediaStoreSignature("", file.lastModified(), 0))
- .into(holder.image!!)
+ val error = RetroUtil.getTintedVectorDrawable(
+ activity, R.drawable.ic_file_music_white_24dp, iconColor
+ )
+ Glide.with(activity).load(AudioFileCover(file.path))
+ .diskCacheStrategy(DiskCacheStrategy.NONE).error(error).placeholder(error)
+ .animate(android.R.anim.fade_in)
+ .signature(MediaStoreSignature("", file.lastModified(), 0)).into(holder.image)
}
}
override fun getItemCount(): Int {
- return dataSet.size
+ return dataSet!!.size
}
- override fun getIdentifier(position: Int): File {
- return dataSet[position]
+ override fun getIdentifier(position: Int): File? {
+ return dataSet!![position]
}
- override fun getName(model: File): String {
- return getFileTitle(model)
+ override fun getName(`object`: File): String {
+ return getFileTitle(`object`)
}
- override fun onMultipleItemAction(menuItem: MenuItem, selection: List) {
- if (iCallbacks == null) return
- iCallbacks.onMultipleItemAction(menuItem, selection as ArrayList)
+ override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList) {
+ if (callbacks == null) return
+ callbacks.onMultipleItemAction(menuItem, selection)
}
- override fun getPopupText(position: Int): String {
- return if (position >= dataSet.lastIndex) "" else getSectionName(position)
+ override fun getSectionName(position: Int): String {
+ return dataSet!![position].name[0].toString().toUpperCase()
}
- private fun getSectionName(position: Int): String {
- return MusicUtil.getSectionName(dataSet[position].name)
+ interface Callbacks {
+ fun onFileSelected(file: File)
+
+ fun onFileMenuClicked(file: File, view: View)
+
+ fun onMultipleItemAction(item: MenuItem, files: ArrayList)
}
- inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) {
+ inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init {
- if (menu != null && iCallbacks != null) {
+ if (menu != null && callbacks != null) {
menu?.setOnClickListener { v ->
- val position = layoutPosition
+ val position = adapterPosition
if (isPositionInRange(position)) {
- iCallbacks.onFileMenuClicked(dataSet[position], v)
+ callbacks.onFileMenuClicked(dataSet!![position], v)
}
}
}
@@ -161,23 +145,23 @@ class SongFileAdapter(
}
override fun onClick(v: View?) {
- val position = layoutPosition
+ val position = adapterPosition
if (isPositionInRange(position)) {
if (isInQuickSelectMode) {
toggleChecked(position)
} else {
- iCallbacks?.onFileSelected(dataSet[position])
+ callbacks?.onFileSelected(dataSet!![position])
}
}
}
override fun onLongClick(v: View?): Boolean {
- val position = layoutPosition
+ val position = adapterPosition
return isPositionInRange(position) && toggleChecked(position)
}
private fun isPositionInRange(position: Int): Boolean {
- return position >= 0 && position < dataSet.size
+ return position >= 0 && position < dataSet!!.size
}
}
@@ -193,4 +177,4 @@ class SongFileAdapter(
return DecimalFormat("#,##0.##").format(size / 1024.0.pow(digitGroups.toDouble())) + " " + units[digitGroups]
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/StorageAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/StorageAdapter.kt
deleted file mode 100644
index 98c2c632f..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/StorageAdapter.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-package code.name.monkey.retromusic.adapter
-
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView
-import code.name.monkey.retromusic.R
-import java.io.File
-
-class StorageAdapter(
- val storageList: List,
- val storageClickListener: StorageClickListener
-) :
- RecyclerView.Adapter() {
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- return ViewHolder(
- LayoutInflater.from(parent.context).inflate(
- R.layout.item_storage,
- parent,
- false
- )
- )
- }
-
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- holder.bindData(storageList[position])
- }
-
- override fun getItemCount(): Int {
- return storageList.size
- }
-
- inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
- val title: TextView = itemView.findViewById(R.id.title)
-
- fun bindData(storage: Storage) {
- title.text = storage.title
- }
-
- init {
- itemView.setOnClickListener { storageClickListener.onStorageClicked(storageList[bindingAdapterPosition]) }
- }
- }
-}
-
-interface StorageClickListener {
- fun onStorageClicked(storage: Storage)
-}
-
-class Storage {
- lateinit var title: String
- lateinit var file: File
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt
deleted file mode 100644
index 160af7e47..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
-package code.name.monkey.retromusic.adapter.album
-
-import android.content.res.ColorStateList
-import android.view.LayoutInflater
-import android.view.MenuItem
-import android.view.View
-import android.view.ViewGroup
-import androidx.core.view.isVisible
-import androidx.fragment.app.FragmentActivity
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
-import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
-import code.name.monkey.retromusic.glide.RetroGlideExtension
-import code.name.monkey.retromusic.glide.RetroGlideExtension.albumCoverOptions
-import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
-import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
-import code.name.monkey.retromusic.helper.SortOrder
-import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
-import code.name.monkey.retromusic.interfaces.IAlbumClickListener
-import code.name.monkey.retromusic.model.Album
-import code.name.monkey.retromusic.model.Song
-import code.name.monkey.retromusic.util.MusicUtil
-import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
-import com.bumptech.glide.Glide
-import me.zhanghai.android.fastscroll.PopupTextProvider
-
-open class AlbumAdapter(
- override val activity: FragmentActivity,
- var dataSet: List,
- var itemLayoutRes: Int,
- val listener: IAlbumClickListener?
-) : AbsMultiSelectAdapter(
- activity,
- R.menu.menu_media_selection
-), PopupTextProvider {
-
- init {
- this.setHasStableIds(true)
- }
-
- fun swapDataSet(dataSet: List) {
- this.dataSet = dataSet
- notifyDataSetChanged()
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
- return createViewHolder(view, viewType)
- }
-
- protected open fun createViewHolder(view: View, viewType: Int): ViewHolder {
- return ViewHolder(view)
- }
-
- private fun getAlbumTitle(album: Album): String {
- return album.title
- }
-
- protected open fun getAlbumText(album: Album): String? {
- return album.albumArtist.let {
- if (it.isNullOrEmpty()) {
- album.artistName
- } else {
- it
- }
- }
- }
-
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val album = dataSet[position]
- val isChecked = isChecked(album)
- holder.itemView.isActivated = isChecked
- holder.title?.text = getAlbumTitle(album)
- holder.text?.text = getAlbumText(album)
- // Check if imageContainer exists so we can have a smooth transition without
- // CardView clipping, if it doesn't exist in current layout set transition name to image instead.
- if (holder.imageContainer != null) {
- holder.imageContainer?.transitionName = album.id.toString()
- } else {
- holder.image?.transitionName = album.id.toString()
- }
- loadAlbumCover(album, holder)
- }
-
- protected open fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) {
- if (holder.paletteColorContainer != null) {
- holder.title?.setTextColor(color.primaryTextColor)
- holder.text?.setTextColor(color.secondaryTextColor)
- holder.paletteColorContainer?.setBackgroundColor(color.backgroundColor)
- }
- holder.mask?.backgroundTintList = ColorStateList.valueOf(color.primaryTextColor)
- holder.imageContainerCard?.setCardBackgroundColor(color.backgroundColor)
- }
-
- protected open fun loadAlbumCover(album: Album, holder: ViewHolder) {
- if (holder.image == null) {
- return
- }
- val song = album.safeGetFirstSong()
- Glide.with(activity)
- .asBitmapPalette()
- .albumCoverOptions(song)
- //.checkIgnoreMediaStore()
- .load(RetroGlideExtension.getSongModel(song))
- .into(object : RetroMusicColoredTarget(holder.image!!) {
- override fun onColorReady(colors: MediaNotificationProcessor) {
- setColors(colors, holder)
- }
- })
- }
-
- override fun getItemCount(): Int {
- return dataSet.size
- }
-
- override fun getItemId(position: Int): Long {
- return dataSet[position].id
- }
-
- override fun getIdentifier(position: Int): Album? {
- return dataSet[position]
- }
-
- override fun getName(model: Album): String {
- return model.title
- }
-
- override fun onMultipleItemAction(
- menuItem: MenuItem,
- selection: List
- ) {
- SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
- }
-
- private fun getSongList(albums: List): List {
- val songs = ArrayList()
- for (album in albums) {
- songs.addAll(album.songs)
- }
- return songs
- }
-
- override fun getPopupText(position: Int): String {
- return getSectionName(position)
- }
-
- private fun getSectionName(position: Int): String {
- var sectionName: String? = null
- when (PreferenceUtil.albumSortOrder) {
- SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName =
- dataSet[position].title
-
- SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].albumArtist
- SortOrder.AlbumSortOrder.ALBUM_YEAR -> return MusicUtil.getYearString(
- dataSet[position].year
- )
- }
- return MusicUtil.getSectionName(sectionName)
- }
-
- inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
-
- init {
- menu?.isVisible = false
- }
-
- override fun onClick(v: View?) {
- super.onClick(v)
- if (isInQuickSelectMode) {
- toggleChecked(layoutPosition)
- } else {
- image?.let {
- listener?.onAlbumClick(dataSet[layoutPosition].id, imageContainer ?: it)
- }
- }
- }
-
- override fun onLongClick(v: View?): Boolean {
- return toggleChecked(layoutPosition)
- }
- }
-
- companion object {
- val TAG: String = AlbumAdapter::class.java.simpleName
- }
-}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt
deleted file mode 100644
index 5a0a7d3cd..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
-package code.name.monkey.retromusic.adapter.album
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
-import androidx.core.os.BundleCompat
-import androidx.core.os.bundleOf
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentManager
-import androidx.lifecycle.lifecycleScope
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.activities.MainActivity
-import code.name.monkey.retromusic.fragments.AlbumCoverStyle
-import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
-import code.name.monkey.retromusic.fragments.base.goToLyrics
-import code.name.monkey.retromusic.glide.RetroGlideExtension
-import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
-import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions
-import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
-import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter
-import code.name.monkey.retromusic.model.Song
-import code.name.monkey.retromusic.util.MusicUtil
-import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
-import com.bumptech.glide.Glide
-import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-
-class AlbumCoverPagerAdapter(
- fragmentManager: FragmentManager,
- private val dataSet: List
-) : CustomFragmentStatePagerAdapter(fragmentManager) {
-
- private var currentColorReceiver: AlbumCoverFragment.ColorReceiver? = null
- private var currentColorReceiverPosition = -1
-
- override fun getItem(position: Int): Fragment {
- return AlbumCoverFragment.newInstance(dataSet[position])
- }
-
- override fun getCount(): Int {
- return dataSet.size
- }
-
- override fun instantiateItem(container: ViewGroup, position: Int): Any {
- val o = super.instantiateItem(container, position)
- if (currentColorReceiver != null && currentColorReceiverPosition == position) {
- receiveColor(currentColorReceiver!!, currentColorReceiverPosition)
- }
- return o
- }
-
- /**
- * Only the latest passed [AlbumCoverFragment.ColorReceiver] is guaranteed to receive a
- * response
- */
- fun receiveColor(colorReceiver: AlbumCoverFragment.ColorReceiver, position: Int) {
-
- if (getFragment(position) is AlbumCoverFragment) {
- val fragment = getFragment(position) as AlbumCoverFragment
- currentColorReceiver = null
- currentColorReceiverPosition = -1
- fragment.receiveColor(colorReceiver, position)
- } else {
- currentColorReceiver = colorReceiver
- currentColorReceiverPosition = position
- }
- }
-
- class AlbumCoverFragment : Fragment() {
-
- private var isColorReady: Boolean = false
- private lateinit var color: MediaNotificationProcessor
- private lateinit var song: Song
- private var colorReceiver: ColorReceiver? = null
- private var request: Int = 0
- private val mainActivity get() = activity as MainActivity
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- if (arguments != null) {
- song = BundleCompat.getParcelable(requireArguments(), SONG_ARG, Song::class.java)!!
- }
- }
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
- view.setOnClickListener {
- if (mainActivity.getBottomSheetBehavior().state == STATE_EXPANDED) {
- showLyricsDialog()
- }
- }
- return view
- }
-
- private fun showLyricsDialog() {
- lifecycleScope.launch(Dispatchers.IO) {
- val data: String? = MusicUtil.getLyrics(song)
- withContext(Dispatchers.Main) {
- MaterialAlertDialogBuilder(
- requireContext(),
- com.google.android.material.R.style.ThemeOverlay_MaterialComponents_Dialog_Alert
- ).apply {
- setTitle(song.title)
- setMessage(if (data.isNullOrEmpty()) "No lyrics found" else data)
- setNegativeButton(R.string.synced_lyrics) { _, _ ->
- goToLyrics(requireActivity())
- }
- show()
- }
- }
- }
- }
-
- private fun getLayoutWithPlayerTheme(): Int {
- return when (PreferenceUtil.nowPlayingScreen) {
- Card, Fit, Tiny, Classic, Gradient, Full -> R.layout.fragment_album_full_cover
- Peek -> R.layout.fragment_peek_album_cover
- else -> {
- if (PreferenceUtil.isCarouselEffect) {
- R.layout.fragment_album_carousel_cover
- } else {
- when (PreferenceUtil.albumCoverStyle) {
- AlbumCoverStyle.Normal -> R.layout.fragment_album_cover
- AlbumCoverStyle.Flat -> R.layout.fragment_album_flat_cover
- AlbumCoverStyle.Circle -> R.layout.fragment_album_circle_cover
- AlbumCoverStyle.Card -> R.layout.fragment_album_card_cover
- AlbumCoverStyle.Full -> R.layout.fragment_album_full_cover
- AlbumCoverStyle.FullCard -> R.layout.fragment_album_full_card_cover
- }
- }
- }
- }
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- loadAlbumCover(albumCover = view.findViewById(R.id.player_image))
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- colorReceiver = null
- }
-
- private fun loadAlbumCover(albumCover: ImageView) {
- Glide.with(this)
- .asBitmapPalette()
- .songCoverOptions(song)
- //.checkIgnoreMediaStore()
- .load(RetroGlideExtension.getSongModel(song))
- .dontAnimate()
- .into(object : RetroMusicColoredTarget(albumCover) {
- override fun onColorReady(colors: MediaNotificationProcessor) {
- setColor(colors)
- }
- })
- }
-
- private fun setColor(color: MediaNotificationProcessor) {
- this.color = color
- isColorReady = true
- if (colorReceiver != null) {
- colorReceiver!!.onColorReady(color, request)
- colorReceiver = null
- }
- }
-
- internal fun receiveColor(colorReceiver: ColorReceiver, request: Int) {
- if (isColorReady) {
- colorReceiver.onColorReady(color, request)
- } else {
- this.colorReceiver = colorReceiver
- this.request = request
- }
- }
-
- interface ColorReceiver {
- fun onColorReady(color: MediaNotificationProcessor, request: Int)
- }
-
- companion object {
-
- private const val SONG_ARG = "song"
-
- fun newInstance(song: Song): AlbumCoverFragment {
- val frag = AlbumCoverFragment()
- frag.arguments = bundleOf(SONG_ARG to song)
- return frag
- }
- }
- }
-
- companion object {
- val TAG: String = AlbumCoverPagerAdapter::class.java.simpleName
- }
-}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt
deleted file mode 100644
index 7a9f7fa6e..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
-package code.name.monkey.retromusic.adapter.album
-
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.FragmentActivity
-import code.name.monkey.retromusic.glide.RetroGlideExtension
-import code.name.monkey.retromusic.glide.RetroGlideExtension.albumCoverOptions
-import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
-import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
-import code.name.monkey.retromusic.helper.HorizontalAdapterHelper
-import code.name.monkey.retromusic.interfaces.IAlbumClickListener
-import code.name.monkey.retromusic.model.Album
-import code.name.monkey.retromusic.util.MusicUtil
-import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
-import com.bumptech.glide.Glide
-
-class HorizontalAlbumAdapter(
- activity: FragmentActivity,
- dataSet: List,
- albumClickListener: IAlbumClickListener
-) : AlbumAdapter(
- activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, albumClickListener
-) {
-
- override fun createViewHolder(view: View, viewType: Int): ViewHolder {
- val params = view.layoutParams as ViewGroup.MarginLayoutParams
- HorizontalAdapterHelper.applyMarginToLayoutParams(activity, params, viewType)
- return ViewHolder(view)
- }
-
- override fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) {
- // holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
- // holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
- }
-
- override fun loadAlbumCover(album: Album, holder: ViewHolder) {
- if (holder.image == null) return
- Glide.with(activity)
- .asBitmapPalette()
- .albumCoverOptions(album.safeGetFirstSong())
- .load(RetroGlideExtension.getSongModel(album.safeGetFirstSong()))
- .into(object : RetroMusicColoredTarget(holder.image!!) {
- override fun onColorReady(colors: MediaNotificationProcessor) {
- setColors(colors, holder)
- }
- })
- }
-
- override fun getAlbumText(album: Album): String {
- return MusicUtil.getYearString(album.year)
- }
-
- override fun getItemViewType(position: Int): Int {
- return HorizontalAdapterHelper.getItemViewType(position, itemCount)
- }
-
- override fun getItemCount(): Int {
- return dataSet.size
- }
-
- companion object {
- val TAG: String = AlbumAdapter::class.java.simpleName
- }
-}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt
index e1ea2ca4c..fd4dcfa98 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt
@@ -1,186 +1,152 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.adapter.artist
-import android.annotation.SuppressLint
+import android.app.ActivityOptions
import android.content.res.ColorStateList
-import android.content.res.Resources
-import android.view.LayoutInflater
-import android.view.MenuItem
-import android.view.View
-import android.view.ViewGroup
-import androidx.core.view.isVisible
-import androidx.fragment.app.FragmentActivity
+import android.graphics.drawable.Drawable
+import android.view.*
+import androidx.appcompat.app.AppCompatActivity
+import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
-import code.name.monkey.retromusic.extensions.hide
-import code.name.monkey.retromusic.glide.RetroGlideExtension
-import code.name.monkey.retromusic.glide.RetroGlideExtension.artistImageOptions
-import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
-import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
+import code.name.monkey.retromusic.adapter.base.*
+import code.name.monkey.retromusic.glide.*
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
-import code.name.monkey.retromusic.interfaces.IAlbumArtistClickListener
-import code.name.monkey.retromusic.interfaces.IArtistClickListener
-import code.name.monkey.retromusic.model.Artist
-import code.name.monkey.retromusic.model.Song
-import code.name.monkey.retromusic.util.MusicUtil
-import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
+import code.name.monkey.retromusic.interfaces.CabHolder
+import code.name.monkey.retromusic.model.*
+import code.name.monkey.retromusic.util.*
import com.bumptech.glide.Glide
-import me.zhanghai.android.fastscroll.PopupTextProvider
+import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
+import java.util.*
class ArtistAdapter(
- override val activity: FragmentActivity,
- var dataSet: List,
- var itemLayoutRes: Int,
- val IArtistClickListener: IArtistClickListener,
- val IAlbumArtistClickListener: IAlbumArtistClickListener? = null
-) : AbsMultiSelectAdapter(activity, R.menu.menu_media_selection),
- PopupTextProvider {
+ val activity: AppCompatActivity,
+ var dataSet: ArrayList,
+ var itemLayoutRes: Int,
+ var usePalette: Boolean,
+ cabHolder: CabHolder?
+) : AbsMultiSelectAdapter(
+ activity, cabHolder, R.menu.menu_media_selection
+), FastScrollRecyclerView.SectionedAdapter {
- var albumArtistsOnly = false
+ fun swapDataSet(dataSet: ArrayList) {
+ this.dataSet = dataSet
+ notifyDataSetChanged()
+ }
- init {
- this.setHasStableIds(true)
- }
+ fun usePalette(usePalette: Boolean) {
+ this.usePalette = usePalette
+ notifyDataSetChanged()
+ }
- @SuppressLint("NotifyDataSetChanged")
- fun swapDataSet(dataSet: List) {
- this.dataSet = dataSet
- notifyDataSetChanged()
- albumArtistsOnly = PreferenceUtil.albumArtistsOnly
- }
+ override fun getItemId(position: Int): Long {
+ return dataSet[position].id.toLong()
+ }
- override fun getItemId(position: Int): Long {
- return dataSet[position].id
- }
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
+ return createViewHolder(view)
+ }
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val view =
- try {
- LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
- } catch (e: Resources.NotFoundException) {
- LayoutInflater.from(activity).inflate(R.layout.item_grid_circle, parent, false)
- }
- return createViewHolder(view)
- }
+ private fun createViewHolder(view: View): ViewHolder {
+ return ViewHolder(view)
+ }
- private fun createViewHolder(view: View): ViewHolder {
- return ViewHolder(view)
- }
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val artist = dataSet[position]
+ val isChecked = isChecked(artist)
+ holder.itemView.isActivated = isChecked
+ holder.title?.text = artist.name
+ holder.text?.visibility = View.GONE
+ loadArtistImage(artist, holder)
+ }
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val artist = dataSet[position]
- val isChecked = isChecked(artist)
- holder.itemView.isActivated = isChecked
- holder.title?.text = artist.name
- holder.text?.hide()
- val transitionName =
- if (albumArtistsOnly) artist.name else artist.id.toString()
- if (holder.imageContainer != null) {
- holder.imageContainer?.transitionName = transitionName
- } else {
- holder.image?.transitionName = transitionName
- }
- loadArtistImage(artist, holder)
- }
+ fun setColors(color: Int, holder: ViewHolder) {
+ if (holder.paletteColorContainer != null) {
+ holder.paletteColorContainer?.setBackgroundColor(color)
+ holder.title?.setTextColor(
+ MaterialValueHelper.getPrimaryTextColor(
+ activity, ColorUtil.isColorLight(
+ color
+ )
+ )
+ )
+ }
- private fun setColors(processor: MediaNotificationProcessor, holder: ViewHolder) {
- holder.mask?.backgroundTintList = ColorStateList.valueOf(processor.primaryTextColor)
- if (holder.paletteColorContainer != null) {
- holder.paletteColorContainer?.setBackgroundColor(processor.backgroundColor)
- holder.title?.setTextColor(processor.primaryTextColor)
- }
- holder.imageContainerCard?.setCardBackgroundColor(processor.backgroundColor)
- }
+ holder.mask?.backgroundTintList = ColorStateList.valueOf(color)
+ }
- private fun loadArtistImage(artist: Artist, holder: ViewHolder) {
- if (holder.image == null) {
- return
- }
- Glide.with(activity)
- .asBitmapPalette()
- .artistImageOptions(artist)
- .load(RetroGlideExtension.getArtistModel(artist))
- .transition(RetroGlideExtension.getDefaultTransition())
- .into(object : RetroMusicColoredTarget(holder.image!!) {
- override fun onColorReady(colors: MediaNotificationProcessor) {
- setColors(colors, holder)
- }
- })
- }
+ private fun loadArtistImage(artist: Artist, holder: ViewHolder) {
+ if (holder.image == null) {
+ return
+ }
+ ArtistGlideRequest.Builder.from(Glide.with(activity), artist).generatePalette(activity)
+ .build().into(object : RetroMusicColoredTarget(holder.image!!) {
+ override fun onLoadCleared(placeholder: Drawable?) {
+ super.onLoadCleared(placeholder)
+ setColors(defaultFooterColor, holder)
+ }
- override fun getItemCount(): Int {
- return dataSet.size
- }
+ override fun onColorReady(color: Int) {
+ setColors(color, holder)
+ }
+ })
+ }
- override fun getIdentifier(position: Int): Artist {
- return dataSet[position]
- }
+ override fun getItemCount(): Int {
+ return dataSet.size
+ }
- override fun getName(model: Artist): String {
- return model.name
- }
+ override fun getIdentifier(position: Int): Artist? {
+ return dataSet[position]
+ }
- override fun onMultipleItemAction(
- menuItem: MenuItem,
- selection: List
- ) {
- SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
- }
+ override fun getName(artist: Artist): String {
+ return artist.name
+ }
- private fun getSongList(artists: List): List {
- val songs = ArrayList()
- for (artist in artists) {
- songs.addAll(artist.songs) // maybe async in future?
- }
- return songs
- }
+ override fun onMultipleItemAction(
+ menuItem: MenuItem, selection: ArrayList
+ ) {
+ SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
+ }
- override fun getPopupText(position: Int): String {
- return getSectionName(position)
- }
+ private fun getSongList(artists: List): ArrayList {
+ val songs = ArrayList()
+ for (artist in artists) {
+ songs.addAll(artist.songs) // maybe async in future?
+ }
+ return songs
+ }
- private fun getSectionName(position: Int): String {
- return MusicUtil.getSectionName(dataSet[position].name)
- }
+ override fun getSectionName(position: Int): String {
+ return MusicUtil.getSectionName(dataSet[position].name)
+ }
- inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) {
+ inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
- init {
- menu?.isVisible = false
- }
+ init {
+ setImageTransitionName(activity.getString(R.string.transition_artist_image))
+ menu?.visibility = View.GONE
+ }
- override fun onClick(v: View?) {
- super.onClick(v)
- if (isInQuickSelectMode) {
- toggleChecked(layoutPosition)
- } else {
- val artist = dataSet[layoutPosition]
- image?.let {
- if (albumArtistsOnly && IAlbumArtistClickListener != null) {
- IAlbumArtistClickListener.onAlbumArtist(artist.name, imageContainer ?: it)
- } else {
- IArtistClickListener.onArtist(artist.id, imageContainer ?: it)
- }
- }
- }
- }
+ override fun onClick(v: View?) {
+ super.onClick(v)
+ if (isInQuickSelectMode) {
+ toggleChecked(adapterPosition)
+ } else {
+ val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
+ activity, image, activity.getString(
+ R.string.transition_artist_image
+ )
+ )
+ NavigationUtil.goToArtistOptions(
+ activity, dataSet[adapterPosition].id, activityOptions
+ )
+ }
+ }
- override fun onLongClick(v: View?): Boolean {
- return toggleChecked(layoutPosition)
- }
- }
+ override fun onLongClick(v: View?): Boolean {
+ toggleChecked(adapterPosition)
+ return super.onLongClick(v)
+ }
+ }
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/backup/BackupAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/backup/BackupAdapter.kt
deleted file mode 100644
index adfcecf1b..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/backup/BackupAdapter.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package code.name.monkey.retromusic.adapter.backup
-
-import android.annotation.SuppressLint
-import android.view.LayoutInflater
-import android.view.MenuItem
-import android.view.ViewGroup
-import androidx.appcompat.widget.PopupMenu
-import androidx.fragment.app.FragmentActivity
-import androidx.recyclerview.widget.RecyclerView
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.databinding.ItemListBackupBinding
-import java.io.File
-
-
-class BackupAdapter(
- val activity: FragmentActivity,
- var dataSet: MutableList,
- val backupClickedListener: BackupClickedListener
-) : RecyclerView.Adapter() {
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- return ViewHolder(
- ItemListBackupBinding.inflate(LayoutInflater.from(activity), parent, false)
- )
- }
-
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- holder.binding.title.text = dataSet[position].nameWithoutExtension
- }
-
- override fun getItemCount(): Int = dataSet.size
-
- @SuppressLint("NotifyDataSetChanged")
- fun swapDataset(dataSet: List) {
- this.dataSet = ArrayList(dataSet)
- notifyDataSetChanged()
- }
-
- inner class ViewHolder(val binding: ItemListBackupBinding) :
- RecyclerView.ViewHolder(binding.root) {
-
- init {
- binding.menu.setOnClickListener { view ->
- val popupMenu = PopupMenu(activity, view)
- popupMenu.inflate(R.menu.menu_backup)
- popupMenu.setOnMenuItemClickListener { menuItem ->
- return@setOnMenuItemClickListener backupClickedListener.onBackupMenuClicked(
- dataSet[bindingAdapterPosition],
- menuItem
- )
- }
- popupMenu.show()
- }
- itemView.setOnClickListener {
- backupClickedListener.onBackupClicked(dataSet[bindingAdapterPosition])
- }
- }
- }
-
- interface BackupClickedListener {
- fun onBackupClicked(file: File)
-
- fun onBackupMenuClicked(file: File, menuItem: MenuItem): Boolean
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.java b/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.java
new file mode 100644
index 000000000..36bbe6bdf
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.java
@@ -0,0 +1,123 @@
+package code.name.monkey.retromusic.adapter.base;
+
+import android.content.Context;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import androidx.annotation.MenuRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
+import 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(@NonNull 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/adapter/base/AbsMultiSelectAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.kt
deleted file mode 100644
index bb7b8491c..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-package code.name.monkey.retromusic.adapter.base
-
-import android.graphics.Color
-import android.view.ActionMode
-import android.view.Menu
-import android.view.MenuItem
-import androidx.activity.OnBackPressedCallback
-import androidx.annotation.MenuRes
-import androidx.fragment.app.FragmentActivity
-import androidx.recyclerview.widget.RecyclerView
-import code.name.monkey.appthemehelper.util.VersionUtils
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.databinding.NumberRollViewBinding
-import code.name.monkey.retromusic.views.NumberRollView
-
-abstract class AbsMultiSelectAdapter(
- open val activity: FragmentActivity, @MenuRes menuRes: Int,
-) : RecyclerView.Adapter(), ActionMode.Callback {
- var actionMode: ActionMode? = null
- private val checked: MutableList
- private var menuRes: Int
-
- override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
- val inflater = mode?.menuInflater
- inflater?.inflate(menuRes, menu)
- return true
- }
-
- override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
- return false
- }
-
- override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
- if (item?.itemId == R.id.action_multi_select_adapter_check_all) {
- checkAll()
- } else {
- onMultipleItemAction(item!!, ArrayList(checked))
- actionMode?.finish()
- clearChecked()
- }
- return true
- }
-
- override fun onDestroyActionMode(mode: ActionMode?) {
- clearChecked()
- activity.window.statusBarColor = when {
- VersionUtils.hasMarshmallow() -> Color.TRANSPARENT
- else -> Color.BLACK
- }
- actionMode = null
- onBackPressedCallback.remove()
- }
-
- private fun checkAll() {
- if (actionMode != null) {
- checked.clear()
- for (i in 0 until itemCount) {
- val identifier = getIdentifier(i)
- if (identifier != null) {
- checked.add(identifier)
- }
- }
- notifyDataSetChanged()
- updateCab()
- }
- }
-
- protected abstract fun getIdentifier(position: Int): I?
-
- protected abstract fun getName(model: I): String?
-
- protected fun isChecked(identifier: I): Boolean {
- return checked.contains(identifier)
- }
-
- protected val isInQuickSelectMode: Boolean
- get() = actionMode != null
-
- protected abstract fun onMultipleItemAction(menuItem: MenuItem, selection: List)
- protected fun setMultiSelectMenuRes(@MenuRes menuRes: Int) {
- this.menuRes = menuRes
- }
-
- protected fun toggleChecked(position: Int): Boolean {
- val identifier = getIdentifier(position) ?: return false
- if (!checked.remove(identifier)) {
- checked.add(identifier)
- }
- notifyItemChanged(position)
- updateCab()
- return true
- }
-
- private fun clearChecked() {
- checked.clear()
- notifyDataSetChanged()
- }
-
- private fun updateCab() {
- if (actionMode == null) {
- actionMode = activity.startActionMode(this)?.apply {
- customView = NumberRollViewBinding.inflate(activity.layoutInflater).root
- }
- activity.onBackPressedDispatcher.addCallback(onBackPressedCallback)
- }
- val size = checked.size
- when {
- size <= 0 -> {
- actionMode?.finish()
- }
- else -> {
- actionMode?.customView?.findViewById(R.id.selection_mode_number)
- ?.setNumber(size, true)
- }
- }
- }
-
- init {
- checked = ArrayList()
- this.menuRes = menuRes
- }
-
- private val onBackPressedCallback = object : OnBackPressedCallback(true) {
- override fun handleOnBackPressed() {
- if (actionMode != null) {
- actionMode?.finish()
- remove()
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java b/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java
index d68186c0f..f1652ea54 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java
@@ -14,115 +14,113 @@
package code.name.monkey.retromusic.adapter.base;
-import android.graphics.Color;
import android.view.View;
-import android.widget.FrameLayout;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.widget.AppCompatImageView;
+import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.card.MaterialCardView;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableSwipeableItemViewHolder;
+import code.name.monkey.appthemehelper.util.ATHUtil;
import code.name.monkey.retromusic.R;
-public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHolder
- implements View.OnLongClickListener, View.OnClickListener {
-
+public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHolder implements View.OnLongClickListener, View.OnClickListener {
@Nullable
- public View dragView;
-
- @Nullable
- public View dummyContainer;
-
- @Nullable
- public ImageView image;
-
- @Nullable
- public MaterialCardView imageContainerCard;
-
- @Nullable
- public FrameLayout imageContainer;
-
- @Nullable
- public TextView imageText;
-
- @Nullable
- public MaterialCardView imageTextContainer;
-
- @Nullable
- public View mask;
-
- @Nullable
- public AppCompatImageView menu;
-
- @Nullable
- public View paletteColorContainer;
+ public TextView title;
@Nullable
public TextView text;
- @Nullable
- public TextView text2;
-
@Nullable
public TextView time;
@Nullable
- public TextView title;
+ public TextView imageText;
+
+ @Nullable
+ public ViewGroup imageContainer;
+
+ @Nullable
+ public MaterialCardView imageContainerCard;
+
+ @Nullable
+ public View menu;
+
+ @Nullable
+ public View dragView;
+
+ @Nullable
+ public View paletteColorContainer;
+
+ @Nullable
+ public RecyclerView recyclerView;
+
+ @Nullable
+ public ImageButton playSongs;
+
+ @Nullable
+ public View mask;
+
+ @Nullable
+ public MaterialCardView imageTextContainer;
+
+ @Nullable
+ public ImageView image;
+ @Nullable
+ public View dummyContainer;
public MediaEntryViewHolder(@NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
text = itemView.findViewById(R.id.text);
- text2 = itemView.findViewById(R.id.text2);
image = itemView.findViewById(R.id.image);
time = itemView.findViewById(R.id.time);
imageText = itemView.findViewById(R.id.imageText);
+ imageContainer = itemView.findViewById(R.id.imageContainer);
imageTextContainer = itemView.findViewById(R.id.imageTextContainer);
imageContainerCard = itemView.findViewById(R.id.imageContainerCard);
- imageContainer = itemView.findViewById(R.id.imageContainer);
menu = itemView.findViewById(R.id.menu);
dragView = itemView.findViewById(R.id.drag_view);
paletteColorContainer = itemView.findViewById(R.id.paletteColorContainer);
+ recyclerView = itemView.findViewById(R.id.recycler_view);
mask = itemView.findViewById(R.id.mask);
+ playSongs = itemView.findViewById(R.id.playSongs);
dummyContainer = itemView.findViewById(R.id.dummy_view);
if (imageContainerCard != null) {
- imageContainerCard.setCardBackgroundColor(Color.TRANSPARENT);
+ imageContainerCard.setCardBackgroundColor(ATHUtil.INSTANCE.resolveColor(itemView.getContext(), R.attr.colorSurface));
}
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
- @Nullable
@Override
public View getSwipeableContainerView() {
return null;
}
- @Override
- public void onClick(View v) {
- }
-
@Override
public boolean onLongClick(View v) {
return false;
}
- public void setImageTransitionName(@NonNull String transitionName) {
- itemView.setTransitionName(transitionName);
- /* if (imageContainerCard != null) {
- imageContainerCard.setTransitionName(transitionName);
+ @Override
+ public void onClick(View v) {
+
}
- if (image != null) {
- image.setTransitionName(transitionName);
- }*/
+
+ public void setImageTransitionName(@NonNull String transitionName) {
+ if (image != null) {
+ image.setTransitionName(transitionName);
+ }
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/LegacyPlaylistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/LegacyPlaylistAdapter.kt
deleted file mode 100644
index 19d681ecf..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/LegacyPlaylistAdapter.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
-package code.name.monkey.retromusic.adapter.playlist
-
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.FragmentActivity
-import androidx.recyclerview.widget.RecyclerView
-import code.name.monkey.retromusic.model.Playlist
-import code.name.monkey.retromusic.util.MusicUtil
-
-class LegacyPlaylistAdapter(
- private val activity: FragmentActivity,
- private var list: List,
- private val layoutRes: Int,
- private val playlistClickListener: PlaylistClickListener
-) :
- RecyclerView.Adapter() {
-
- fun swapData(list: List) {
- this.list = list
- notifyDataSetChanged()
- }
-
- class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView)
-
- override fun onCreateViewHolder(
- parent: ViewGroup,
- viewType: Int
- ): ViewHolder {
- return ViewHolder(
- LayoutInflater.from(parent.context).inflate(layoutRes, parent, false)
- )
- }
-
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val playlist: Playlist = list[position]
- holder.title?.text = playlist.name
- holder.text?.text = MusicUtil.getPlaylistInfoString(activity, playlist.getSongs())
- holder.itemView.setOnClickListener {
- playlistClickListener.onPlaylistClick(playlist)
- }
- }
-
- override fun getItemCount(): Int {
- return list.size
- }
-
- interface PlaylistClickListener {
- fun onPlaylistClick(playlist: Playlist)
- }
-}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt
index 6e5b0c001..f448f3d68 100755
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt
@@ -1,70 +1,57 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.adapter.playlist
-import android.graphics.Color
import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
-import androidx.core.view.isGone
-import androidx.core.view.setPadding
-import androidx.fragment.app.FragmentActivity
+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.adapter.base.AbsMultiSelectAdapter
-import code.name.monkey.retromusic.db.PlaylistEntity
-import code.name.monkey.retromusic.db.PlaylistWithSongs
-import code.name.monkey.retromusic.db.toSongs
-import code.name.monkey.retromusic.extensions.dipToPix
-import code.name.monkey.retromusic.glide.RetroGlideExtension.playlistOptions
-import code.name.monkey.retromusic.glide.playlistPreview.PlaylistPreview
-import code.name.monkey.retromusic.helper.SortOrder.PlaylistSortOrder
+import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
+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.IPlaylistClickListener
+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.util.MusicUtil
-import code.name.monkey.retromusic.util.PreferenceUtil
-import com.bumptech.glide.Glide
-import me.zhanghai.android.fastscroll.PopupTextProvider
+import code.name.monkey.retromusic.util.NavigationUtil
+import java.util.*
class PlaylistAdapter(
- override val activity: FragmentActivity,
- var dataSet: List,
- private var itemLayoutRes: Int,
- private val listener: IPlaylistClickListener
-) : AbsMultiSelectAdapter(
- activity,
- R.menu.menu_playlists_selection
-), PopupTextProvider {
+ private val activity: AppCompatActivity,
+ var dataSet: ArrayList,
+ private var itemLayoutRes: Int,
+ cabHolder: CabHolder?
+) : AbsMultiSelectAdapter(
+ activity,
+ cabHolder,
+ R.menu.menu_playlists_selection
+) {
+
+ var songs = ArrayList()
init {
setHasStableIds(true)
}
- fun swapDataSet(dataSet: List) {
+ fun swapDataSet(dataSet: ArrayList) {
this.dataSet = dataSet
notifyDataSetChanged()
}
override fun getItemId(position: Int): Long {
- return dataSet[position].playlistEntity.playListId
+ return dataSet[position].id.toLong()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@@ -72,115 +59,158 @@ class PlaylistAdapter(
return createViewHolder(view)
}
- private fun createViewHolder(view: View): ViewHolder {
+ protected fun createViewHolder(view: View): ViewHolder {
return ViewHolder(view)
}
- private fun getPlaylistTitle(playlist: PlaylistEntity): String {
- return playlist.playlistName.ifEmpty { "-" }
+ protected fun getPlaylistTitle(playlist: Playlist): String {
+ return playlist.name
}
- private fun getPlaylistText(playlist: PlaylistWithSongs): String {
- return MusicUtil.getPlaylistInfoString(activity, playlist.songs.toSongs())
- }
-
- override fun getPopupText(position: Int): String {
- val sectionName: String = when (PreferenceUtil.playlistSortOrder) {
- PlaylistSortOrder.PLAYLIST_A_Z, PlaylistSortOrder.PLAYLIST_Z_A -> dataSet[position].playlistEntity.playlistName
- PlaylistSortOrder.PLAYLIST_SONG_COUNT, PlaylistSortOrder.PLAYLIST_SONG_COUNT_DESC -> dataSet[position].songs.size.toString()
- else -> {
- return ""
- }
- }
- return MusicUtil.getSectionName(sectionName)
+ protected fun getPlaylistText(playlist: Playlist): String {
+ return MusicUtil.getPlaylistInfoString(activity, getSongs(playlist))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val playlist = dataSet[position]
holder.itemView.isActivated = isChecked(playlist)
- holder.title?.text = getPlaylistTitle(playlist.playlistEntity)
+ holder.title?.text = getPlaylistTitle(playlist)
holder.text?.text = getPlaylistText(playlist)
- holder.menu?.isGone = isChecked(playlist)
- if (itemLayoutRes == R.layout.item_list) {
- holder.image?.setPadding(activity.dipToPix(8F).toInt())
- holder.image?.setImageDrawable(getIconRes())
- } else {
- Glide.with(activity)
- .load(PlaylistPreview(playlist))
- .playlistOptions()
- .into(holder.image!!)
- }
+ holder.image?.setImageDrawable(getIconRes(playlist))
}
- private fun getIconRes(): Drawable = TintHelper.createTintedDrawable(
- activity,
- R.drawable.ic_playlist_play,
- ATHUtil.resolveColor(activity, android.R.attr.colorControlNormal)
- )
+ private fun getIconRes(playlist: Playlist): Drawable {
+ return if (MusicUtil.isFavoritePlaylist(activity, playlist))
+ TintHelper.createTintedDrawable(activity, R.drawable.ic_favorite_white_24dp, ThemeStore.accentColor(activity))!!
+ else TintHelper.createTintedDrawable(activity, R.drawable.ic_playlist_play_white_24dp, ATHUtil.resolveColor(activity, R.attr.colorControlNormal))!!
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return if (dataSet[position] is AbsSmartPlaylist) SMART_PLAYLIST else DEFAULT_PLAYLIST
+ }
override fun getItemCount(): Int {
return dataSet.size
}
- override fun getIdentifier(position: Int): PlaylistWithSongs {
+ override fun getIdentifier(position: Int): Playlist? {
return dataSet[position]
}
- override fun getName(model: PlaylistWithSongs): String {
- return model.playlistEntity.playlistName
+ override fun getName(playlist: Playlist): String {
+ return playlist.name
}
- override fun onMultipleItemAction(menuItem: MenuItem, selection: List) {
+ override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList) {
when (menuItem.itemId) {
+ R.id.action_delete_playlist -> {
+ var i = 0
+ while (i < selection.size) {
+ val playlist = selection[i]
+ if (playlist is AbsSmartPlaylist) {
+ ClearSmartPlaylistDialog.create(playlist).show(
+ activity.supportFragmentManager, "CLEAR_PLAYLIST_" + playlist.name
+ )
+ selection.remove(playlist)
+ i--
+ }
+ i++
+ }
+ if (selection.size > 0) {
+ DeletePlaylistDialog.create(selection)
+ .show(activity.supportFragmentManager, "DELETE_PLAYLIST")
+ }
+ }
else -> SongsMenuHelper.handleMenuClick(
- activity,
- getSongList(selection),
- menuItem.itemId
+ activity,
+ getSongList(selection),
+ menuItem.itemId
)
}
}
- private fun getSongList(playlists: List): List {
- val songs = mutableListOf()
- playlists.forEach {
- songs.addAll(it.songs.toSongs())
+ private fun getSongList(playlists: List): ArrayList {
+ val songs = ArrayList()
+ for (playlist in playlists) {
+ if (playlist is AbsCustomPlaylist) {
+ songs.addAll(playlist.getSongs(activity))
+ } else {
+ songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
+ }
}
return songs
}
- inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) {
+ private fun getSongs(playlist: Playlist): ArrayList {
+ val songs = ArrayList()
+ if (playlist is AbsSmartPlaylist) {
+ songs.addAll(playlist.getSongs(activity))
+ } else {
+ songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
+ }
+ return songs
+ }
+
+ inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init {
+
+ image?.apply {
+ val iconPadding = activity.resources.getDimensionPixelSize(R.dimen.list_item_image_icon_padding)
+ setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
+ //setColorFilter(ATHUtil.resolveColor(activity, R.attr.iconColor), PorterDuff.Mode.SRC_IN)
+ }
+
menu?.setOnClickListener { view ->
+ val playlist = dataSet[adapterPosition]
val popupMenu = PopupMenu(activity, view)
- popupMenu.inflate(R.menu.menu_item_playlist)
+ popupMenu.inflate(
+ if (itemViewType == SMART_PLAYLIST) R.menu.menu_item_smart_playlist
+ else R.menu.menu_item_playlist
+ )
+ if (playlist is LastAddedPlaylist) {
+ popupMenu.menu.findItem(R.id.action_clear_playlist).isVisible = false
+ }
popupMenu.setOnMenuItemClickListener { item ->
- PlaylistMenuHelper.handleMenuClick(activity, dataSet[layoutPosition], item)
+ if (item.itemId == R.id.action_clear_playlist) {
+ if (playlist is AbsSmartPlaylist) {
+ ClearSmartPlaylistDialog.create(playlist).show(
+ activity.supportFragmentManager,
+ "CLEAR_SMART_PLAYLIST_" + playlist.name
+ )
+ return@setOnMenuItemClickListener true
+ }
+ }
+ PlaylistMenuHelper.handleMenuClick(
+ activity, dataSet[adapterPosition], item
+ )
}
popupMenu.show()
}
imageTextContainer?.apply {
cardElevation = 0f
- setCardBackgroundColor(Color.TRANSPARENT)
+ setCardBackgroundColor(ATHUtil.resolveColor(activity, R.attr.colorSurface))
}
}
override fun onClick(v: View?) {
if (isInQuickSelectMode) {
- toggleChecked(layoutPosition)
+ toggleChecked(adapterPosition)
} else {
- itemView.transitionName = "playlist"
- listener.onPlaylistClick(dataSet[layoutPosition], itemView)
+ val playlist = dataSet[adapterPosition]
+ NavigationUtil.goToPlaylistNew(activity, playlist)
}
}
override fun onLongClick(v: View?): Boolean {
- toggleChecked(layoutPosition)
+ toggleChecked(adapterPosition)
return true
}
}
companion object {
val TAG: String = PlaylistAdapter::class.java.simpleName
+ private const val SMART_PLAYLIST = 0
+ private const val DEFAULT_PLAYLIST = 1
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt
index 2d5fd724f..9cf2aaf12 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt
@@ -1,91 +1,95 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.adapter.song
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
+import android.view.*
import androidx.annotation.LayoutRes
-import androidx.fragment.app.FragmentActivity
+import androidx.appcompat.app.AppCompatActivity
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.*
-abstract class AbsOffsetSongAdapter(
- activity: FragmentActivity,
- dataSet: MutableList,
- @LayoutRes itemLayoutRes: Int
-) : SongAdapter(activity, dataSet, itemLayoutRes) {
+abstract class AbsOffsetSongAdapter : SongAdapter {
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder {
- if (viewType == OFFSET_ITEM) {
- val view = LayoutInflater.from(activity)
- .inflate(R.layout.item_list_quick_actions, parent, false)
- return createViewHolder(view)
- }
- return super.onCreateViewHolder(parent, viewType)
- }
+ constructor(
+ activity: AppCompatActivity,
+ dataSet: ArrayList, @LayoutRes itemLayoutRes: Int,
+ usePalette: Boolean,
+ cabHolder: CabHolder?
+ ) : super(activity, dataSet, itemLayoutRes, usePalette, cabHolder)
- override fun createViewHolder(view: View): SongAdapter.ViewHolder {
- return ViewHolder(view)
- }
+ constructor(
+ activity: AppCompatActivity,
+ dataSet: ArrayList, @LayoutRes itemLayoutRes: Int,
+ usePalette: Boolean,
+ cabHolder: CabHolder?,
+ showSectionName: Boolean
+ ) : super(activity, dataSet, itemLayoutRes, usePalette, cabHolder, showSectionName) {
+ }
- override fun getItemId(position: Int): Long {
- var positionFinal = position
- positionFinal--
- return if (positionFinal < 0) -2 else super.getItemId(positionFinal)
- }
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder {
+ if (viewType == OFFSET_ITEM) {
+ val view = LayoutInflater.from(activity)
+ .inflate(R.layout.item_list_quick_actions, parent, false)
+ return createViewHolder(view)
+ }
+ return super.onCreateViewHolder(parent, viewType)
+ }
- override fun getIdentifier(position: Int): Song? {
- var positionFinal = position
- positionFinal--
- return if (positionFinal < 0) null else super.getIdentifier(positionFinal)
- }
+ override fun createViewHolder(view: View): SongAdapter.ViewHolder {
+ return ViewHolder(view)
+ }
- override fun getItemCount(): Int {
- val superItemCount = super.getItemCount()
- return if (superItemCount == 0) 0 else superItemCount + 1
- }
+ override fun getItemId(position: Int): Long {
+ var positionFinal = position
+ positionFinal--
+ return if (positionFinal < 0) -2 else super.getItemId(positionFinal)
+ }
- override fun getItemViewType(position: Int): Int {
- return if (position == 0) OFFSET_ITEM else SONG
- }
+ override fun getIdentifier(position: Int): Song? {
+ var positionFinal = position
+ positionFinal--
+ return if (positionFinal < 0) null else super.getIdentifier(positionFinal)
+ }
- open inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) {
+ override fun getItemCount(): Int {
+ val superItemCount = super.getItemCount()
+ return if (superItemCount == 0) 0 else superItemCount + 1
+ }
- override // could also return null, just to be safe return empty song
- val song: Song
- get() = if (itemViewType == OFFSET_ITEM) Song.emptySong else dataSet[layoutPosition - 1]
+ override fun getItemViewType(position: Int): Int {
+ return if (position == 0) OFFSET_ITEM else SONG
+ }
- override fun onClick(v: View?) {
- if (isInQuickSelectMode && itemViewType != OFFSET_ITEM) {
- toggleChecked(layoutPosition)
- } else {
- MusicPlayerRemote.openQueue(dataSet, layoutPosition - 1, true)
- }
- }
+ override fun getSectionName(position: Int): String {
+ var positionF = position
+ positionF--
+ return if (positionF < 0) "" else super.getSectionName(positionF)
+ }
- override fun onLongClick(v: View?): Boolean {
- if (itemViewType == OFFSET_ITEM) return false
- toggleChecked(layoutPosition)
- return true
- }
- }
+ open inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) {
- companion object {
- const val OFFSET_ITEM = 0
- const val SONG = 1
- }
-}
+ override // could also return null, just to be safe return empty song
+ val song: Song
+ get() = if (itemViewType == OFFSET_ITEM) Song.emptySong else dataSet[adapterPosition - 1]
+
+ override fun onClick(v: View?) {
+ if (isInQuickSelectMode && itemViewType != OFFSET_ITEM) {
+ toggleChecked(adapterPosition)
+ } else {
+ MusicPlayerRemote.openQueue(dataSet, adapterPosition - 1, true)
+ }
+ }
+
+ override fun onLongClick(v: View?): Boolean {
+ if (itemViewType == OFFSET_ITEM) return false
+ toggleChecked(adapterPosition)
+ return true
+ }
+ }
+
+ companion object {
+ const val OFFSET_ITEM = 0
+ const val SONG = 1
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt
index bf85fe28b..5095a4408 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt
@@ -1,134 +1,134 @@
-/*
- * Copyright (c) 2020 Hemanth Savarla.
- *
- * Licensed under the GNU General Public License v3
- *
- * This is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- */
package code.name.monkey.retromusic.adapter.song
-import android.view.MenuItem
-import android.view.View
-import androidx.core.view.isVisible
-import androidx.fragment.app.FragmentActivity
-import androidx.lifecycle.lifecycleScope
+import android.view.*
+import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.db.PlaylistEntity
-import code.name.monkey.retromusic.db.toSongEntity
-import code.name.monkey.retromusic.db.toSongsEntity
-import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog
-import code.name.monkey.retromusic.fragments.LibraryViewModel
-import code.name.monkey.retromusic.model.Song
+import code.name.monkey.retromusic.dialogs.RemoveFromPlaylistDialog
+import code.name.monkey.retromusic.interfaces.CabHolder
+import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.util.ViewUtil
-import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
-import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import org.koin.androidx.viewmodel.ext.android.viewModel
+import com.h6ah4i.android.widget.advrecyclerview.draggable.*
+import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
class OrderablePlaylistSongAdapter(
- private val playlistId: Long,
- activity: FragmentActivity,
- dataSet: MutableList,
- itemLayoutRes: Int,
-) : SongAdapter(activity, dataSet, itemLayoutRes),
- DraggableItemAdapter {
+ activity: AppCompatActivity,
+ dataSet: ArrayList