(...);
+}
+-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
+ **[] $VALUES;
+ public *;
+}
+-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
+ *** rewind();
}
--keep class !android.support.v7.internal.view.menu.**,** {*;}
+# OkHttp
+-keepattributes Signature
+-keepattributes *Annotation*
+-keep interface com.squareup.okhttp3.** { *; }
+-dontwarn com.squareup.okhttp3.**
--dontwarn
--ignorewarnings
+#-dontwarn
+#-ignorewarnings
-# ------- FastScrollRecycleView START -------
--keep class com.simplecityapps.recyclerview_fastscroll.views.FastScrollPopup { *; }
-# ------- FastScrollRecycleView END -------
+#Jaudiotagger
+-dontwarn org.jaudiotagger.**
+-dontwarn org.jcodec.**
+-keep class org.jaudiotagger.** { *; }
+-keep class org.jcodec.** { *; }
--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
+-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
diff --git a/app/src/debug/res/font/bold.ttf b/app/src/debug/res/font/bold.ttf
new file mode 100644
index 000000000..96619df92
Binary files /dev/null and b/app/src/debug/res/font/bold.ttf differ
diff --git a/app/src/debug/res/font/google_sans_bold.ttf b/app/src/debug/res/font/google_sans_bold.ttf
new file mode 100644
index 000000000..80497666e
Binary files /dev/null and b/app/src/debug/res/font/google_sans_bold.ttf differ
diff --git a/app/src/debug/res/font/google_sans_medium.ttf b/app/src/debug/res/font/google_sans_medium.ttf
new file mode 100644
index 000000000..1543660da
Binary files /dev/null and b/app/src/debug/res/font/google_sans_medium.ttf differ
diff --git a/app/src/debug/res/font/google_sans_regular.ttf b/app/src/debug/res/font/google_sans_regular.ttf
new file mode 100644
index 000000000..ab605f9e2
Binary files /dev/null and b/app/src/debug/res/font/google_sans_regular.ttf differ
diff --git a/app/src/debug/res/font/medium.ttf b/app/src/debug/res/font/medium.ttf
new file mode 100644
index 000000000..fd818d6f5
Binary files /dev/null and b/app/src/debug/res/font/medium.ttf differ
diff --git a/app/src/debug/res/font/regular.ttf b/app/src/debug/res/font/regular.ttf
new file mode 100644
index 000000000..e2c69c3fb
Binary files /dev/null and b/app/src/debug/res/font/regular.ttf differ
diff --git a/app/src/debug/res/font/sans.xml b/app/src/debug/res/font/sans.xml
new file mode 100644
index 000000000..7bbc8513b
--- /dev/null
+++ b/app/src/debug/res/font/sans.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/debug/res/values/bools.xml b/app/src/debug/res/values/bools.xml
new file mode 100644
index 000000000..7d3f0ee62
--- /dev/null
+++ b/app/src/debug/res/values/bools.xml
@@ -0,0 +1,5 @@
+
+
+ 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
new file mode 100644
index 000000000..79e559838
--- /dev/null
+++ b/app/src/debug/res/values/donottranslate.xml
@@ -0,0 +1,4 @@
+
+
+ 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
new file mode 100644
index 000000000..f3761b219
--- /dev/null
+++ b/app/src/debug/res/values/styles.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2941835c5..14fbaaab7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,36 +1,57 @@
+ package="code.name.monkey.retromusic"
+ android:installLocation="auto">
+
+
+
+
-
-
-
-
+
+
+
+
-
+
-
-
-
+
+
+ android:usesCleartextTraffic="true"
+ tools:ignore="UnusedAttribute">
+ android:exported="true"
+ android:launchMode="singleTop"
+ android:theme="@style/Theme.RetroMusic.SplashScreen">
@@ -41,7 +62,6 @@
-
@@ -101,31 +121,54 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
-
+
-
+
@@ -172,7 +216,7 @@
@@ -185,7 +229,7 @@
@@ -197,7 +241,7 @@
@@ -209,7 +253,7 @@
@@ -221,7 +265,7 @@
@@ -231,13 +275,36 @@
android:name="android.appwidget.provider"
android:resource="@xml/app_widget_card_info" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:foregroundServiceType="mediaPlayback"
+ android:label="@string/app_name">
@@ -251,15 +318,33 @@
android:name="com.lge.support.SPLIT_WINDOW"
android:value="true" />
+
+ android:name="com.google.android.gms.car.application"
+ android:resource="@xml/automotive_app_desc" />
+
+
-
-
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/assets/contributors.json b/app/src/main/assets/contributors.json
deleted file mode 100644
index e84023c32..000000000
--- a/app/src/main/assets/contributors.json
+++ /dev/null
@@ -1,32 +0,0 @@
-[
- {
- "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
new file mode 100644
index 000000000..737f9066c
Binary files /dev/null and b/app/src/main/assets/images/daksh.png differ
diff --git a/app/src/main/assets/images/haythem.jpg b/app/src/main/assets/images/haythem.jpg
new file mode 100644
index 000000000..c74527f1d
Binary files /dev/null and b/app/src/main/assets/images/haythem.jpg differ
diff --git a/app/src/main/assets/images/hemanth.jpg b/app/src/main/assets/images/hemanth.jpg
new file mode 100644
index 000000000..b8f5e7805
Binary files /dev/null and b/app/src/main/assets/images/hemanth.jpg differ
diff --git a/app/src/main/assets/images/lenny.jpg b/app/src/main/assets/images/lenny.jpg
new file mode 100644
index 000000000..7f8025f08
Binary files /dev/null and b/app/src/main/assets/images/lenny.jpg differ
diff --git a/app/src/main/assets/images/milind.png b/app/src/main/assets/images/milind.png
new file mode 100644
index 000000000..bbf9b8278
Binary files /dev/null and b/app/src/main/assets/images/milind.png differ
diff --git a/app/src/main/assets/images/pratham.jpg b/app/src/main/assets/images/pratham.jpg
new file mode 100644
index 000000000..7f05ad9d5
Binary files /dev/null and b/app/src/main/assets/images/pratham.jpg differ
diff --git a/app/src/main/assets/index.html b/app/src/main/assets/index.html
deleted file mode 100644
index 4d858fba4..000000000
--- a/app/src/main/assets/index.html
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-
-
- 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
new file mode 100644
index 000000000..2fd8ba5ed
--- /dev/null
+++ b/app/src/main/assets/license.html
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+ 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 dc00d3156..b6b1c411a 100644
--- a/app/src/main/assets/retro-changelog.html
+++ b/app/src/main/assets/retro-changelog.html
@@ -1 +1,466 @@
-
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
+
+
+
+
+
+
+
+
+
+
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
diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png
index af146924b..aa6e4ae9a 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 ff0f8b9ff..7e7647db5 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 2a1dcccac..93dfe4d96 100644
--- a/app/src/main/java/code/name/monkey/retromusic/App.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/App.kt
@@ -1,71 +1,67 @@
/*
- * Copyright (c) 2019 Hemanth Savarala.
+ * Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
- * This is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by
- * the Free Software Foundation either version 3 of the License, or (at your option) any later version.
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
+ *
*/
-
package code.name.monkey.retromusic
-import android.widget.Toast
-import androidx.multidex.MultiDexApplication
+import android.app.Application
+import androidx.preference.PreferenceManager
+import cat.ereza.customactivityoncrash.config.CaocConfig
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.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
+import code.name.monkey.retromusic.helper.WallpaperAccentManager
+import org.koin.android.ext.koin.androidContext
+import org.koin.core.context.startKoin
+class App : Application() {
-class App : MultiDexApplication() {
-
- lateinit var billingProcessor: BillingProcessor
+ private val wallpaperAccentManager = WallpaperAccentManager(this)
override fun onCreate() {
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(R.color.md_deep_purple_A200)
- .coloredNavigationBar(true)
- .commit()
+ .accentColorRes(code.name.monkey.appthemehelper.R.color.md_deep_purple_A200)
+ .coloredNavigationBar(true)
+ .commit()
}
+ wallpaperAccentManager.init()
if (VersionUtils.hasNougatMR())
DynamicShortcutManager(this).initDynamicShortcuts()
- // automatically restores purchases
- billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY,
- object : BillingProcessor.IBillingHandler {
- override fun onProductPurchased(productId: String, details: TransactionDetails?) {}
+ // setting Error activity
+ CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java)
+ .restartActivity(MainActivity::class.java).apply()
- 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() {}
- })
+ // 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 onTerminate() {
super.onTerminate()
- billingProcessor.release()
+ wallpaperAccentManager.release()
}
companion object {
@@ -74,14 +70,5 @@ class App : MultiDexApplication() {
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 6c04105ca..31032f62b 100644
--- a/app/src/main/java/code/name/monkey/retromusic/Constants.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/Constants.kt
@@ -1,51 +1,154 @@
/*
- * Copyright (c) 2019 Hemanth Savarala.
+ * Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
- * This is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by
- * the Free Software Foundation either version 3 of the License, or (at your option) any later version.
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
+ *
*/
-
package code.name.monkey.retromusic
import android.provider.BaseColumns
import android.provider.MediaStore
object Constants {
-
- 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 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 USER_PROFILE = "profile.jpg"
const val USER_BANNER = "banner.jpg"
- 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 FAQ_LINK = "https://github.com/MuntashirAkon/Metro/blob/master/FAQ.md"
- const val BASE_SELECTION = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
+ const val IS_MUSIC =
+ MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
- 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 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
+ )
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
new file mode 100644
index 000000000..4f1273a03
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/HomeSection.kt
@@ -0,0 +1,42 @@
+/*
+ * 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
new file mode 100644
index 000000000..d88f8a760
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt
@@ -0,0 +1,156 @@
+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
deleted file mode 100644
index f2f00f8b9..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/Result.kt
+++ /dev/null
@@ -1,24 +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
-
-/**
- * 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
deleted file mode 100644
index 48ffc3fbd..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/AboutActivity.kt
+++ /dev/null
@@ -1,172 +0,0 @@
-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.ATHUtil
-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.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)
-
-
- val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
- toolbar.setBackgroundColor(toolbarColor)
- ToolbarContentTintHelper.colorBackButton(toolbar)
- setSupportActionBar(toolbar)
- version.setSummary(getAppVersion())
- setUpView()
- loadContributors()
- }
-
- 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
deleted file mode 100644
index 2c5ab8589..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt
+++ /dev/null
@@ -1,306 +0,0 @@
-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.album.HorizontalAlbumAdapter
-import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
-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
deleted file mode 100755
index 980e98655..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt
+++ /dev/null
@@ -1,321 +0,0 @@
-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.adapter.album.AlbumAdapter
-import code.name.monkey.retromusic.adapter.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
new file mode 100644
index 000000000..af3890d22
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt
@@ -0,0 +1,258 @@
+/*
+ * 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
new file mode 100644
index 000000000..6823b80f8
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/ErrorActivity.kt
@@ -0,0 +1,80 @@
+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
deleted file mode 100644
index 6d3ca8091..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/GenreDetailsActivity.kt
+++ /dev/null
@@ -1,151 +0,0 @@
-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
deleted file mode 100644
index d0edccdb3..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.java
+++ /dev/null
@@ -1,96 +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 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, 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");
- }
-
- }
-}
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
new file mode 100644
index 000000000..e41352dae
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt
@@ -0,0 +1,94 @@
+/*
+ * 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 3f0dffbd3..3ac219871 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,96 +1,121 @@
+/*
+ * 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.view.ViewCompat
+import androidx.core.content.getSystemService
+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.fragments.player.lockscreen.LockScreenPlayerControlsFragment
+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.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 var fragment: LockScreenPlayerControlsFragment? = null
+ private lateinit var binding: ActivityLockScreenBinding
+ private var fragment: LockScreenControlsFragment? = null
- 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)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ lockScreenInit()
+ binding = ActivityLockScreenBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ hideStatusBar()
+ setTaskDescriptionColorAuto()
- 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 onSlideChange(percent: Float) {
+ override fun onSlideOpened() {
+ }
- }
+ override fun onSlideClosed(): Boolean {
+ if (VersionUtils.hasOreo()) {
+ val keyguardManager =
+ getSystemService()
+ keyguardManager?.requestDismissKeyguard(this@LockScreenActivity, null)
+ }
+ finish()
+ return true
+ }
+ }).position(SlidrPosition.BOTTOM).build()
- override fun onSlideOpened() {
+ Slidr.attach(this, config)
- }
+ fragment = whichFragment(R.id.playback_controls_fragment)
- 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()
+ binding.slide.apply {
+ translationY = 100f
+ alpha = 0f
+ animate().translationY(0f).alpha(1f).setDuration(1500).start()
+ }
+ }
- Slidr.attach(this, config)
+ @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
+ )
+ }
+ }
- fragment = supportFragmentManager.findFragmentById(R.id.playback_controls_fragment) as LockScreenPlayerControlsFragment?
+ override fun onPlayingMetaChanged() {
+ super.onPlayingMetaChanged()
+ updateSongs()
+ }
- findViewById(R.id.slide).apply {
- translationY = 100f
- alpha = 0f
- ViewCompat.animate(this).translationY(0f).alpha(1f).setDuration(1500).start()
- }
- }
+ override fun onServiceConnected() {
+ super.onServiceConnected()
+ updateSongs()
+ }
- 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
+ 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)
+ }
+ })
+ }
+}
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
deleted file mode 100644
index 16ddd66ff..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/LyricsActivity.kt
+++ /dev/null
@@ -1,414 +0,0 @@
-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.*
-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.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()
-
- 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)
- }
-
- val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
- toolbar.setBackgroundColor(toolbarColor)
- tabs.setBackgroundColor(toolbarColor)
- ToolbarContentTintHelper.colorBackButton(toolbar)
-
- tabs.setupWithViewPager(viewPager)
- tabs.setSelectedTabIndicator(TintHelper.createTintedDrawable(ContextCompat.getDrawable(this, R.drawable.tab_indicator), ThemeStore.accentColor(this)))
- tabs.setTabTextColors(ATHUtil.resolveColor(this, android.R.attr.textColorSecondary), ThemeStore.accentColor(this))
- tabs.setSelectedTabIndicatorColor(ThemeStore.accentColor(this))
-
- fab.setOnClickListener(this)
- }
-
- override fun onPlayingMetaChanged() {
- super.onPlayingMetaChanged()
- updateTitleSong()
- }
-
- override fun onServiceConnected() {
- super.onServiceConnected()
- updateTitleSong()
- }
-
- private fun updateTitleSong() {
- 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 ac724d2e0..e9cb29abe 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,259 +1,214 @@
+/*
+ * 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.*
+import android.content.Intent
+import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
-import android.util.Log
-import android.view.View
-import androidx.core.app.ActivityCompat
-import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.contains
+import androidx.navigation.ui.setupWithNavController
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
-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.extensions.*
import code.name.monkey.retromusic.helper.MusicPlayerRemote
-import code.name.monkey.retromusic.helper.SearchQueryHelper
-import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
-import code.name.monkey.retromusic.loaders.AlbumLoader
-import code.name.monkey.retromusic.loaders.ArtistLoader
-import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
+import code.name.monkey.retromusic.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.service.MusicService
-import code.name.monkey.retromusic.util.AppRater
import code.name.monkey.retromusic.util.PreferenceUtil
-import io.reactivex.disposables.CompositeDisposable
-import java.util.*
+import code.name.monkey.retromusic.util.logE
+import kotlinx.coroutines.Dispatchers.IO
+import kotlinx.coroutines.launch
+import org.koin.android.ext.android.get
-class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
+class MainActivity : AbsSlidingMusicPanelActivity() {
+ companion object {
+ const val TAG = "MainActivity"
+ const val EXPAND_PANEL = "expand_panel"
+ }
- private lateinit var currentFragment: MainActivityFragmentCallbacks
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setTaskDescriptionColorAuto()
+ hideStatusBar()
+ updateTabs()
- 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)
+ setupNavigationController()
+
+ WhatsNewFragment.showChangeLog(this)
+ }
+
+ private fun setupNavigationController() {
+ val navController = findNavController(R.id.fragment_container)
+ val navInflater = navController.navInflater
+ val navGraph = navInflater.inflate(R.navigation.main_graph)
+
+ val categoryInfo: CategoryInfo = PreferenceUtil.libraryCategory.first { it.visible }
+ if (categoryInfo.visible) {
+ 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()
}
}
}
- }
-
- override fun createContentView(): View {
- return wrapSlidingMusicPanel(R.layout.activity_main_content)
- }
-
- override fun onCreate(
- savedInstanceState: Bundle?
- ) {
- setDrawUnderStatusBar()
- super.onCreate(savedInstanceState)
- getBottomNavigationView().selectedItemId = PreferenceUtil.getInstance(this).lastPage
- getBottomNavigationView().setOnNavigationItemSelectedListener {
- PreferenceUtil.getInstance(this).lastPage = it.itemId
- selectedFragment(it.itemId)
- true
- }
-
- if (savedInstanceState == null) {
- setMusicChooser(PreferenceUtil.getInstance(this).lastMusicChooser)
- } else {
- restoreCurrentFragment()
- }
-
- checkShowChangelog()
- AppRater.appLaunched(this)
- }
-
- 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
- )
+ navController.addOnDestinationChangedListener { _, destination, _ ->
+ if (destination.id == navGraph.startDestinationId) {
+ currentFragment(R.id.fragment_container)?.enterTransition = null
}
- } catch (e: Throwable) {
- e.printStackTrace()
- }
-
- }
-
- 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)
+ 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 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
+ private fun saveTab(id: Int) {
+ if (PreferenceUtil.libraryCategory.firstOrNull { it.category.id == id }?.visible == true) {
+ PreferenceUtil.lastTab = id
}
}
- private fun restoreCurrentFragment() {
- currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as MainActivityFragmentCallbacks
+ override fun onSupportNavigateUp(): Boolean =
+ findNavController(R.id.fragment_container).navigateUp()
+
+ 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 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)
+ }
- 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)
+ 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)
+ }
handled = true
}
- } 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)
+ if (uri != null && uri.toString().isNotEmpty()) {
+ MusicPlayerRemote.playFromUri(this@MainActivity, uri)
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
+ }
}
- } 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())
}
}
- if (handled) {
- setIntent(Intent())
- }
}
- private fun parseIdFromIntent(intent: Intent, longKey: String, stringKey: String): Long {
+ private fun parseLongFromIntent(
+ 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 = java.lang.Long.parseLong(idString)
+ id = idString.toLong()
} catch (e: NumberFormatException) {
- Log.e(TAG, e.message)
+ logE(e)
}
}
}
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
new file mode 100644
index 000000000..5cb64cf93
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/PermissionActivity.kt
@@ -0,0 +1,144 @@
+/*
+ * 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/activities/PlaylistDetailActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt
deleted file mode 100644
index 5d1361ce8..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt
+++ /dev/null
@@ -1,232 +0,0 @@
-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
deleted file mode 100644
index 419f81df3..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt
+++ /dev/null
@@ -1,155 +0,0 @@
-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
deleted file mode 100644
index 082adc6b5..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/SearchActivity.kt
+++ /dev/null
@@ -1,223 +0,0 @@
-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
deleted file mode 100755
index b11287322..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/SettingsActivity.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-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
new file mode 100644
index 000000000..546c9d794
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/ShareInstagramStory.kt
@@ -0,0 +1,114 @@
+/*
+ * 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
deleted file mode 100644
index 0f27363ea..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt
+++ /dev/null
@@ -1,247 +0,0 @@
-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
deleted file mode 100644
index c623d11d9..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/UserInfoActivity.kt
+++ /dev/null
@@ -1,245 +0,0 @@
-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
deleted file mode 100644
index 176114cbb..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.java
+++ /dev/null
@@ -1,93 +0,0 @@
-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
new file mode 100644
index 000000000..48b39ed35
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewFragment.kt
@@ -0,0 +1,153 @@
+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 3b096f518..1e0c110d5 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,143 +1,204 @@
+/*
+ * 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.*
+import android.os.Bundle
import android.provider.Settings
-import android.view.*
+import android.view.KeyEvent
+import android.view.MotionEvent
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import android.widget.EditText
import androidx.core.app.ActivityCompat
-import code.name.monkey.appthemehelper.ThemeStore
+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 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(code.name.monkey.retromusic.R.string.permissions_denied) else permissionDeniedMessage!!
- }
+ fun getPermissionDeniedMessage(): String {
+ return if (permissionDeniedMessage == null) getString(R.string.permissions_denied) else permissionDeniedMessage!!
+ }
- private val snackBarContainer: View
- get() = window.decorView
+ private val snackBarContainer: View
+ get() = rootView
- 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 onPostCreate(savedInstanceState: Bundle?) {
- super.onPostCreate(savedInstanceState)
- if (!hasPermissions()) {
- requestPermissions()
- }
- }
+ override fun onResume() {
+ super.onResume()
+ val hasPermissions = hasPermissions()
+ if (hasPermissions != hadPermissions) {
+ hadPermissions = hasPermissions
+ if (VersionUtils.hasMarshmallow()) {
+ onHasPermissionsChanged(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)
- }
- }
- }
+ protected open fun onHasPermissionsChanged(hasPermissions: Boolean) {
+ // implemented by sub classes
+ logD(hasPermissions)
+ }
- protected open fun onHasPermissionsChanged(hasPermissions: Boolean) {
- // implemented by sub classes
- }
+ override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+ if (event.keyCode == KeyEvent.KEYCODE_MENU && event.action == KeyEvent.ACTION_UP) {
+ showOverflowMenu()
+ return true
+ }
+ return super.dispatchKeyEvent(event)
+ }
- override fun dispatchKeyEvent(event: KeyEvent): Boolean {
- if (event.keyCode == KeyEvent.KEYCODE_MENU && event.action == KeyEvent.ACTION_UP) {
- showOverflowMenu()
- return true
- }
- return super.dispatchKeyEvent(event)
- }
+ private fun showOverflowMenu() {
+ }
- protected fun showOverflowMenu() {
+ protected open fun requestPermissions() {
+ ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST)
+ }
- }
+ protected fun hasPermissions(): Boolean {
+ for (permission in permissions) {
+ if (ActivityCompat.checkSelfPermission(this,
+ permission) != PackageManager.PERMISSION_GRANTED
+ ) {
+ return false
+ }
+ }
+ return true
+ }
- protected open fun requestPermissions() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- requestPermissions(permissions, PERMISSION_REQUEST)
- }
- }
+ 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 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
- }
+ companion object {
+ const val PERMISSION_REQUEST = 100
+ const val BLUETOOTH_PERMISSION_REQUEST = 101
+ }
- 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
- }
+ // 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)
+ }
}
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 30e99735b..f9f05c919 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,167 +1,221 @@
+/*
+ * 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.*
+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 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.MusicServiceEventListener
-import code.name.monkey.retromusic.service.MusicService.*
+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 java.lang.ref.WeakReference
-import java.util.*
-abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener {
+abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventListener {
- private val mMusicServiceEventListeners = ArrayList()
+ 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 var serviceToken: MusicPlayerRemote.ServiceToken? = null
- private var musicStateReceiver: MusicStateReceiver? = null
- private var receiverRegistered: Boolean = false
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ serviceToken = MusicPlayerRemote.bindToService(this, object : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ this@AbsMusicServiceActivity.onServiceConnected()
+ }
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- serviceToken = MusicPlayerRemote.bindToService(this, object : ServiceConnection {
- override fun onServiceConnected(name: ComponentName, service: IBinder) {
- this@AbsMusicServiceActivity.onServiceConnected()
- }
+ override fun onServiceDisconnected(name: ComponentName) {
+ this@AbsMusicServiceActivity.onServiceDisconnected()
+ }
+ })
- override fun onServiceDisconnected(name: ComponentName) {
- this@AbsMusicServiceActivity.onServiceDisconnected()
- }
- })
+ setPermissionDeniedMessage(getString(R.string.permission_external_storage_denied))
+ }
- setPermissionDeniedMessage(getString(R.string.permission_external_storage_denied));
- }
+ override fun onDestroy() {
+ super.onDestroy()
+ MusicPlayerRemote.unbindFromService(serviceToken)
+ if (receiverRegistered) {
+ unregisterReceiver(musicStateReceiver)
+ receiverRegistered = false
+ }
+ }
- override fun onDestroy() {
- super.onDestroy()
- MusicPlayerRemote.unbindFromService(serviceToken)
- if (receiverRegistered) {
- unregisterReceiver(musicStateReceiver)
- receiverRegistered = false
- }
- }
+ fun addMusicServiceEventListener(listenerI: IMusicServiceEventListener?) {
+ if (listenerI != null) {
+ mMusicServiceEventListeners.add(listenerI)
+ }
+ }
- fun addMusicServiceEventListener(listener: MusicServiceEventListener?) {
- if (listener != null) {
- mMusicServiceEventListeners.add(listener)
- }
- }
+ fun removeMusicServiceEventListener(listenerI: IMusicServiceEventListener?) {
+ if (listenerI != null) {
+ mMusicServiceEventListeners.remove(listenerI)
+ }
+ }
- fun removeMusicServiceEventListener(listener: MusicServiceEventListener?) {
- if (listener != null) {
- mMusicServiceEventListeners.remove(listener)
- }
- }
+ override fun onServiceConnected() {
+ if (!receiverRegistered) {
+ musicStateReceiver = MusicStateReceiver(this)
- override fun onServiceConnected() {
- if (!receiverRegistered) {
- musicStateReceiver = MusicStateReceiver(this)
+ 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)
- 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)
+ ContextCompat.registerReceiver(this, musicStateReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED)
+ receiverRegistered = true
+ }
- registerReceiver(musicStateReceiver, filter)
+ for (listener in mMusicServiceEventListeners) {
+ listener.onServiceConnected()
+ }
+ }
- receiverRegistered = true
- }
+ override fun onServiceDisconnected() {
+ if (receiverRegistered) {
+ unregisterReceiver(musicStateReceiver)
+ receiverRegistered = false
+ }
- for (listener in mMusicServiceEventListeners) {
- listener.onServiceConnected()
- }
- }
+ for (listener in mMusicServiceEventListeners) {
+ listener.onServiceDisconnected()
+ }
+ }
- override fun onServiceDisconnected() {
- if (receiverRegistered) {
- unregisterReceiver(musicStateReceiver)
- receiverRegistered = false
- }
+ 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()
- for (listener in mMusicServiceEventListeners) {
- listener.onServiceDisconnected()
- }
- }
+ repository.upsertSongInPlayCount(song)
+ }
+ }
- override fun onPlayingMetaChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onPlayingMetaChanged()
- }
- }
+ override fun onQueueChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onQueueChanged()
+ }
+ }
- override fun onQueueChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onQueueChanged()
- }
- }
+ override fun onPlayStateChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onPlayStateChanged()
+ }
+ }
- override fun onPlayStateChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onPlayStateChanged()
- }
- }
+ override fun onMediaStoreChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onMediaStoreChanged()
+ }
+ }
- override fun onMediaStoreChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onMediaStoreChanged()
- }
- }
+ override fun onRepeatModeChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onRepeatModeChanged()
+ }
+ }
- override fun onRepeatModeChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onRepeatModeChanged()
- }
- }
+ override fun onShuffleModeChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onShuffleModeChanged()
+ }
+ }
- override fun onShuffleModeChanged() {
- for (listener in mMusicServiceEventListeners) {
- listener.onShuffleModeChanged()
- }
- }
+ override fun onFavoriteStateChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onFavoriteStateChanged()
+ }
+ }
- 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 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 getPermissionsToRequest(): Array {
- return arrayOf(
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE
- )
- }
+ 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()
+ }
- 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, 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 -> 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()
+ }
+ }
+ }
+ }
- 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 cc72372dc..2a81ca9b4 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,110 +1,226 @@
+/*
+ * 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 androidx.annotation.LayoutRes
-import androidx.fragment.app.Fragment
-import code.name.monkey.appthemehelper.util.ATHUtil
-import code.name.monkey.appthemehelper.util.ColorUtil
+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 code.name.monkey.retromusic.R
-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.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.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.peak.PeakPlayerFragment
+import code.name.monkey.retromusic.fragments.player.peek.PeekPlayerFragment
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.views.BottomNavigationBarTinted
+import code.name.monkey.retromusic.util.ViewUtil
+import code.name.monkey.retromusic.util.logD
+import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.bottomsheet.BottomSheetBehavior
-import com.google.android.material.card.MaterialCardView
-import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
+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
-abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlayerFragment.Callbacks {
+
+abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
+ SharedPreferences.OnSharedPreferenceChangeListener {
companion object {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
}
- private lateinit var bottomSheetBehavior: BottomSheetBehavior
+ var fromNotification = false
+ private var windowInsets: WindowInsetsCompat? = null
+ protected val libraryViewModel by viewModel()
+ private lateinit var bottomSheetBehavior: BottomSheetBehavior
+ private lateinit var playerFragment: AbsPlayerFragment
private var miniPlayerFragment: MiniPlayerFragment? = null
- private var playerFragment: AbsPlayerFragment? = null
- private var currentNowPlayingScreen: NowPlayingScreen? = null
- private var navigationBarColor: Int = 0
+ private var nowPlayingScreen: NowPlayingScreen? = null
private var taskColor: Int = 0
- private var lightStatusBar: Boolean = false
- private var lightNavigationBar: Boolean = false
- private var navigationBarColorAnimator: ValueAnimator? = null
- protected abstract fun createContentView(): View
+ private var paletteColor: Int = Color.WHITE
+ private var navigationBarColor = 0
+
private val panelState: Int
get() = bottomSheetBehavior.state
+ private lateinit var binding: SlidingMusicPanelLayoutBinding
+ private var isInOneTabMode = false
- private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
+ private var navigationBarColorAnimator: ValueAnimator? = null
+ private val argbEvaluator: ArgbEvaluator = ArgbEvaluator()
- override fun onSlide(bottomSheet: View, slideOffset: Float) {
- setMiniPlayerAlphaProgress(slideOffset)
- dimBackground.show()
- dimBackground.alpha = slideOffset
+ private val onBackPressedCallback = object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+ println("Handle back press ${bottomSheetBehavior.state}")
+ if (!handleBackPress()) {
+ remove()
+ onBackPressedDispatcher.onBackPressed()
+ }
}
+ }
- override fun onStateChanged(bottomSheet: View, newState: Int) {
- when (newState) {
- BottomSheetBehavior.STATE_EXPANDED -> {
- onPanelExpanded()
- }
- BottomSheetBehavior.STATE_COLLAPSED -> {
- onPanelCollapsed()
- dimBackground.hide()
- }
- else -> {
+ private val bottomSheetCallbackList by lazy {
+ object : BottomSheetCallback() {
+ 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)
- setContentView(createContentView())
-
+ 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
+ }
chooseFragmentForTheme()
setupSlidingUpPanel()
+ setupBottomSheet()
+ updateColor()
+ if (!PreferenceUtil.materialYou) {
+ binding.slidingPanel.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
+ navigationView.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
+ }
- updateTabs()
+ navigationBarColor = surfaceColor()
- bottomSheetBehavior = BottomSheetBehavior.from(slidingPanel)
+ onBackPressedDispatcher.addCallback(onBackPressedCallback)
+ }
- val themeColor = ATHUtil.resolveColor(this, android.R.attr.windowBackground, Color.GRAY)
- dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
+ private fun setupBottomSheet() {
+ bottomSheetBehavior = from(binding.slidingPanel)
+ bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
+ bottomSheetBehavior.isHideable = PreferenceUtil.swipeDownToDismiss
+ bottomSheetBehavior.significantVelocityThreshold = 300
+ setMiniPlayerAlphaProgress(0F)
}
override fun onResume() {
super.onResume()
- if (currentNowPlayingScreen != PreferenceUtil.getInstance(this).nowPlayingScreen) {
+ PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
+ if (nowPlayingScreen != PreferenceUtil.nowPlayingScreen) {
postRecreate()
}
- bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
-
- if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) {
+ if (bottomSheetBehavior.state == STATE_EXPANDED) {
setMiniPlayerAlphaProgress(1f)
}
}
@@ -112,246 +228,354 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlay
override fun onDestroy() {
super.onDestroy()
bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList)
- if (navigationBarColorAnimator != null) navigationBarColorAnimator?.cancel() // just in case
+ PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)
}
- 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
+ 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()
+ }
+ }
}
- private fun collapsePanel() {
- bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
+ fun collapsePanel() {
+ bottomSheetBehavior.state = STATE_COLLAPSED
}
fun expandPanel() {
- bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
- setMiniPlayerAlphaProgress(1f)
+ bottomSheetBehavior.state = STATE_EXPANDED
}
private fun setMiniPlayerAlphaProgress(progress: Float) {
- if (miniPlayerFragment?.view == null) return
+ if (progress < 0) return
val alpha = 1 - progress
- miniPlayerFragment?.view?.alpha = alpha
- // necessary to make the views below clickable
- miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE
+ 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
+ }
- bottomNavigationView.translationY = progress * 500
- //bottomNavigationView.alpha = alpha
+ 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()
+ }
}
open fun onPanelCollapsed() {
+ setMiniPlayerAlphaProgress(0F)
// restore values
- super.setLightStatusbar(lightStatusBar)
- super.setTaskDescriptionColor(taskColor)
- super.setNavigationbarColor(navigationBarColor)
- super.setLightNavigationBar(lightNavigationBar)
-
-
- playerFragment?.setMenuVisibility(false)
- playerFragment?.userVisibleHint = false
- playerFragment?.onHide()
+ animateNavigationBarColor(surfaceColor())
+ setLightStatusBarAuto()
+ setLightNavigationBarAuto()
+ setTaskDescriptionColor(taskColor)
+ //playerFragment?.onHide()
}
open fun onPanelExpanded() {
- val playerFragmentColor = playerFragment!!.paletteColor
- super.setTaskDescriptionColor(playerFragmentColor)
-
- playerFragment?.setMenuVisibility(true)
- playerFragment?.userVisibleHint = true
- playerFragment?.onShow()
+ setMiniPlayerAlphaProgress(1F)
onPaletteColorChanged()
+ //playerFragment?.onShow()
}
private fun setupSlidingUpPanel() {
- slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
+ binding.slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object :
+ ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
- slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
- if (currentNowPlayingScreen != PEAK) {
- val params = slidingPanel.layoutParams as ViewGroup.LayoutParams
- params.height = ViewGroup.LayoutParams.MATCH_PARENT
- slidingPanel.layoutParams = params
+ binding.slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
+ if (nowPlayingScreen != Peek) {
+ binding.slidingPanel.updateLayoutParams {
+ height = ViewGroup.LayoutParams.MATCH_PARENT
+ }
}
when (panelState) {
- BottomSheetBehavior.STATE_EXPANDED -> onPanelExpanded()
- BottomSheetBehavior.STATE_COLLAPSED -> onPanelCollapsed()
- else -> playerFragment!!.onHide()
+ STATE_EXPANDED -> onPanelExpanded()
+ STATE_COLLAPSED -> onPanelCollapsed()
+ else -> {
+ // playerFragment!!.onHide()
+ }
}
}
})
}
- fun toggleBottomNavigationView(toggle: Boolean) {
- bottomNavigationView.visibility = if (toggle) View.GONE else View.VISIBLE
- }
+ val navigationView get() = binding.navigationView
- fun getBottomNavigationView(): BottomNavigationBarTinted {
- return bottomNavigationView
- }
+ val slidingPanel get() = binding.slidingPanel
- 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() }
- }
+ val isBottomNavVisible get() = navigationView.isVisible && navigationView is BottomNavigationView
override fun onServiceConnected() {
super.onServiceConnected()
- 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
+ hideBottomSheet(false)
}
override fun onQueueChanged() {
super.onQueueChanged()
- hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
+ // 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())
+ }
}
- override fun onBackPressed() {
- if (!handleBackPress()) super.onBackPressed()
- }
-
- open fun handleBackPress(): Boolean {
- if (bottomSheetBehavior.peekHeight != 0 && playerFragment!!.onBackPressed()) return true
- if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
+ private fun handleBackPress(): Boolean {
+ if (panelState == STATE_EXPANDED) {
collapsePanel()
return true
}
return 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 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 setLightStatusbar(enabled: Boolean) {
- lightStatusBar = enabled
- if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
- super.setLightStatusbar(enabled)
- }
- }
-
- 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) {
+ private fun setTaskDescColor(color: Int) {
taskColor = color
- if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
- super.setTaskDescriptionColor(color)
+ if (panelState == STATE_COLLAPSED) {
+ setTaskDescriptionColor(color)
}
}
- private fun updateTabs() {
- bottomNavigationView.menu.clear()
- val currentTabs: List = PreferenceUtil.getInstance(this).libraryCategoryInfos
+ fun updateTabs() {
+ binding.navigationView.menu.clear()
+ val currentTabs: List = PreferenceUtil.libraryCategory
for (tab in currentTabs) {
if (tab.visible) {
val menu = tab.category
- bottomNavigationView.menu.add(0, menu.id, 0, menu.stringRes).setIcon(menu.icon)
+ binding.navigationView.menu.add(0, menu.id, 0, menu.stringRes)
+ .setIcon(menu.icon)
}
}
- print("Tabs -> ${currentTabs.size}")
- if (currentTabs.size <= 1) {
- toggleBottomNavigationView(true)
+ if (binding.navigationView.menu.size() == 1) {
+ isInOneTabMode = true
+ binding.navigationView.isVisible = false
+ } else {
+ isInOneTabMode = false
}
}
- /*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
+ 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()
}
}
}
- return super.dispatchTouchEvent(ev)
- }*/
-}
\ No newline at end of file
+ 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() }
+ }
+}
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 96bace4d9..32b025f01 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,44 +1,69 @@
+/*
+ * 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.graphics.Color
-import android.graphics.drawable.Drawable
+import android.content.Context
import android.os.Bundle
import android.os.Handler
+import android.os.Looper
import android.view.KeyEvent
-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 androidx.appcompat.app.AppCompatDelegate
+import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
+import androidx.core.os.LocaleListCompat
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.RetroUtil
-import code.name.monkey.retromusic.util.ThemeManager
+import code.name.monkey.retromusic.util.theme.getNightMode
+import code.name.monkey.retromusic.util.theme.getThemeResValue
abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
- private val handler = Handler()
+ private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
- setTheme(ThemeManager.getThemeResValue(this))
+ updateLocale()
+ updateTheme()
hideStatusBar()
super.onCreate(savedInstanceState)
- setImmersiveFullscreen()
- registerSystemUiVisibility()
- toggleScreenOn()
+ setEdgeToEdgeOrImmersive()
+ maybeSetScreenOn()
+ setLightNavigationBarAuto()
+ setLightStatusBarAuto(surfaceColor())
+ if (VersionUtils.hasQ()) {
+ window.decorView.isForceDarkAllowed = false
+ }
}
- 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)
+ 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
}
}
@@ -53,122 +78,6 @@ 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()
}
@@ -180,7 +89,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
public override fun onDestroy() {
super.onDestroy()
- unregisterSystemUiVisibility()
exitFullscreen()
}
@@ -190,6 +98,9 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
handler.postDelayed(this, 500)
}
return super.onKeyDown(keyCode, event)
-
}
-}
\ No newline at end of file
+
+ override fun attachBaseContext(newBase: Context?) {
+ super.attachBaseContext(newBase)
+ }
+}
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 a8a578094..e99881953 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,331 +1,91 @@
+/*
+ * 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 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 androidx.core.content.getSystemService
+import androidx.core.net.toUri
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.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
+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
open class BugReportActivity : AbsThemeActivity() {
+ private lateinit var binding: ActivityBugReportBinding
private var deviceInfo: DeviceInfo? = null
override fun onCreate(savedInstanceState: Bundle?) {
- setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_bug_report)
- setStatusbarColorAuto()
- setNavigationbarColorAuto()
+ binding = ActivityBugReportBinding.inflate(layoutInflater)
+ setContentView(binding.root)
setTaskDescriptionColorAuto()
initViews()
- if (TextUtils.isEmpty(title)) setTitle(R.string.report_an_issue)
+ if (title.isNullOrEmpty()) setTitle(R.string.report_an_issue)
deviceInfo = DeviceInfo(this)
- airTextDeviceInfo.text = deviceInfo.toString()
+ binding.cardDeviceInfo.airTextDeviceInfo.text = deviceInfo.toString()
}
private fun initViews() {
- val accentColor = ThemeStore.accentColor(this)
- val primaryColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
- toolbar.setBackgroundColor(primaryColor)
- setSupportActionBar(toolbar)
- ToolbarContentTintHelper.colorBackButton(toolbar)
+ val accentColor = accentColor()
+ setSupportActionBar(binding.toolbar)
+ ToolbarContentTintHelper.colorBackButton(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
- TintHelper.setTintAuto(optionUseAccount, accentColor, false)
- optionUseAccount?.setOnClickListener {
- inputTitle.isEnabled = true
- inputDescription.isEnabled = true
- inputUsername.isEnabled = true
- inputPassword.isEnabled = true
- 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
+ binding.cardDeviceInfo.airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() }
- 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)
+ TintHelper.setTintAuto(binding.sendFab, accentColor, true)
+ binding.sendFab.setOnClickListener { reportIssue() }
}
private fun reportIssue() {
- 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)
- }
+ copyDeviceInfoToClipBoard()
+ val i = Intent(Intent.ACTION_VIEW)
+ i.data = ISSUE_TRACKER_LINK.toUri()
+ i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ startActivity(i)
}
private fun copyDeviceInfoToClipBoard() {
- val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ val clipboard = getSystemService()
val clip = ClipData.newPlainText(getString(R.string.device_info), deviceInfo?.toMarkdown())
- clipboard.setPrimaryClip(clip)
- Toast.makeText(
- this@BugReportActivity,
- R.string.copied_device_info_to_clipboard,
- Toast.LENGTH_LONG
- ).show()
+ clipboard?.setPrimaryClip(clip)
+ showToast(R.string.copied_device_info_to_clipboard)
}
- 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) {
- onBackPressed()
+ onBackPressedDispatcher.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 STATUS_BAD_CREDENTIALS = 401
- private const val STATUS_ISSUES_NOT_ENABLED = 410
- private const val ISSUE_TRACKER_LINK = "https://github.com/h4h13/RetroMusicPlayer"
+ private const val ISSUE_TRACKER_LINK =
+ "https://github.com/MuntashirAkon/Metro/issues/new"
}
}
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
deleted file mode 100644
index 4e7ea77eb..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.java
+++ /dev/null
@@ -1,106 +0,0 @@
-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
new file mode 100644
index 000000000..19aff73a2
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.kt
@@ -0,0 +1,111 @@
+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
deleted file mode 100644
index 4549693f4..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/Report.java
+++ /dev/null
@@ -1,32 +0,0 @@
-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
deleted file mode 100644
index c9bedfa63..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/ExtraInfo.java
+++ /dev/null
@@ -1,59 +0,0 @@
-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
deleted file mode 100644
index a2d147eea..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/GithubLogin.java
+++ /dev/null
@@ -1,40 +0,0 @@
-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
deleted file mode 100644
index 4bea98be7..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/GithubTarget.java
+++ /dev/null
@@ -1,20 +0,0 @@
-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 4ba6c9902..efd56210e 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,47 +24,53 @@ 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;
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ public static final int REQUEST_CODE_SAF_GUIDE = 98;
- setButtonCtaVisible(false);
- setButtonNextVisible(false);
- setButtonBackVisible(false);
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- setButtonCtaTintMode(BUTTON_CTA_TINT_MODE_TEXT);
+ setButtonCtaVisible(false);
+ setButtonNextVisible(false);
+ setButtonBackVisible(false);
- String title = String.format(getString(R.string.saf_guide_slide1_title), getString(R.string.app_name));
+ setButtonCtaTintMode(BUTTON_CTA_TINT_MODE_TEXT);
- 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());
- }
+ 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());
+ }
}
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
new file mode 100644
index 000000000..1b389b9d2
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/saf/SAFRequestActivity.kt
@@ -0,0 +1,44 @@
+/*
+ * 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 df8cbe297..3a9ca4e4b 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,416 +1,457 @@
+/*
+ * 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.*
+import android.app.Activity
+import android.app.SearchManager
import android.content.Intent
-import android.content.res.ColorStateList
-import android.graphics.*
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
import android.net.Uri
-import android.os.*
+import android.os.Bundle
+import android.provider.MediaStore
import android.util.Log
-import android.view.*
+import android.view.LayoutInflater
+import android.view.MenuItem
import android.view.animation.OvershootInterpolator
-import code.name.monkey.appthemehelper.ThemeStore
-import code.name.monkey.appthemehelper.util.*
+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.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
-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 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 com.google.android.material.button.MaterialButton
-import kotlinx.android.synthetic.main.activity_album_tag_editor.*
-import org.jaudiotagger.audio.*
+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 org.jaudiotagger.tag.FieldKey
+import org.koin.android.ext.android.inject
import java.io.File
-import java.util.*
-abstract class AbsTagEditorActivity : AbsBaseActivity() {
+abstract class AbsTagEditorActivity : AbsBaseActivity() {
+ abstract val editorImage: ImageView
+ val repository by inject()
- 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
+ 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()
- private var savedSongPaths: List? = null
- private val currentSongPath: String? = null
- private var savedTags: Map? = null
- private var savedArtworkInfo: ArtworkInfo? = null
+ abstract val bindingInflater: (LayoutInflater) -> VB
- 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
+ private lateinit var launcher: ActivityResultLauncher
- internal val albumArtist: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
- } catch (ignored: Exception) {
- null
- }
+ protected abstract fun loadImageFromFile(selectedFile: Uri?)
- }
+ 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()
- protected val songTitle: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TITLE)
- } catch (ignored: Exception) {
- null
- }
+ internal val albumArtist: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
+ } 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 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 albumTitle: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM)
+ } 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 artistName: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ARTIST)
+ } catch (e: Exception) {
+ logE(e)
+ null
+ }
+ }
- }
+ protected val albumArtistName: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
+ } 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 genreName: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.GENRE)
+ } catch (e: Exception) {
+ logE(e)
+ null
+ }
+ }
- }
+ protected val songYear: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.YEAR)
+ } 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 trackNumber: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TRACK)
+ } catch (e: Exception) {
+ logE(e)
+ null
+ }
+ }
- }
+ protected val discNumber: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.DISC_NO)
+ } 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 lyrics: String?
+ get() {
+ return try {
+ getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.LYRICS)
+ } catch (e: Exception) {
+ logE(e)
+ 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
+ }
+ }
- protected val songYear: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.YEAR)
- } catch (ignored: Exception) {
- null
- }
+ private val pickArtworkImage =
+ registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
+ loadImageFromFile(uri)
+ }
- }
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ _binding = bindingInflater.invoke(layoutInflater)
+ setContentView(binding.root)
+ setTaskDescriptionColorAuto()
- protected val trackNumber: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TRACK)
- } catch (ignored: Exception) {
- null
- }
+ saveFab = findViewById(R.id.saveTags)
+ getIntentExtras()
- }
+ songPaths = getSongPaths()
+ logD(songPaths?.size)
+ if (songPaths!!.isEmpty()) {
+ finish()
+ }
+ setUpViews()
+ launcher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) {
+ if (it.resultCode == Activity.RESULT_OK) {
+ writeToFiles(getSongUris(), cacheFiles)
+ }
+ }
+ }
- protected val lyrics: String?
- get() {
- return try {
- getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.LYRICS)
- } catch (ignored: Exception) {
- null
- }
+ private fun setUpViews() {
+ setUpFab()
+ setUpImageView()
+ }
- }
+ private lateinit var items: List
- 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 setUpImageView() {
+ loadCurrentImage()
+ items = listOf(
+ getString(R.string.pick_from_local_storage),
+ getString(R.string.web_search),
+ getString(R.string.remove_cover)
+ )
+ editorImage.setOnClickListener { show }
+ }
- }
+ private fun startImagePicker() {
+ pickArtworkImage.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
+ }
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(contentViewLayout)
+ protected abstract fun loadCurrentImage()
- saveFab = findViewById(R.id.saveTags)
- getIntentExtras()
+ protected abstract fun searchImageOnWeb()
- songPaths = getSongPaths()
- if (songPaths!!.isEmpty()) {
- finish()
- return
- }
+ protected abstract fun deleteImage()
- setUpViews()
+ private fun setUpFab() {
+ saveFab.accentColor()
+ saveFab.apply {
+ scaleX = 0f
+ scaleY = 0f
+ isEnabled = false
+ setOnClickListener { save() }
+ }
+ }
+ protected abstract fun save()
- setNavigationbarColorAuto()
- setTaskDescriptionColorAuto()
- }
+ private fun getIntentExtras() {
+ val intentExtras = intent.extras
+ if (intentExtras != null) {
+ id = intentExtras.getLong(EXTRA_ID)
+ }
+ }
- private fun setUpViews() {
- setUpScrollView()
- setUpFab()
- setUpImageView()
- }
+ protected abstract fun getSongPaths(): List
- private fun setUpScrollView() {
- //observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
- }
+ protected abstract fun getSongUris(): List
- private lateinit var items: List
+ 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 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 }
- }
+ startActivity(intent)
+ }
- 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
- )
- }
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ android.R.id.home -> {
+ onBackPressedDispatcher.onBackPressed()
+ return true
+ }
+ }
+ return super.onOptionsItemSelected(item)
+ }
- protected abstract fun loadCurrentImage()
+ protected fun dataChanged() {
+ showFab()
+ }
- protected abstract fun searchImageOnWeb()
+ private fun showFab() {
+ saveFab.animate().setDuration(500).setInterpolator(OvershootInterpolator()).scaleX(1f)
+ .scaleY(1f).start()
+ saveFab.isEnabled = true
+ }
- protected abstract fun deleteImage()
+ private fun hideFab() {
+ saveFab.animate().setDuration(500).setInterpolator(OvershootInterpolator()).scaleX(0.0f)
+ .scaleY(0.0f).start()
+ saveFab.isEnabled = false
+ }
- 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 fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) {
+ if (bitmap == null) {
+ editorImage.setImageResource(R.drawable.default_audio_art)
+ } else {
+ editorImage.setImageBitmap(bitmap)
+ }
+ setColors(bgColor)
+ }
- protected abstract fun save()
+ protected open fun setColors(color: Int) {
+ paletteColorPrimary = color
+ }
- private fun getIntentExtras() {
- val intentExtras = intent.extras
- if (intentExtras != null) {
- id = intentExtras.getInt(EXTRA_ID)
- }
- }
+ protected fun writeValuesToFiles(
+ fieldKeyValueMap: Map,
+ artworkInfo: ArtworkInfo?
+ ) {
+ hideSoftKeyboard()
- protected abstract fun getSongPaths(): List
+ hideFab()
+ logD(fieldKeyValueMap)
+ GlobalScope.launch {
+ if (VersionUtils.hasR()) {
+ cacheFiles = TagWriter.writeTagsToFilesR(
+ 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)
+ if (cacheFiles.isNotEmpty()) {
+ val pendingIntent =
+ MediaStore.createWriteRequest(contentResolver, getSongUris())
+ launcher.launch(IntentSenderRequest.Builder(pendingIntent).build())
+ }
+ } else {
+ TagWriter.writeTagsToFiles(
+ this@AbsTagEditorActivity, AudioTagInfo(
+ songPaths,
+ fieldKeyValueMap,
+ artworkInfo
+ )
+ )
+ }
+ }
+ }
- startActivity(intent)
- }
+ 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())
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- android.R.id.home -> {
- super.onBackPressed()
- return true
- }
- }
- return super.onOptionsItemSelected(item)
- }
+ launcher.launch(IntentSenderRequest.Builder(pendingIntent).build())
+ } else {
+ TagWriter.writeTagsToFiles(
+ this@AbsTagEditorActivity, AudioTagInfo(
+ paths,
+ savedTags,
+ savedArtworkInfo
+ )
+ )
+ }
+ }
+ }
- protected fun setNoImageMode() {
- isInNoImageMode = true
- imageContainer?.visibility = View.GONE
- editorImage?.visibility = View.GONE
- editorImage?.isEnabled = false
+ private lateinit var audioFile: AudioFile
- setColors(
- intent.getIntExtra(
- EXTRA_PALETTE,
- ATHUtil.resolveColor(this, R.attr.colorPrimary)
- )
- )
- }
+ 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()
+ }
+ }
- protected fun dataChanged() {
- showFab()
- }
+ 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())
+ }
+ }
- private fun showFab() {
- saveFab.animate().setDuration(500).setInterpolator(OvershootInterpolator()).scaleX(1f)
- .scaleY(1f).start()
- saveFab.isEnabled = true
- }
+ override fun onDestroy() {
+ super.onDestroy()
+ // Delete Cache Files
+ cacheFiles.forEach { file ->
+ file.delete()
+ }
+ }
- 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
- }
+ 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 c96990322..2c9013657 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,3 +1,17 @@
+/*
+ * Copyright (c) 2020 Hemanth Savarla.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
package code.name.monkey.retromusic.activities.tageditor
import android.app.Activity
@@ -8,241 +22,198 @@ import android.graphics.Color
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
-import android.text.Editable
-import android.text.TextUtils
-import android.text.TextWatcher
+import android.transition.Slide
+import android.view.LayoutInflater
+import android.widget.ImageView
import android.widget.Toast
-import code.name.monkey.appthemehelper.util.ATHUtil
-import code.name.monkey.appthemehelper.util.MaterialUtil
+import androidx.core.widget.doAfterTextChanged
+import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R
-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.databinding.ActivityAlbumTagEditorBinding
+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.loaders.AlbumLoader
-import code.name.monkey.retromusic.rest.LastFMRestClient
-import code.name.monkey.retromusic.rest.model.LastFmAlbum
+import code.name.monkey.retromusic.model.ArtworkInfo
+import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.ImageUtil
-import code.name.monkey.retromusic.util.LastFMUtil
+import code.name.monkey.retromusic.util.MusicUtil
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.animation.GlideAnimation
-import com.bumptech.glide.request.target.SimpleTarget
-import io.reactivex.disposables.CompositeDisposable
-import kotlinx.android.synthetic.main.activity_album_tag_editor.*
+import com.bumptech.glide.request.target.ImageViewTarget
+import com.bumptech.glide.request.transition.Transition
+import com.google.android.material.shape.MaterialShapeDrawable
import org.jaudiotagger.tag.FieldKey
import java.util.*
-class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
- override val contentViewLayout: Int
- get() = R.layout.activity_album_tag_editor
+class AlbumTagEditorActivity : AbsTagEditorActivity() {
- override fun loadImageFromFile(selectedFileUri: Uri?) {
+ override val bindingInflater: (LayoutInflater) -> ActivityAlbumTagEditorBinding =
+ ActivityAlbumTagEditorBinding::inflate
- 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)
- }
+ 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)
- override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
- super.onLoadFailed(e, errorDrawable)
- Toast.makeText(this@AlbumTagEditorActivity, e.toString(), Toast.LENGTH_LONG)
- .show()
- }
- })
- }
+ window.enterTransition = slide
+ }
- private var albumArtBitmap: Bitmap? = null
- private var deleteAlbumArt: Boolean = false
- private var lastFMRestClient: LastFMRestClient? = null
- private val disposable = CompositeDisposable()
+ private var albumArtBitmap: Bitmap? = null
+ private var deleteAlbumArt: Boolean = false
- private fun setupToolbar() {
- applyToolbar(toolbar)
- supportActionBar?.setDisplayShowHomeEnabled(true)
- }
+ private fun setupToolbar() {
+ setSupportActionBar(binding.toolbar)
+ binding.appBarLayout?.statusBarForeground =
+ MaterialShapeDrawable.createWithElevationOverlay(this)
+ }
- override fun onCreate(savedInstanceState: Bundle?) {
- setDrawUnderStatusBar()
- super.onCreate(savedInstanceState)
- lastFMRestClient = LastFMRestClient(this)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ window.sharedElementsUseOverlay = true
+ binding.imageContainer.transitionName = getString(R.string.transition_album_art)
+ windowEnterTransition()
+ setUpViews()
+ setupToolbar()
+ }
- setUpViews()
- setupToolbar()
- }
+ private fun setUpViews() {
+ fillViewsWithFileTags()
- private fun setUpViews() {
- fillViewsWithFileTags()
+ binding.yearContainer.setTint(false)
+ binding.genreContainer.setTint(false)
+ binding.albumTitleContainer.setTint(false)
+ binding.albumArtistContainer.setTint(false)
- MaterialUtil.setTint(yearContainer, false)
- MaterialUtil.setTint(genreContainer, false)
- MaterialUtil.setTint(albumTitleContainer, false)
- MaterialUtil.setTint(albumArtistContainer, false)
+ binding.albumText.appHandleColor().doAfterTextChanged { dataChanged() }
+ binding.albumArtistText.appHandleColor().doAfterTextChanged { dataChanged() }
+ binding.genreTitle.appHandleColor().doAfterTextChanged { dataChanged() }
+ binding.yearTitle.appHandleColor().doAfterTextChanged { dataChanged() }
+ }
- albumText.appHandleColor().addTextChangedListener(this)
- albumArtistText.appHandleColor().addTextChangedListener(this)
- genreTitle.appHandleColor().addTextChangedListener(this)
- yearTitle.appHandleColor().addTextChangedListener(this)
- }
+ private fun fillViewsWithFileTags() {
+ binding.albumText.setText(albumTitle)
+ binding.albumArtistText.setText(albumArtistName)
+ binding.genreTitle.setText(genreName)
+ binding.yearTitle.setText(songYear)
+ logD(albumTitle + albumArtistName)
+ }
- private fun fillViewsWithFileTags() {
- albumText.setText(albumTitle)
- albumArtistText.setText(albumArtistName)
- genreTitle.setText(genreName)
- yearTitle.setText(songYear)
- }
+ override fun loadCurrentImage() {
+ val bitmap = albumArt
+ setImageBitmap(
+ bitmap,
+ getColor(
+ generatePalette(bitmap),
+ defaultFooterColor()
+ )
+ )
+ deleteAlbumArt = false
+ }
- override fun loadCurrentImage() {
- val bitmap = albumArt
- setImageBitmap(
- bitmap,
- getColor(
- generatePalette(bitmap),
- ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
- )
- )
- deleteAlbumArt = false
- }
+ private fun toastLoadingFailed() {
+ showToast(R.string.could_not_download_album_cover)
+ }
- override fun onPause() {
- super.onPause()
- disposable.clear()
- }
+ override fun searchImageOnWeb() {
+ searchWebFor(binding.albumText.text.toString(), binding.albumArtistText.text.toString())
+ }
- private fun extractDetails(lastFmAlbum: LastFmAlbum) {
- if (lastFmAlbum.album != null) {
+ override fun deleteImage() {
+ setImageBitmap(
+ BitmapFactory.decodeResource(resources, R.drawable.default_audio_art),
+ defaultFooterColor()
+ )
+ deleteAlbumArt = true
+ dataChanged()
+ }
- val url = LastFMUtil.getLargestAlbumImageUrl(lastFmAlbum.album.image)
+ 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)
+ }
- 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 onLoadFailed(errorDrawable: Drawable?) {
+ super.onLoadFailed(errorDrawable)
+ showToast(R.string.error_load_failed, Toast.LENGTH_LONG)
+ }
- 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 setResource(resource: BitmapPaletteWrapper?) {}
+ })
+ }
- }
- toastLoadingFailed()
- }
+ 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()
- private fun toastLoadingFailed() {
- Toast.makeText(
- this@AlbumTagEditorActivity,
- R.string.could_not_download_album_cover,
- Toast.LENGTH_SHORT
- ).show()
- }
+ writeValuesToFiles(
+ fieldKeyValueMap,
+ when {
+ deleteAlbumArt -> ArtworkInfo(id, null)
+ albumArtBitmap == null -> null
+ else -> ArtworkInfo(id, albumArtBitmap!!)
+ }
+ )
+ }
- override fun searchImageOnWeb() {
- searchWebFor(albumText.text.toString(), albumArtistText.text.toString())
- }
+ override fun getSongPaths(): List {
+ return repository.albumById(id).songs
+ .map(Song::data)
+ }
- override fun deleteImage() {
- setImageBitmap(
- BitmapFactory.decodeResource(resources, R.drawable.default_album_art),
- ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
- )
- deleteAlbumArt = true
- dataChanged()
- }
+ override fun getSongUris(): List = repository.albumById(id).songs.map {
+ MusicUtil.getSongFileUri(it.id)
+ }
- 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()
+ 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)
+ }
+ }
- writeValuesToFiles(
- fieldKeyValueMap, if (deleteAlbumArt) ArtworkInfo(id, null)
- else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)
- )
- }
- 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
- }
+ override val editorImage: ImageView
+ get() = binding.editorImage
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+ companion object {
- }
-
- 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
- }
+ 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 fb1dbb50b..93dd8a44f 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,119 +1,214 @@
+/*
+ * 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.text.Editable
-import android.text.TextWatcher
-import code.name.monkey.appthemehelper.util.MaterialUtil
+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 code.name.monkey.retromusic.R
-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 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 org.jaudiotagger.tag.FieldKey
+import org.koin.android.ext.android.inject
import java.util.*
-class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
+class SongTagEditorActivity : AbsTagEditorActivity() {
- override val contentViewLayout: Int
- get() = R.layout.activity_song_tag_editor
+ override val bindingInflater: (LayoutInflater) -> ActivitySongTagEditorBinding =
+ ActivitySongTagEditorBinding::inflate
+ 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()
- applyToolbar(toolbar)
- setStatusbarColorAuto()
+ setSupportActionBar(binding.toolbar)
+ binding.appBarLayout?.statusBarForeground =
+ MaterialShapeDrawable.createWithElevationOverlay(this)
}
+ @SuppressLint("ClickableViewAccessibility")
private fun setUpViews() {
fillViewsWithFileTags()
- 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.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)
- 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)
+ 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() }
}
private fun fillViewsWithFileTags() {
- 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)
+ 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)
}
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] = 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)
+ 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!!)
+ }
+ )
}
- override fun getSongPaths(): List {
- val paths = ArrayList(1)
- paths.add(SongLoader.getSong(this, id).data)
- return paths
- }
+ override fun getSongPaths(): List = listOf(songRepository.song(id).data)
+
+ override fun getSongUris(): List = listOf(MusicUtil.getSongFileUri(id))
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 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()
+ override fun setResource(resource: BitmapPaletteWrapper?) {}
+ })
}
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
new file mode 100644
index 000000000..b9d5f28dd
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt
@@ -0,0 +1,204 @@
+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
deleted file mode 100644
index d9bfb86af..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/WriteTagsAsyncTask.java
+++ /dev/null
@@ -1,188 +0,0 @@
-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
deleted file mode 100644
index 83273edc9..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java
+++ /dev/null
@@ -1,131 +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 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
new file mode 100644
index 000000000..dd5cda1d3
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.kt
@@ -0,0 +1,116 @@
+/*
+ * 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
deleted file mode 100644
index df7fec524..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-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 d8166e4f1..b139a0af8 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,14 +1,37 @@
+/*
+ * Copyright (c) 2020 Hemanth Savarla.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
package code.name.monkey.retromusic.adapter
-import android.app.Activity
+import android.annotation.SuppressLint
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.adapter.base.MediaEntryViewHolder
+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.model.Genre
-import code.name.monkey.retromusic.util.NavigationUtil
+import code.name.monkey.retromusic.util.MusicUtil
+import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
+import com.bumptech.glide.Glide
import java.util.*
/**
@@ -16,39 +39,74 @@ import java.util.*
*/
class GenreAdapter(
- private val activity: Activity, dataSet: ArrayList, private val mItemLayoutRes: Int
+ private val activity: FragmentActivity,
+ var dataSet: List,
+ private val listener: IGenreClickListener
) : RecyclerView.Adapter() {
- var dataSet = ArrayList()
- private set
init {
- this.dataSet = dataSet
+ this.setHasStableIds(true)
+ }
+
+ override fun getItemId(position: Int): Long {
+ return dataSet[position].id
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
+ return ViewHolder(ItemGenreBinding.inflate(LayoutInflater.from(activity), parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val genre = dataSet[position]
- holder.title?.text = genre.name
- holder.text?.text = String.format(Locale.getDefault(), "%d %s", genre.songCount, if (genre.songCount > 1) activity.getString(R.string.songs) else activity.getString(R.string.song))
+ 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)
}
override fun getItemCount(): Int {
return dataSet.size
}
- fun swapDataSet(list: ArrayList) {
+ @SuppressLint("NotifyDataSetChanged")
+ fun swapDataSet(list: List) {
dataSet = list
notifyDataSetChanged()
}
- inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
+ inner class ViewHolder(val binding: ItemGenreBinding) : RecyclerView.ViewHolder(binding.root),
+ View.OnClickListener {
override fun onClick(v: View?) {
- super.onClick(v)
- val genre = dataSet[adapterPosition]
- NavigationUtil.goToGenre(activity, genre)
+ listener.onClickGenre(dataSet[layoutPosition], itemView)
+ }
+
+ init {
+ itemView.setOnClickListener(this)
}
}
}
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 dc38bf15f..e3f809b5f 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,70 +1,124 @@
+/*
+ * 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.util.DisplayMetrics
+import android.annotation.SuppressLint
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.R
-import code.name.monkey.retromusic.adapter.album.AlbumFullWidthAdapter
+import code.name.monkey.retromusic.*
+import code.name.monkey.retromusic.adapter.album.AlbumAdapter
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
import code.name.monkey.retromusic.adapter.song.SongAdapter
-import code.name.monkey.retromusic.extensions.show
-import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
+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.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Home
-import code.name.monkey.retromusic.model.Playlist
+import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil
-class HomeAdapter(
- private val activity: AppCompatActivity, private val displayMetrics: DisplayMetrics
-) : RecyclerView.Adapter() {
+class HomeAdapter(private val activity: AppCompatActivity) :
+ RecyclerView.Adapter(), IArtistClickListener, IAlbumClickListener {
- private var list = ArrayList()
+ private var list = listOf()
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)
- PLAYLISTS -> PlaylistViewHolder(layout)
+ FAVOURITES -> PlaylistViewHolder(layout)
+ TOP_ALBUMS, RECENT_ALBUMS -> AlbumViewHolder(layout)
else -> {
- AlbumViewHolder(LayoutInflater.from(activity).inflate(R.layout.metal_section_recycler_view, parent, false))
+ ArtistViewHolder(layout)
}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- println("ViewType ${getItemViewType(position)}")
+ val home = list[position]
when (getItemViewType(position)) {
RECENT_ALBUMS -> {
val viewHolder = holder as AlbumViewHolder
- viewHolder.bindView(list[position].arrayList.toAlbums(), R.string.recent_albums)
+ viewHolder.bindView(home)
+ viewHolder.clickableArea.setOnClickListener {
+ it.findFragment().setSharedAxisXTransitions()
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.detailListFragment,
+ bundleOf("type" to RECENT_ALBUMS)
+ )
+ }
}
TOP_ALBUMS -> {
val viewHolder = holder as AlbumViewHolder
- viewHolder.bindView(list[position].arrayList.toAlbums(), R.string.top_albums)
+ viewHolder.bindView(home)
+ viewHolder.clickableArea.setOnClickListener {
+ it.findFragment().setSharedAxisXTransitions()
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.detailListFragment,
+ bundleOf("type" to TOP_ALBUMS)
+ )
+ }
}
RECENT_ARTISTS -> {
val viewHolder = holder as ArtistViewHolder
- viewHolder.bindView(list[position].arrayList.toArtists(), R.string.recent_artists)
+ viewHolder.bindView(home)
+ viewHolder.clickableArea.setOnClickListener {
+ it.findFragment().setSharedAxisXTransitions()
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.detailListFragment,
+ bundleOf("type" to RECENT_ARTISTS)
+ )
+ }
}
TOP_ARTISTS -> {
val viewHolder = holder as ArtistViewHolder
- viewHolder.bindView(list[position].arrayList.toArtists(), R.string.top_artists)
+ viewHolder.bindView(home)
+ viewHolder.clickableArea.setOnClickListener {
+ it.findFragment().setSharedAxisXTransitions()
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.detailListFragment,
+ bundleOf("type" to TOP_ARTISTS)
+ )
+ }
}
- PLAYLISTS -> {
+ FAVOURITES -> {
val viewHolder = holder as PlaylistViewHolder
- viewHolder.bindView(list[position].arrayList.toPlaylist(), R.string.favorites)
+ viewHolder.bindView(home)
+ viewHolder.clickableArea.setOnClickListener {
+ it.findFragment().setSharedAxisXTransitions()
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.detailListFragment,
+ bundleOf("type" to FAVOURITES)
+ )
+ }
}
}
}
@@ -73,108 +127,87 @@ class HomeAdapter(
return list.size
}
- fun swapData(sections: ArrayList) {
+ @SuppressLint("NotifyDataSetChanged")
+ fun swapData(sections: List) {
list = sections
notifyDataSetChanged()
}
- 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
-
- }
-
+ @Suppress("UNCHECKED_CAST")
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
- fun bindView(list: ArrayList, titleRes: Int) {
- if (list.isNotEmpty()) {
- recyclerView.apply {
- show()
- adapter = AlbumFullWidthAdapter(activity, list, displayMetrics)
- }
- title.text = activity.getString(titleRes)
+ fun bindView(home: Home) {
+ title.setText(home.titleRes)
+ recyclerView.apply {
+ adapter = albumAdapter(home.arrayList as List)
+ layoutManager = gridLayoutManager()
}
}
}
- 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 ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
+ fun bindView(home: Home) {
+ title.setText(home.titleRes)
+ recyclerView.apply {
+ layoutManager = linearLayoutManager()
+ adapter = artistsAdapter(home.arrayList as List)
}
}
}
+ @Suppress("UNCHECKED_CAST")
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
- 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)
- }
+ 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
}
}
}
- open inner class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ open 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 dc5c066d4..22a60bd95 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,16 +1,38 @@
+/*
+ * 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.app.ActivityOptions
+import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.appcompat.app.AppCompatActivity
+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.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore
-import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
-import code.name.monkey.retromusic.glide.ArtistGlideRequest
-import code.name.monkey.retromusic.glide.SongGlideRequest
+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.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.model.Album
@@ -18,80 +40,137 @@ 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 android.util.Pair as UtilPair
+import java.util.*
class SearchAdapter(
- private val activity: AppCompatActivity, private var dataSet: List?
+ private val activity: FragmentActivity,
+ private var dataSet: List
) : RecyclerView.Adapter() {
- fun swapDataSet(dataSet: MutableList) {
+ @SuppressLint("NotifyDataSetChanged")
+ fun swapDataSet(dataSet: List) {
this.dataSet = dataSet
notifyDataSetChanged()
}
override fun getItemViewType(position: Int): Int {
- 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
+ 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
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- 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)
+ 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
+ )
+ }
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (getItemViewType(position)) {
ALBUM -> {
- val album = dataSet?.get(position) as Album
+ holder.imageTextContainer?.isVisible = true
+ val album = dataSet[position] as Album
holder.title?.text = album.title
holder.text?.text = album.artistName
- SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
- .checkIgnoreMediaStore(activity).build().into(holder.image)
+ Glide.with(activity).asDrawable().albumCoverOptions(album.safeGetFirstSong())
+ .load(RetroGlideExtension.getSongModel(album.safeGetFirstSong()))
+ .into(holder.image!!)
}
+
ARTIST -> {
- val artist = dataSet?.get(position) as Artist
+ holder.imageTextContainer?.isVisible = true
+ val artist = dataSet[position] as Artist
holder.title?.text = artist.name
holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
- ArtistGlideRequest.Builder.from(Glide.with(activity), artist).build()
- .into(holder.image)
+ Glide.with(activity).asDrawable().artistImageOptions(artist).load(
+ RetroGlideExtension.getArtistModel(artist)
+ ).into(holder.image!!)
}
+
SONG -> {
- val song = dataSet?.get(position) as Song
+ holder.imageTextContainer?.isVisible = true
+ val song = dataSet[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?.get(position) as Genre
+ val genre = dataSet[position] as Genre
holder.title?.text = genre.name
+ holder.text?.text = String.format(
+ Locale.getDefault(),
+ "%d %s",
+ genre.songCount,
+ if (genre.songCount > 1) activity.getString(R.string.songs) else activity.getString(
+ R.string.song
+ )
+ )
}
+
+ PLAYLIST -> {
+ val playlist = dataSet[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?.get(position).toString()
+ holder.title?.text = dataSet[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) {
- menu?.visibility = View.VISIBLE
+ imageTextContainer?.isGone = true
+ menu?.isVisible = true
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
override val song: Song
- get() = dataSet!![adapterPosition] as Song
+ get() = dataSet[layoutPosition] as Song
})
} else {
- menu?.visibility = View.GONE
+ menu?.isVisible = false
}
when (itemViewType) {
@@ -99,29 +178,52 @@ class SearchAdapter(
ARTIST -> setImageTransitionName(activity.getString(R.string.transition_artist_image))
else -> {
val container = itemView.findViewById(R.id.imageContainer)
- container?.visibility = View.GONE
+ container?.isVisible = false
}
}
}
override fun onClick(v: View?) {
- val item = dataSet!![adapterPosition]
+ val item = dataSet[layoutPosition]
when (itemViewType) {
ALBUM -> {
- val options = ActivityOptions.makeSceneTransitionAnimation(activity, UtilPair.create(image, activity.getString(R.string.transition_album_art)))
- NavigationUtil.goToAlbumOptions(activity, (item as Album).id, options)
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.albumDetailsFragment,
+ bundleOf(EXTRA_ALBUM_ID to (item as Album).id)
+ )
}
+
ARTIST -> {
- val options = ActivityOptions.makeSceneTransitionAnimation(activity, UtilPair.create(image, activity.getString(R.string.transition_artist_image)))
- NavigationUtil.goToArtistOptions(activity, (item as Artist).id, options)
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.artistDetailsFragment,
+ bundleOf(EXTRA_ARTIST_ID to (item as Artist).id)
+ )
}
+
+ ALBUM_ARTIST -> {
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.albumArtistDetailsFragment,
+ bundleOf(EXTRA_ARTIST_NAME to (item as Artist).name)
+ )
+ }
+
GENRE -> {
- NavigationUtil.goToGenre(activity, item as Genre)
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.genreDetailsFragment,
+ bundleOf(EXTRA_GENRE to (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 -> {
- val playList = ArrayList()
- playList.add(item as Song)
- MusicPlayerRemote.openQueue(playList, 0, true)
+ MusicPlayerRemote.playNext(item as Song)
+ MusicPlayerRemote.playNextSong()
}
}
}
@@ -133,5 +235,7 @@ 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 60d2d8551..4005c6e6c 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,3 +1,17 @@
+/*
+ * Copyright (c) 2020 Hemanth Savarla.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
package code.name.monkey.retromusic.adapter
import android.graphics.PorterDuff
@@ -6,43 +20,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.adapter.base.MediaEntryViewHolder
+import code.name.monkey.retromusic.extensions.getTintedDrawable
+import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.audiocover.AudioFileCover
-import code.name.monkey.retromusic.interfaces.CabHolder
-import code.name.monkey.retromusic.util.RetroUtil
+import code.name.monkey.retromusic.interfaces.ICallbacks
+import code.name.monkey.retromusic.util.MusicUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.MediaStoreSignature
-import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
+import me.zhanghai.android.fastscroll.PopupTextProvider
import java.io.File
import java.text.DecimalFormat
-import java.util.*
import kotlin.math.log10
import kotlin.math.pow
class SongFileAdapter(
- private val activity: AppCompatActivity,
- private var dataSet: List?,
- private val itemLayoutRes: Int,
- private val callbacks: Callbacks?,
- cabHolder: CabHolder?
+ override val activity: AppCompatActivity,
+ private var dataSet: List,
+ private val itemLayoutRes: Int,
+ private val iCallbacks: ICallbacks?
) : AbsMultiSelectAdapter(
- activity, cabHolder, R.menu.menu_media_selection
-), FastScrollRecyclerView.SectionedAdapter {
+ activity, R.menu.menu_media_selection
+), PopupTextProvider {
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) {
@@ -55,14 +69,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?.visibility = View.GONE
+ holder.text?.isVisible = false
}
}
@@ -80,62 +94,64 @@ class SongFileAdapter(
}
private fun loadFileImage(file: File, holder: ViewHolder) {
- val iconColor = ATHUtil.resolveColor(activity, R.attr.colorControlNormal)
+ val iconColor = ATHUtil.resolveColor(activity, androidx.appcompat.R.attr.colorControlNormal)
if (file.isDirectory) {
holder.image?.let {
it.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN)
- it.setImageResource(R.drawable.ic_folder_white_24dp)
+ it.setImageResource(R.drawable.ic_folder)
}
- holder.imageTextContainer?.setCardBackgroundColor(ATHUtil.resolveColor(activity, R.attr.colorSurface))
-
- } else {
- val error = RetroUtil.getTintedVectorDrawable(
- activity, R.drawable.ic_file_music_white_24dp, iconColor
+ holder.imageTextContainer?.setCardBackgroundColor(
+ ATHUtil.resolveColor(
+ activity,
+ com.google.android.material.R.attr.colorSurface
+ )
)
- 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)
+ } 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!!)
}
}
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(`object`: File): String {
- return getFileTitle(`object`)
+ override fun getName(model: File): String {
+ return getFileTitle(model)
}
- override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList) {
- if (callbacks == null) return
- callbacks.onMultipleItemAction(menuItem, selection)
+ override fun onMultipleItemAction(menuItem: MenuItem, selection: List) {
+ if (iCallbacks == null) return
+ iCallbacks.onMultipleItemAction(menuItem, selection as ArrayList)
}
- override fun getSectionName(position: Int): String {
- return dataSet!![position].name[0].toString().toUpperCase()
+ override fun getPopupText(position: Int): String {
+ return if (position >= dataSet.lastIndex) "" else getSectionName(position)
}
- interface Callbacks {
- fun onFileSelected(file: File)
-
- fun onFileMenuClicked(file: File, view: View)
-
- fun onMultipleItemAction(item: MenuItem, files: ArrayList)
+ private fun getSectionName(position: Int): String {
+ return MusicUtil.getSectionName(dataSet[position].name)
}
- inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
+ inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) {
init {
- if (menu != null && callbacks != null) {
+ if (menu != null && iCallbacks != null) {
menu?.setOnClickListener { v ->
- val position = adapterPosition
+ val position = layoutPosition
if (isPositionInRange(position)) {
- callbacks.onFileMenuClicked(dataSet!![position], v)
+ iCallbacks.onFileMenuClicked(dataSet[position], v)
}
}
}
@@ -145,23 +161,23 @@ class SongFileAdapter(
}
override fun onClick(v: View?) {
- val position = adapterPosition
+ val position = layoutPosition
if (isPositionInRange(position)) {
if (isInQuickSelectMode) {
toggleChecked(position)
} else {
- callbacks?.onFileSelected(dataSet!![position])
+ iCallbacks?.onFileSelected(dataSet[position])
}
}
}
override fun onLongClick(v: View?): Boolean {
- val position = adapterPosition
+ val position = layoutPosition
return isPositionInRange(position) && toggleChecked(position)
}
private fun isPositionInRange(position: Int): Boolean {
- return position >= 0 && position < dataSet!!.size
+ return position >= 0 && position < dataSet.size
}
}
@@ -177,4 +193,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
new file mode 100644
index 000000000..98c2c632f
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/StorageAdapter.kt
@@ -0,0 +1,55 @@
+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
index 3c064e4c9..160af7e47 100644
--- 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
@@ -1,65 +1,59 @@
+/*
+ * 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.app.ActivityOptions
import android.content.res.ColorStateList
-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 code.name.monkey.appthemehelper.util.ColorUtil
-import code.name.monkey.appthemehelper.util.MaterialValueHelper
+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.glide.SongGlideRequest
-import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
-import code.name.monkey.retromusic.interfaces.CabHolder
+import code.name.monkey.retromusic.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.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
+import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
-import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
+import me.zhanghai.android.fastscroll.PopupTextProvider
open class AlbumAdapter(
- protected val activity: AppCompatActivity,
- dataSet: ArrayList,
- protected var itemLayoutRes: Int,
- usePalette: Boolean,
- cabHolder: CabHolder?
+ override val activity: FragmentActivity,
+ var dataSet: List,
+ var itemLayoutRes: Int,
+ val listener: IAlbumClickListener?
) : AbsMultiSelectAdapter(
- activity,
- cabHolder,
- R.menu.menu_media_selection
-), FastScrollRecyclerView.SectionedAdapter {
- var dataSet: ArrayList
- protected set
-
- protected var usePalette = false
+ activity,
+ R.menu.menu_media_selection
+), PopupTextProvider {
init {
- this.dataSet = dataSet
- this.usePalette = usePalette
this.setHasStableIds(true)
}
- fun useItemLayout(itemLayoutRes: Int) {
- this.itemLayoutRes = itemLayoutRes
- notifyDataSetChanged()
- }
-
- fun usePalette(usePalette: Boolean) {
- this.usePalette = usePalette
- notifyDataSetChanged()
- }
-
- fun swapDataSet(dataSet: ArrayList) {
+ fun swapDataSet(dataSet: List) {
this.dataSet = dataSet
notifyDataSetChanged()
}
@@ -73,12 +67,18 @@ open class AlbumAdapter(
return ViewHolder(view)
}
- private fun getAlbumTitle(album: Album): String? {
+ private fun getAlbumTitle(album: Album): String {
return album.title
}
protected open fun getAlbumText(album: Album): String? {
- return album.artistName
+ return album.albumArtist.let {
+ if (it.isNullOrEmpty()) {
+ album.artistName
+ } else {
+ it
+ }
+ }
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@@ -87,36 +87,41 @@ open class AlbumAdapter(
holder.itemView.isActivated = isChecked
holder.title?.text = getAlbumTitle(album)
holder.text?.text = getAlbumText(album)
- holder.playSongs?.setOnClickListener { album.songs?.let { songs -> MusicPlayerRemote.openQueue(songs, 0, true) } }
+ // 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: Int, holder: ViewHolder) {
+ protected open fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) {
if (holder.paletteColorContainer != null) {
- holder.title?.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color)))
- holder.text?.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color)))
- holder.paletteColorContainer?.setBackgroundColor(color)
+ holder.title?.setTextColor(color.primaryTextColor)
+ holder.text?.setTextColor(color.secondaryTextColor)
+ holder.paletteColorContainer?.setBackgroundColor(color.backgroundColor)
}
- holder.mask?.backgroundTintList = ColorStateList.valueOf(color)
+ 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
}
-
- SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
- .checkIgnoreMediaStore(activity).generatePalette(activity).build()
- .into(object : RetroMusicColoredTarget(holder.image!!) {
- override fun onLoadCleared(placeholder: Drawable?) {
- super.onLoadCleared(placeholder)
- setColors(defaultFooterColor, holder)
- }
-
- override fun onColorReady(color: Int) {
- setColors(color, holder)
- }
- })
+ 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 {
@@ -124,70 +129,69 @@ open class AlbumAdapter(
}
override fun getItemId(position: Int): Long {
- return dataSet[position].id.toLong()
+ return dataSet[position].id
}
override fun getIdentifier(position: Int): Album? {
return dataSet[position]
}
- override fun getName(album: Album): String {
- return album.title!!
+ override fun getName(model: Album): String {
+ return model.title
}
override fun onMultipleItemAction(
- menuItem: MenuItem, selection: ArrayList
+ menuItem: MenuItem,
+ selection: List
) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
}
- private fun getSongList(albums: List): ArrayList {
+ private fun getSongList(albums: List): List {
val songs = ArrayList()
for (album in albums) {
- songs.addAll(album.songs!!)
+ songs.addAll(album.songs)
}
return songs
}
- override fun getSectionName(position: Int): String {
+ override fun getPopupText(position: Int): String {
+ return getSectionName(position)
+ }
+
+ private fun getSectionName(position: Int): String {
var sectionName: String? = null
- when (PreferenceUtil.getInstance(activity).albumSortOrder) {
- SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName = dataSet[position].title
- SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].artistName
+ 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
+ dataSet[position].year
)
}
-
return MusicUtil.getSectionName(sectionName)
}
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init {
- setImageTransitionName(activity.getString(R.string.transition_album_art))
- menu?.visibility = View.GONE
+ menu?.isVisible = false
}
override fun onClick(v: View?) {
super.onClick(v)
if (isInQuickSelectMode) {
- toggleChecked(adapterPosition)
+ toggleChecked(layoutPosition)
} else {
- val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
- activity, image, activity.getString(
- R.string.transition_album_art
- )
- )
- NavigationUtil.goToAlbumOptions(
- activity, dataSet[adapterPosition].id, activityOptions
- )
+ image?.let {
+ listener?.onAlbumClick(dataSet[layoutPosition].id, imageContainer ?: it)
+ }
}
}
override fun onLongClick(v: View?): Boolean {
- toggleChecked(adapterPosition)
- return super.onLongClick(v)
+ return toggleChecked(layoutPosition)
}
}
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
index 3560ba701..5a0a7d3cd 100644
--- 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
@@ -1,165 +1,220 @@
+/*
+ * 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.*
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
import android.widget.ImageView
-import androidx.fragment.app.*
+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.glide.*
+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.*
+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 java.util.*
+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(
- fm: FragmentManager,
- private val dataSet: ArrayList
-) : CustomFragmentStatePagerAdapter(fm) {
+ fragmentManager: FragmentManager,
+ private val dataSet: List
+) : CustomFragmentStatePagerAdapter(fragmentManager) {
- private var currentColorReceiver: AlbumCoverFragment.ColorReceiver? = null
- private var currentColorReceiverPosition = -1
+ private var currentColorReceiver: AlbumCoverFragment.ColorReceiver? = null
+ private var currentColorReceiverPosition = -1
- override fun getItem(position: Int): Fragment {
- return AlbumCoverFragment.newInstance(dataSet[position])
- }
+ override fun getItem(position: Int): Fragment {
+ return AlbumCoverFragment.newInstance(dataSet[position])
+ }
- override fun getCount(): Int {
- return dataSet.size
- }
+ 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
- }
+ 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) {
+ /**
+ * 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
- }
- }
+ 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() {
+ class AlbumCoverFragment : Fragment() {
- lateinit var albumCover: ImageView
- private var isColorReady: Boolean = false
- private var color: Int = 0
- private lateinit var song: Song
- private var colorReceiver: ColorReceiver? = null
- private var request: Int = 0
+ 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
- private val layout: Int
- get() {
- return when (PreferenceUtil.getInstance(activity).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.MATERIAL -> R.layout.fragment_album_material_cover
- AlbumCoverStyle.FULL -> R.layout.fragment_album_full_cover
- AlbumCoverStyle.FULL_CARD -> R.layout.fragment_album_full_card_cover
- else -> R.layout.fragment_album_cover
- }
- }
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (arguments != null) {
+ song = BundleCompat.getParcelable(requireArguments(), SONG_ARG, Song::class.java)!!
+ }
+ }
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- if (arguments != null) {
- song = arguments!!.getParcelable(SONG_ARG)!!
- }
- }
+ 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
+ }
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- val finalLayout = when {
- PreferenceUtil.getInstance(activity).carouselEffect() -> R.layout.fragment_album_carousel_cover
- else -> layout
- }
- val view = inflater.inflate(finalLayout, container, false)
- albumCover = view.findViewById(R.id.player_image)
- albumCover.setOnClickListener {
+ 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()
+ }
+ }
+ }
+ }
- NavigationUtil.goToLyrics(requireActivity())
- }
- return view
- }
+ 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()
- }
+ 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
- }
+ override fun onDestroyView() {
+ super.onDestroyView()
+ colorReceiver = null
+ }
- private fun loadAlbumCover() {
- SongGlideRequest.Builder.from(Glide.with(requireContext()), song)
- .checkIgnoreMediaStore(activity).generatePalette(activity).build()
- .into(object : RetroMusicColoredTarget(albumCover) {
- override fun onColorReady(color: Int) {
- setColor(color)
- }
- })
- }
+ 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: Int) {
- this.color = color
- isColorReady = true
- if (colorReceiver != null) {
- colorReceiver!!.onColorReady(color, request)
- colorReceiver = null
- }
- }
+ 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
- }
- }
+ 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: Int, request: Int)
- }
+ interface ColorReceiver {
+ fun onColorReady(color: MediaNotificationProcessor, request: Int)
+ }
- companion object {
+ companion object {
- private const val SONG_ARG = "song"
+ private const val SONG_ARG = "song"
- fun newInstance(song: Song): AlbumCoverFragment {
- val frag = AlbumCoverFragment()
- val args = Bundle()
- args.putParcelable(SONG_ARG, song)
- frag.arguments = args
- return frag
- }
- }
- }
+ 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
- }
+ companion object {
+ val TAG: String = AlbumCoverPagerAdapter::class.java.simpleName
+ }
}
-
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumFullWidthAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumFullWidthAdapter.kt
deleted file mode 100644
index a3cc654f1..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumFullWidthAdapter.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2017. Alexander Bilchuk
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package code.name.monkey.retromusic.adapter.album
-
-import android.app.*
-import android.util.DisplayMetrics
-import android.view.*
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.glide.*
-import code.name.monkey.retromusic.helper.MusicPlayerRemote
-import code.name.monkey.retromusic.model.Album
-import code.name.monkey.retromusic.util.NavigationUtil
-import code.name.monkey.retromusic.views.MetalRecyclerViewPager
-import com.bumptech.glide.Glide
-
-class AlbumFullWidthAdapter(
- private val activity: Activity,
- private val dataSet: ArrayList,
- metrics: DisplayMetrics
-) : MetalRecyclerViewPager.MetalAdapter(metrics) {
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FullMetalViewHolder {
- return FullMetalViewHolder(
- LayoutInflater.from(parent.context).inflate(
- R.layout.pager_item,
- parent,
- false
- )
- )
- }
-
- override fun onBindViewHolder(holder: FullMetalViewHolder, position: Int) {
- // don't forget about calling supper.onBindViewHolder!
- super.onBindViewHolder(holder, position)
- val album = dataSet[position]
- holder.title?.text = getAlbumTitle(album)
- holder.text?.text = getAlbumText(album)
- holder.playSongs?.setOnClickListener {
- album.songs?.let { songs ->
- MusicPlayerRemote.openQueue(
- songs,
- 0,
- true
- )
- }
- }
- loadAlbumCover(album, holder)
- }
-
- private fun getAlbumTitle(album: Album): String? {
- return album.title
- }
-
- private fun getAlbumText(album: Album): String? {
- return album.artistName
- }
-
- private fun loadAlbumCover(album: Album, holder: FullMetalViewHolder) {
- if (holder.image == null) {
- return
- }
- SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
- .checkIgnoreMediaStore(activity).generatePalette(activity).build()
- .into(object : RetroMusicColoredTarget(holder.image!!) {
- override fun onColorReady(color: Int) {
-
- }
- })
- }
-
- override fun getItemCount(): Int {
- return dataSet.size
- }
-
- inner class FullMetalViewHolder(itemView: View) : MetalRecyclerViewPager.MetalViewHolder(
- itemView
- ) {
-
- override fun onClick(v: View?) {
- val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
- activity,
- image,
- activity.getString(R.string.transition_album_art)
- )
- NavigationUtil.goToAlbumOptions(activity, dataSet[adapterPosition].id, activityOptions)
- }
- }
-}
\ No newline at end of file
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
index 1a85231f9..7a9f7fa6e 100644
--- 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
@@ -1,71 +1,78 @@
+/*
+ * 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.graphics.drawable.Drawable
import android.view.View
import android.view.ViewGroup
-import androidx.appcompat.app.AppCompatActivity
-import code.name.monkey.appthemehelper.util.ColorUtil
-import code.name.monkey.appthemehelper.util.MaterialValueHelper
+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.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.HorizontalAdapterHelper
-import code.name.monkey.retromusic.interfaces.CabHolder
+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
-import java.util.*
class HorizontalAlbumAdapter(
- activity: AppCompatActivity,
- dataSet: ArrayList,
- usePalette: Boolean,
- cabHolder: CabHolder?
+ activity: FragmentActivity,
+ dataSet: List,
+ albumClickListener: IAlbumClickListener
) : AlbumAdapter(
- activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, usePalette, cabHolder
+ 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 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: Int, holder: ViewHolder) {
- holder.title?.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color)))
- holder.text?.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color)))
- }
+ 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
+ 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)
+ }
+ })
+ }
- SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
- .checkIgnoreMediaStore(activity).generatePalette(activity).build()
- .into(object : RetroMusicColoredTarget(holder.image!!) {
- override fun onLoadCleared(placeholder: Drawable?) {
- super.onLoadCleared(placeholder)
- setColors(albumArtistFooterColor, holder)
- }
+ override fun getAlbumText(album: Album): String {
+ return MusicUtil.getYearString(album.year)
+ }
- override fun onColorReady(color: Int) {
- if (usePalette) setColors(color, holder)
- else setColors(albumArtistFooterColor, holder)
- }
- })
- }
+ override fun getItemViewType(position: Int): Int {
+ return HorizontalAdapterHelper.getItemViewType(position, itemCount)
+ }
- override fun getAlbumText(album: Album): String? {
- return MusicUtil.getYearString(album.year)
- }
+ override fun getItemCount(): Int {
+ return dataSet.size
+ }
- 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
- }
+ 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 fd4dcfa98..e1ea2ca4c 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,152 +1,186 @@
+/*
+ * 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.app.ActivityOptions
+import android.annotation.SuppressLint
import android.content.res.ColorStateList
-import android.graphics.drawable.Drawable
-import android.view.*
-import androidx.appcompat.app.AppCompatActivity
-import code.name.monkey.appthemehelper.util.*
+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 code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.adapter.base.*
-import code.name.monkey.retromusic.glide.*
+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.helper.menu.SongsMenuHelper
-import code.name.monkey.retromusic.interfaces.CabHolder
-import code.name.monkey.retromusic.model.*
-import code.name.monkey.retromusic.util.*
+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 com.bumptech.glide.Glide
-import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
-import java.util.*
+import me.zhanghai.android.fastscroll.PopupTextProvider
class ArtistAdapter(
- val activity: AppCompatActivity,
- var dataSet: ArrayList,
- var itemLayoutRes: Int,
- var usePalette: Boolean,
- cabHolder: CabHolder?
-) : AbsMultiSelectAdapter(
- activity, cabHolder, R.menu.menu_media_selection
-), FastScrollRecyclerView.SectionedAdapter {
+ 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 {
- fun swapDataSet(dataSet: ArrayList) {
- this.dataSet = dataSet
- notifyDataSetChanged()
- }
+ var albumArtistsOnly = false
- fun usePalette(usePalette: Boolean) {
- this.usePalette = usePalette
- notifyDataSetChanged()
- }
+ init {
+ this.setHasStableIds(true)
+ }
- override fun getItemId(position: Int): Long {
- return dataSet[position].id.toLong()
- }
+ @SuppressLint("NotifyDataSetChanged")
+ fun swapDataSet(dataSet: List) {
+ this.dataSet = dataSet
+ notifyDataSetChanged()
+ albumArtistsOnly = PreferenceUtil.albumArtistsOnly
+ }
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
- return createViewHolder(view)
- }
+ override fun getItemId(position: Int): Long {
+ return dataSet[position].id
+ }
- private fun createViewHolder(view: View): ViewHolder {
- return ViewHolder(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)
+ }
- 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)
- }
+ private fun createViewHolder(view: View): ViewHolder {
+ return ViewHolder(view)
+ }
- fun setColors(color: Int, holder: ViewHolder) {
- if (holder.paletteColorContainer != null) {
- holder.paletteColorContainer?.setBackgroundColor(color)
- holder.title?.setTextColor(
- MaterialValueHelper.getPrimaryTextColor(
- activity, ColorUtil.isColorLight(
- color
- )
- )
- )
- }
+ 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)
+ }
- holder.mask?.backgroundTintList = ColorStateList.valueOf(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)
+ }
- 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)
- }
+ 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)
+ }
+ })
+ }
- override fun onColorReady(color: Int) {
- setColors(color, holder)
- }
- })
- }
+ override fun getItemCount(): Int {
+ return dataSet.size
+ }
- override fun getItemCount(): Int {
- return dataSet.size
- }
+ override fun getIdentifier(position: Int): Artist {
+ return dataSet[position]
+ }
- override fun getIdentifier(position: Int): Artist? {
- return dataSet[position]
- }
+ override fun getName(model: Artist): String {
+ return model.name
+ }
- override fun getName(artist: Artist): String {
- return artist.name
- }
+ override fun onMultipleItemAction(
+ menuItem: MenuItem,
+ selection: List
+ ) {
+ SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
+ }
- override fun onMultipleItemAction(
- menuItem: MenuItem, selection: ArrayList
- ) {
- SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
- }
+ private fun getSongList(artists: List): List {
+ val songs = ArrayList()
+ for (artist in artists) {
+ songs.addAll(artist.songs) // maybe async in future?
+ }
+ return songs
+ }
- private fun getSongList(artists: List): ArrayList {
- val songs = ArrayList()
- for (artist in artists) {
- songs.addAll(artist.songs) // maybe async in future?
- }
- return songs
- }
+ override fun getPopupText(position: Int): String {
+ return getSectionName(position)
+ }
- override fun getSectionName(position: Int): String {
- return MusicUtil.getSectionName(dataSet[position].name)
- }
+ private fun getSectionName(position: Int): String {
+ return MusicUtil.getSectionName(dataSet[position].name)
+ }
- inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
+ inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) {
- init {
- setImageTransitionName(activity.getString(R.string.transition_artist_image))
- menu?.visibility = View.GONE
- }
+ init {
+ menu?.isVisible = false
+ }
- 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 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 onLongClick(v: View?): Boolean {
- toggleChecked(adapterPosition)
- return super.onLongClick(v)
- }
- }
+ override fun onLongClick(v: View?): Boolean {
+ return toggleChecked(layoutPosition)
+ }
+ }
}
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
new file mode 100644
index 000000000..adfcecf1b
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/backup/BackupAdapter.kt
@@ -0,0 +1,65 @@
+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
deleted file mode 100644
index 36bbe6bdf..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.java
+++ /dev/null
@@ -1,123 +0,0 @@
-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
new file mode 100644
index 000000000..bb7b8491c
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.kt
@@ -0,0 +1,131 @@
+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 f1652ea54..d68186c0f 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,113 +14,115 @@
package code.name.monkey.retromusic.adapter.base;
+import android.graphics.Color;
import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageButton;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.RecyclerView;
+import androidx.appcompat.widget.AppCompatImageView;
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 {
- @Nullable
- public TextView title;
-
- @Nullable
- public TextView text;
-
- @Nullable
- public TextView time;
-
- @Nullable
- public TextView imageText;
-
- @Nullable
- public ViewGroup imageContainer;
-
- @Nullable
- public MaterialCardView imageContainerCard;
-
- @Nullable
- public View menu;
+public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHolder
+ implements View.OnLongClickListener, View.OnClickListener {
@Nullable
public View dragView;
@Nullable
- public View paletteColorContainer;
+ public View dummyContainer;
@Nullable
- public RecyclerView recyclerView;
+ public ImageView image;
@Nullable
- public ImageButton playSongs;
+ public MaterialCardView imageContainerCard;
@Nullable
- public View mask;
+ public FrameLayout imageContainer;
+
+ @Nullable
+ public TextView imageText;
@Nullable
public MaterialCardView imageTextContainer;
@Nullable
- public ImageView image;
+ public View mask;
+
@Nullable
- public View dummyContainer;
+ public AppCompatImageView menu;
+
+ @Nullable
+ public View paletteColorContainer;
+
+ @Nullable
+ public TextView text;
+
+ @Nullable
+ public TextView text2;
+
+ @Nullable
+ public TextView time;
+
+ @Nullable
+ public TextView title;
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(ATHUtil.INSTANCE.resolveColor(itemView.getContext(), R.attr.colorSurface));
+ imageContainerCard.setCardBackgroundColor(Color.TRANSPARENT);
}
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
+ @Nullable
@Override
public View getSwipeableContainerView() {
return null;
}
+ @Override
+ public void onClick(View v) {
+ }
+
@Override
public boolean onLongClick(View v) {
return false;
}
- @Override
- public void onClick(View v) {
-
- }
-
public void setImageTransitionName(@NonNull String transitionName) {
- if (image != null) {
- image.setTransitionName(transitionName);
- }
+ itemView.setTransitionName(transitionName);
+ /* if (imageContainerCard != null) {
+ imageContainerCard.setTransitionName(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
new file mode 100644
index 000000000..19d681ecf
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/LegacyPlaylistAdapter.kt
@@ -0,0 +1,65 @@
+/*
+ * 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 f448f3d68..6e5b0c001 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,57 +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.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 code.name.monkey.appthemehelper.ThemeStore
+import androidx.core.view.isGone
+import androidx.core.view.setPadding
+import androidx.fragment.app.FragmentActivity
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.adapter.base.MediaEntryViewHolder
-import code.name.monkey.retromusic.dialogs.ClearSmartPlaylistDialog
-import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog
+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.helper.menu.PlaylistMenuHelper
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
-import code.name.monkey.retromusic.interfaces.CabHolder
-import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
-import code.name.monkey.retromusic.model.AbsCustomPlaylist
-import code.name.monkey.retromusic.model.Playlist
+import code.name.monkey.retromusic.interfaces.IPlaylistClickListener
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.NavigationUtil
-import java.util.*
+import code.name.monkey.retromusic.util.PreferenceUtil
+import com.bumptech.glide.Glide
+import me.zhanghai.android.fastscroll.PopupTextProvider
class PlaylistAdapter(
- private val activity: AppCompatActivity,
- var dataSet: ArrayList,
- private var itemLayoutRes: Int,
- cabHolder: CabHolder?
-) : AbsMultiSelectAdapter(
- activity,
- cabHolder,
- R.menu.menu_playlists_selection
-) {
-
- var songs = ArrayList()
+ override val activity: FragmentActivity,
+ var dataSet: List,
+ private var itemLayoutRes: Int,
+ private val listener: IPlaylistClickListener
+) : AbsMultiSelectAdapter(
+ activity,
+ R.menu.menu_playlists_selection
+), PopupTextProvider {
init {
setHasStableIds(true)
}
- fun swapDataSet(dataSet: ArrayList) {
+ fun swapDataSet(dataSet: List) {
this.dataSet = dataSet
notifyDataSetChanged()
}
override fun getItemId(position: Int): Long {
- return dataSet[position].id.toLong()
+ return dataSet[position].playlistEntity.playListId
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@@ -59,158 +72,115 @@ class PlaylistAdapter(
return createViewHolder(view)
}
- protected fun createViewHolder(view: View): ViewHolder {
+ private fun createViewHolder(view: View): ViewHolder {
return ViewHolder(view)
}
- protected fun getPlaylistTitle(playlist: Playlist): String {
- return playlist.name
+ private fun getPlaylistTitle(playlist: PlaylistEntity): String {
+ return playlist.playlistName.ifEmpty { "-" }
}
- protected fun getPlaylistText(playlist: Playlist): String {
- return MusicUtil.getPlaylistInfoString(activity, getSongs(playlist))
+ 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)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val playlist = dataSet[position]
holder.itemView.isActivated = isChecked(playlist)
- holder.title?.text = getPlaylistTitle(playlist)
+ holder.title?.text = getPlaylistTitle(playlist.playlistEntity)
holder.text?.text = getPlaylistText(playlist)
- holder.image?.setImageDrawable(getIconRes(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!!)
+ }
}
- 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
- }
+ private fun getIconRes(): Drawable = TintHelper.createTintedDrawable(
+ activity,
+ R.drawable.ic_playlist_play,
+ ATHUtil.resolveColor(activity, android.R.attr.colorControlNormal)
+ )
override fun getItemCount(): Int {
return dataSet.size
}
- override fun getIdentifier(position: Int): Playlist? {
+ override fun getIdentifier(position: Int): PlaylistWithSongs {
return dataSet[position]
}
- override fun getName(playlist: Playlist): String {
- return playlist.name
+ override fun getName(model: PlaylistWithSongs): String {
+ return model.playlistEntity.playlistName
}
- override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList) {
+ override fun onMultipleItemAction(menuItem: MenuItem, selection: List) {
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): ArrayList {
- val songs = ArrayList