(...);
+}
+-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
--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 { *; }
+#Jaudiotagger
+-dontwarn org.jaudiotagger.**
+-dontwarn org.jcodec.**
+-keep class org.jaudiotagger.** { *; }
+-keep class org.jcodec.** { *; }
-#-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.** { *; }
-
--obfuscationdictionary build/obfuscation-dictionary.txt
--classobfuscationdictionary build/class-dictionary.txt
--packageobfuscationdictionary build/package-dictionary.txt
+-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 1ff053167..14fbaaab7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,40 +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">
@@ -45,7 +62,6 @@
-
@@ -105,32 +121,54 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
-
+
-
+
@@ -177,7 +216,7 @@
@@ -190,7 +229,7 @@
@@ -202,7 +241,7 @@
@@ -214,7 +253,7 @@
@@ -226,7 +265,7 @@
@@ -236,13 +275,36 @@
android:name="android.appwidget.provider"
android:resource="@xml/app_widget_card_info" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:foregroundServiceType="mediaPlayback"
+ android:label="@string/app_name">
@@ -256,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 639b75535..000000000
--- a/app/src/main/assets/contributors.json
+++ /dev/null
@@ -1,26 +0,0 @@
-[
- {
- "name": "Hemanth Savarala",
- "summary": "Lead Developer & Designer",
- "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": "GameSpeck",
- "summary": "Telegram group maintainer",
- "link": "https://t.me/GameSpeck",
- "profile_image": "https://imgur.com/B15Kb9a.jpg"
- },
- {
- "name": "Milind Goel",
- "summary": "Github & Telegram maintainer",
- "link": "https://t.me/MilindGoel15",
- "profile_image": "https://i.imgur.com/Bz4De21_d.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 037d52fad..000000000
--- a/app/src/main/assets/index.html
+++ /dev/null
@@ -1,69 +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 c3771c482..b6b1c411a 100644
--- a/app/src/main/assets/retro-changelog.html
+++ b/app/src/main/assets/retro-changelog.html
@@ -1 +1,466 @@
-
v3.5.010
Added grid size and layout change for songs list
Removed menu options (No use of having only settings)
Added settings option to toolbar
Updated internal library
v3.4.970
Added default cover with accent color
Added date modified option to sort songs
Added toggle bluetooth connection to play on device as soon as it connected
Major code refactor for library tabs
Folder option now in available in tabs
Improved drive mode page
Improved fit, full, card themes for status visibility
Fix tablet version of app
Fix Album and Artist details toolbar full width for better accessibility
Updated internal libraries
v3.4.900
Added playlist search
Added Drive mode
Added Album and Artist layout change option in library
Added Show more album and artist information in details
Added Pixel style scroller bar
Added current now playing share
Fix font issues and colors in some places
Improved Full now playing theme
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 991844b5e..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 afabc12b6..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,78 +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 : MultiDexApplication() {
+class App : Application() {
- lateinit var billingProcessor: BillingProcessor
+ private val wallpaperAccentManager = WallpaperAccentManager(this)
override fun onCreate() {
super.onCreate()
instance = this
- musicComponent = initDagger(this)
+ startKoin {
+ androidContext(this@App)
+ modules(appModules)
+ }
// default theme
if (!ThemeStore.isConfigured(this, 3)) {
ThemeStore.editTheme(this)
- .accentColorRes(R.color.md_deep_purple_A200)
+ .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)
}
- private fun initDagger(app: App): MusicComponent =
- DaggerMusicComponent.builder()
- .appModule(AppModule(app))
- .build()
-
override fun onTerminate() {
super.onTerminate()
- billingProcessor.release()
+ wallpaperAccentManager.release()
}
companion object {
@@ -81,15 +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 0b3c6fa9d..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,53 +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 =
+ const val IS_MUSIC =
MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
+ const val DATA = "_data"
+
+ @Suppress("Deprecation")
val baseProjection = arrayOf(
BaseColumns._ID, // 0
MediaStore.Audio.AudioColumns.TITLE, // 1
MediaStore.Audio.AudioColumns.TRACK, // 2
MediaStore.Audio.AudioColumns.YEAR, // 3
MediaStore.Audio.AudioColumns.DURATION, // 4
- MediaStore.Audio.AudioColumns.DATA, // 5
+ 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
+ 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/LanguageContextWrapper.java b/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.java
deleted file mode 100644
index 72ae6aba3..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package code.name.monkey.retromusic;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.os.LocaleList;
-
-import java.util.Locale;
-
-import code.name.monkey.appthemehelper.util.VersionUtils;
-
-public class LanguageContextWrapper extends android.content.ContextWrapper {
-
- public LanguageContextWrapper(Context base) {
- super(base);
- }
-
- public static LanguageContextWrapper wrap(Context context, Locale newLocale) {
- Resources res = context.getResources();
- Configuration configuration = res.getConfiguration();
-
- if (VersionUtils.INSTANCE.hasNougatMR()) {
- configuration.setLocale(newLocale);
-
- LocaleList localeList = new LocaleList(newLocale);
- LocaleList.setDefault(localeList);
- configuration.setLocales(localeList);
-
- context = context.createConfigurationContext(configuration);
-
- } else if (VersionUtils.INSTANCE.hasLollipop()) {
- configuration.setLocale(newLocale);
- context = context.createConfigurationContext(configuration);
-
- } else {
- configuration.locale = newLocale;
- res.updateConfiguration(configuration, res.getDisplayMetrics());
- }
-
- return new LanguageContextWrapper(context);
- }
-}
\ No newline at end of file
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 64b638a6e..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/Result.kt
+++ /dev/null
@@ -1,26 +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 704e92c6f..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/AboutActivity.kt
+++ /dev/null
@@ -1,171 +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.App
-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 contributorsJson: 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 isPro = if (App.isProVersion()) "Pro" else "Free"
- val packageInfo = packageManager.getPackageInfo(packageName, 0)
- "${packageInfo.versionName} $isPro"
- } 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 type = object : TypeToken>() {
-
- }.type
- val contributors = Gson().fromJson>(contributorsJson, 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 7be3cbeb0..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt
+++ /dev/null
@@ -1,396 +0,0 @@
-package code.name.monkey.retromusic.activities
-
-import android.app.ActivityOptions
-import android.content.Intent
-import android.os.Bundle
-import android.transition.Slide
-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.util.ATHUtil
-import code.name.monkey.appthemehelper.util.MaterialUtil
-import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
-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.AlbumGlideRequest
-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.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.rest.model.LastFmAlbum
-import code.name.monkey.retromusic.util.*
-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
-
- 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)
-
- window.enterTransition = slide
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- setDrawUnderStatusBar()
- super.onCreate(savedInstanceState)
- toggleBottomNavigationView(true)
- setStatusbarColorAuto()
- setNavigationbarColorAuto()
- setTaskDescriptionColorAuto()
- setLightNavigationBar(true)
- window.sharedElementsUseOverlay = true
-
- App.musicComponent.inject(this)
- albumDetailsPresenter.attachView(this)
-
- if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
- intent.extras?.getInt(EXTRA_ALBUM_ID)?.let {
- albumDetailsPresenter.loadAlbum(it)
- albumCoverContainer?.transitionName =
- "${getString(R.string.transition_album_art)}_$it"
- }
- } else {
- finish()
- }
-
- windowEnterTransition()
- ActivityCompat.postponeEnterTransition(this)
-
-
- artistImage = findViewById(R.id.artistImage)
-
- setupRecyclerView()
-
- artistImage.setOnClickListener {
- val artistPairs = ActivityOptions.makeSceneTransitionAnimation(
- this,
- UtilPair.create(
- artistImage,
- "${getString(R.string.transition_artist_image)}_${album.artistId}"
- )
- )
- NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs)
- }
- playAction.apply {
- setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
- }
- shuffleAction.apply {
- setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) }
- }
-
- aboutAlbumText.setOnClickListener {
- if (aboutAlbumText.maxLines == 4) {
- aboutAlbumText.maxLines = Integer.MAX_VALUE
- } else {
- aboutAlbumText.maxLines = 4
- }
- }
- }
-
- 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) {
- complete()
- 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(album.songs))
- )
- } else {
- albumText.text = String.format(
- "%s • %s • %s",
- album.artistName,
- MusicUtil.getYearString(album.year),
- MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
- )
- }
- loadAlbumCover()
- simpleSongAdapter.swapDataSet(album.songs)
- albumDetailsPresenter.loadMore(album.artistId)
- albumDetailsPresenter.aboutAlbum(album.artistName!!, album.title!!)
- }
-
- override fun moreAlbums(albums: List) {
- moreTitle.show()
- moreRecyclerView.show()
- moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName)
-
- val albumAdapter = HorizontalAlbumAdapter(this, albums, null)
- moreRecyclerView.layoutManager = GridLayoutManager(
- this,
- 1,
- GridLayoutManager.HORIZONTAL,
- false
- )
- moreRecyclerView.adapter = albumAdapter
- }
-
- override fun aboutAlbum(lastFmAlbum: LastFmAlbum) {
- if (lastFmAlbum.album != null) {
- if (lastFmAlbum.album.wiki != null) {
- aboutAlbumText.show()
- aboutAlbumTitle.show()
- aboutAlbumTitle.text = String.format(getString(R.string.about_album_label), lastFmAlbum.album.name)
- aboutAlbumText.text = lastFmAlbum.album.wiki.content
- }
- if (lastFmAlbum.album.listeners.isNotEmpty()) {
- listeners.show()
- listenersLabel.show()
- scrobbles.show()
- scrobblesLabel.show()
-
- listeners.text = RetroUtil.formatValue(lastFmAlbum.album.listeners.toFloat())
- scrobbles.text = RetroUtil.formatValue(lastFmAlbum.album.playcount.toFloat())
- }
- }
- }
-
- 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() {
- AlbumGlideRequest.Builder.from(Glide.with(this), album.safeGetFirstSong())
- .checkIgnoreMediaStore(this)
- .ignoreMediaStore(PreferenceUtil.getInstance(this).ignoreMediaStoreArtwork())
- .generatePalette(this)
- .build()
- .dontAnimate()
- .dontTransform()
- .into(object : RetroMusicColoredTarget(image) {
- override fun onColorReady(color: Int) {
- setColors(color)
- }
- })
- }
-
- private fun setColors(color: Int) {
- val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor)
- color.ripAlpha()
- else
- ATHUtil.resolveColor(this, android.R.attr.textColorPrimary)
-
- songTitle.setTextColor(textColor)
- moreTitle.setTextColor(textColor)
- aboutAlbumTitle.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)
- 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)
- ToolbarContentTintHelper.handleOnCreateOptionsMenu(
- this,
- toolbar,
- menu,
- getToolbarBackgroundColor(toolbar)
- )
- 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,
- albumCoverContainer,
- "${getString(R.string.transition_album_art)}_${album.id}"
- )
- 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 e0fdbe4a0..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt
+++ /dev/null
@@ -1,347 +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.transition.Slide
-import android.view.Menu
-import android.view.MenuItem
-import android.view.View
-import android.widget.Toast
-import androidx.core.app.ActivityCompat
-import androidx.core.text.HtmlCompat
-import androidx.recyclerview.widget.DefaultItemAnimator
-import androidx.recyclerview.widget.GridLayoutManager
-import androidx.recyclerview.widget.LinearLayoutManager
-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.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.extensions.show
-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: HorizontalAlbumAdapter
- private var forceDownload: Boolean = false
-
- override fun createContentView(): View {
- return wrapSlidingMusicPanel(R.layout.activity_artist_details)
- }
-
- @Inject
- lateinit var artistDetailsPresenter: ArtistDetailsPresenter
-
- 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)
- window.enterTransition = slide
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- setDrawUnderStatusBar()
- super.onCreate(savedInstanceState)
- toggleBottomNavigationView(true)
- setStatusbarColorAuto()
- setNavigationbarColorAuto()
- setTaskDescriptionColorAuto()
- setLightNavigationBar(true)
- window.sharedElementsUseOverlay = true
-
- App.musicComponent.inject(this)
- artistDetailsPresenter.attachView(this)
-
- if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
- intent.extras?.getInt(EXTRA_ARTIST_ID)?.let {
- artistDetailsPresenter.loadArtist(it)
- val name = "${getString(R.string.transition_artist_image)}_$it"
- artistCoverContainer?.transitionName = name
- }
- } else {
- finish()
- }
-
- windowEnterTransition()
- ActivityCompat.postponeEnterTransition(this)
-
- setupRecyclerView()
-
- 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
- }
- }
- }
-
- override fun onDestroy() {
- super.onDestroy()
- artistDetailsPresenter.detachView()
- }
-
- private fun setupRecyclerView() {
- albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), 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) {
- complete()
- 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(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 = HtmlCompat.fromHtml(bioContent,HtmlCompat.FROM_HTML_MODE_LEGACY)
- biographyText.text = biography
- if (lastFmArtist.artist.stats.listeners.isNotEmpty()) {
- listeners.show()
- listenersLabel.show()
- scrobbles.show()
- scrobblesLabel.show()
-
- listeners.text =
- RetroUtil.formatValue(lastFmArtist.artist.stats.listeners.toFloat())
- scrobbles.text =
- RetroUtil.formatValue(lastFmArtist.artist.stats.playcount.toFloat())
- }
- }
- }
-
- // 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(image) {
- override fun onColorReady(color: Int) {
- setColors(color)
- }
- })
- }
-
- private fun setColors(color: Int) {
- val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor)
- color.ripAlpha()
- else
- ATHUtil.resolveColor(this, android.R.attr.textColorPrimary)
-
- 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)
- 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
index 633bf0fd9..af3890d22 100644
--- a/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt
@@ -1,45 +1,48 @@
/*
- * Copyright (c) 2020 Hemanth Savarala.
+ * Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
- * This is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by
- * the Free Software Foundation either version 3 of the License, or (at your option) any later version.
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
+ *
*/
-
package code.name.monkey.retromusic.activities
-import android.animation.ObjectAnimator
+import android.content.Intent
import android.graphics.Color
import android.graphics.PorterDuff
import android.os.Bundle
-import android.view.animation.LinearInterpolator
-import android.widget.SeekBar
-import code.name.monkey.appthemehelper.ThemeStore
+import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
-import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
+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.RetroMusicColoredTarget
-import code.name.monkey.retromusic.glide.SongGlideRequest
+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.misc.SimpleOnSeekbarChangeListener
+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 kotlinx.android.synthetic.main.activity_drive_mode.*
-import kotlinx.coroutines.CoroutineScope
+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.
@@ -47,21 +50,24 @@ import kotlinx.coroutines.withContext
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?) {
- setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_drive_mode)
+ binding = ActivityDriveModeBinding.inflate(layoutInflater)
+ setContentView(binding.root)
setUpMusicControllers()
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
- lastPlaybackControlsColor = ThemeStore.accentColor(this)
- close.setOnClickListener {
- onBackPressed()
+ lastPlaybackControlsColor = accentColor()
+ binding.close.setOnClickListener {
+ onBackPressedDispatcher.onBackPressed()
}
+ binding.repeatButton.drawAboveSystemBars()
}
private fun setUpMusicControllers() {
@@ -74,36 +80,45 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
}
private fun setupFavouriteToggle() {
- songFavourite.setOnClickListener {
- MusicUtil.toggleFavorite(
- this@DriveModeActivity,
- MusicPlayerRemote.currentSong
- )
+ binding.songFavourite.setOnClickListener {
+ toggleFavorite(MusicPlayerRemote.currentSong)
}
}
- private fun toggleFavourite() {
- CoroutineScope(Dispatchers.IO).launch {
- val isFavourite =
- MusicUtil.isFavorite(this@DriveModeActivity, 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) {
- songFavourite.setImageResource(if (isFavourite) R.drawable.ic_favorite_white_24dp else R.drawable.ic_favorite_border_white_24dp)
+ binding.songFavourite.setImageResource(if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border)
}
}
}
private fun setUpProgressSlider() {
- progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
- override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
- if (fromUser) {
- MusicPlayerRemote.seekTo(progress)
- onUpdateProgressViews(
- MusicPlayerRemote.songProgressMillis,
- MusicPlayerRemote.songDurationMillis
- )
- }
+ binding.progressSlider.addOnChangeListener { _: Slider, progress: Float, fromUser: Boolean ->
+ if (fromUser) {
+ MusicPlayerRemote.seekTo(progress.toInt())
+ onUpdateProgressViews(
+ MusicPlayerRemote.songProgressMillis,
+ MusicPlayerRemote.songDurationMillis
+ )
}
- })
+ }
}
override fun onPause() {
@@ -117,21 +132,20 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
}
private fun setUpPrevNext() {
-
- nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
- previousButton.setOnClickListener { MusicPlayerRemote.back() }
+ binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
+ binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun setUpShuffleButton() {
- shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
+ binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
private fun setUpRepeatButton() {
- repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
+ binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
private fun setUpPlayPauseFab() {
- playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
+ binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
override fun onRepeatModeChanged() {
@@ -155,24 +169,25 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
updateSong()
updateRepeatState()
updateShuffleState()
- toggleFavourite()
+ updateFavorite()
}
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
- playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp)
+ binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
- playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp)
+ binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow)
}
}
fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
- MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
+ MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
- else -> shuffleButton.setColorFilter(
+
+ else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@@ -182,19 +197,27 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
private fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
- repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp)
- repeatButton.setColorFilter(
+ binding.repeatButton.setImageResource(R.drawable.ic_repeat)
+ binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
+
MusicService.REPEAT_MODE_ALL -> {
- repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp)
- repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
+ binding.repeatButton.setImageResource(R.drawable.ic_repeat)
+ binding.repeatButton.setColorFilter(
+ lastPlaybackControlsColor,
+ PorterDuff.Mode.SRC_IN
+ )
}
+
MusicService.REPEAT_MODE_THIS -> {
- repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp)
- repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
+ binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
+ binding.repeatButton.setColorFilter(
+ lastPlaybackControlsColor,
+ PorterDuff.Mode.SRC_IN
+ )
}
}
}
@@ -202,35 +225,34 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged()
updateSong()
- toggleFavourite()
+ updateFavorite()
+ }
+
+ override fun onFavoriteStateChanged() {
+ super.onFavoriteStateChanged()
+ updateFavorite()
}
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
- songTitle.text = song.title
- songText.text = song.artistName
+ binding.songTitle.text = song.title
+ binding.songText.text = song.artistName
- SongGlideRequest.Builder.from(Glide.with(this), song)
- .checkIgnoreMediaStore(this)
- .generatePalette(this)
- .build()
+ Glide.with(this)
+ .load(RetroGlideExtension.getSongModel(song))
+ .songCoverOptions(song)
.transform(BlurTransformation.Builder(this).build())
- .into(object : RetroMusicColoredTarget(image) {
- override fun onColorReady(color: Int) {
- }
- })
+ .into(binding.image)
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
- progressSlider.max = total
+ binding.progressSlider.run {
+ valueTo = total.toFloat()
+ value = progress.toFloat().coerceIn(valueFrom, valueTo)
+ }
- val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
- animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
- animator.interpolator = LinearInterpolator()
- animator.start()
-
- songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
- songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
+ binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
+ binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
-}
\ No newline at end of file
+}
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 3f57ac584..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/GenreDetailsActivity.kt
+++ /dev/null
@@ -1,163 +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.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.DensityUtil
-import code.name.monkey.retromusic.util.RetroColorUtil
-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() {
- checkForPadding()
- emptyEmoji.text = getEmojiByUnicode(0x1F631)
- empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE
- }
-
- private fun checkForPadding() {
- val height = DensityUtil.dip2px(this, 52f)
- recyclerView.setPadding(0, 0, 0, (height))
- }
-
- 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() {
- toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
- setSupportActionBar(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() {
- songAdapter = ShuffleButtonSongAdapter(this, ArrayList(), R.layout.item_list, 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: List) {
- 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 d21171294..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.java
+++ /dev/null
@@ -1,99 +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.ATHUtil;
-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;
-
-/**
- * Created by hemanths on 2019-09-27.
- */
-public class LicenseActivity extends AbsBaseActivity {
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- setDrawUnderStatusBar();
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_license);
- setStatusbarColorAuto();
- setNavigationbarColorAuto();
- setLightNavigationBar(true);
- Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- ToolbarContentTintHelper.colorBackButton(toolbar);
- toolbar.setBackgroundColor(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface));
- WebView webView = findViewById(R.id.license);
- try {
- StringBuilder buf = new StringBuilder();
- InputStream json = getAssets().open("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 = ATHUtil.INSTANCE.isWindowBackgroundDark(this);
- final String backgroundColor = colorToCSS(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface,
- Color.parseColor(isDark ? "#424242" : "#ffffff")));
- final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000"));
- final String changeLog = buf.toString()
- .replace("{style-placeholder}",
- String.format("body { background-color: %s; color: %s; }", backgroundColor, contentColor))
- .replace("{link-color}", colorToCSS(ThemeStore.Companion.accentColor(this)))
- .replace("{link-color-active}",
- colorToCSS(ColorUtil.INSTANCE.lightenColor(ThemeStore.Companion.accentColor(this))));
-
- webView.loadData(changeLog, "text/html", "UTF-8");
- } catch (Throwable e) {
- webView.loadData("Unable to load " + e.getLocalizedMessage() + "
", "text/html", "UTF-8");
- }
-
- }
-
- @Override
- public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- onBackPressed();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- 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
- }
-}
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 5af09dfe6..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,47 +1,54 @@
+/*
+ * 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)
+ lockScreenInit()
+ binding = ActivityLockScreenBinding.inflate(layoutInflater)
+ setContentView(binding.root)
hideStatusBar()
- setStatusbarColorAuto()
- setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
- setLightNavigationBar(true)
val config = SlidrConfig.Builder().listener(object : SlidrListener {
override fun onSlideStateChanged(state: Int) {
@@ -54,10 +61,10 @@ class LockScreenActivity : AbsMusicServiceActivity() {
}
override fun onSlideClosed(): Boolean {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ if (VersionUtils.hasOreo()) {
val keyguardManager =
- getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
- keyguardManager.requestDismissKeyguard(this@LockScreenActivity, null)
+ getSystemService()
+ keyguardManager?.requestDismissKeyguard(this@LockScreenActivity, null)
}
finish()
return true
@@ -66,13 +73,25 @@ class LockScreenActivity : AbsMusicServiceActivity() {
Slidr.attach(this, config)
- fragment =
- supportFragmentManager.findFragmentById(R.id.playback_controls_fragment) as LockScreenPlayerControlsFragment?
+ fragment = whichFragment(R.id.playback_controls_fragment)
- findViewById(R.id.slide).apply {
+ binding.slide.apply {
translationY = 100f
alpha = 0f
- ViewCompat.animate(this).translationY(0f).alpha(1f).setDuration(1500).start()
+ animate().translationY(0f).alpha(1f).setDuration(1500).start()
+ }
+ }
+
+ @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
+ )
}
}
@@ -88,12 +107,15 @@ class LockScreenActivity : AbsMusicServiceActivity() {
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)
+ Glide.with(this)
+ .asBitmapPalette()
+ .songCoverOptions(song)
+ .load(RetroGlideExtension.getSongModel(song))
+ .dontAnimate()
+ .into(object : RetroMusicColoredTarget(binding.image) {
+ override fun onColorReady(colors: MediaNotificationProcessor) {
+ fragment?.setColor(colors)
}
})
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/LyricsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/LyricsActivity.kt
deleted file mode 100644
index 091b8881f..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/LyricsActivity.kt
+++ /dev/null
@@ -1,428 +0,0 @@
-package code.name.monkey.retromusic.activities
-
-import android.R.attr
-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.appthemehelper.util.ATHUtil.resolveColor
-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
-import kotlin.collections.set
-
-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)
- setSupportActionBar(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) {
- finish()
- return true
- }
- return super.onOptionsItemSelected(item)
- }
-
- private fun showSyncedLyrics() {
- var content = ""
- try {
- content = LyricUtil.getStringFromFile(song.title, song.artistName)
- } catch (e: Exception) {
- e.printStackTrace()
- }
-
- val materialDialog = MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT))
- .show {
- cornerRadius(PreferenceUtil.getInstance(this@LyricsActivity).dialogCorner)
- 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.title, 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 {
- cornerRadius(PreferenceUtil.getInstance(this@LyricsActivity).dialogCorner)
- 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 {
- setCurrentPlayLineColor(ThemeStore.accentColor(requireContext()))
- setIndicatorTextColor(ThemeStore.accentColor(requireContext()))
- setCurrentIndicateLineTextColor(
- resolveColor(
- requireContext(),
- attr.textColorPrimary
- )
- )
- setNoLrcTextColor(resolveColor(requireContext(), attr.textColorPrimary))
- 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() {
- lyricsView.resetView("Empty")
- val song = MusicPlayerRemote.currentSong
- 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.java b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.java
deleted file mode 100644
index ea69fb81b..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.java
+++ /dev/null
@@ -1,780 +0,0 @@
-/*
- * Copyright (c) 2020 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.app.ActivityOptions;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.provider.MediaStore;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.widget.Toolbar;
-import androidx.core.app.ActivityCompat;
-import androidx.fragment.app.Fragment;
-import androidx.transition.TransitionManager;
-
-import com.afollestad.materialcab.MaterialCab;
-import com.afollestad.materialcab.MaterialCab.Callback;
-import com.google.android.material.appbar.AppBarLayout;
-import com.google.android.material.card.MaterialCardView;
-import com.google.android.material.textview.MaterialTextView;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-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.AbsSlidingMusicPanelActivity;
-import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog;
-import code.name.monkey.retromusic.fragments.base.AbsLibraryPagerRecyclerViewCustomGridSizeFragment;
-import code.name.monkey.retromusic.fragments.mainactivity.AlbumsFragment;
-import code.name.monkey.retromusic.fragments.mainactivity.ArtistsFragment;
-import code.name.monkey.retromusic.fragments.mainactivity.BannerHomeFragment;
-import code.name.monkey.retromusic.fragments.mainactivity.FoldersFragment;
-import code.name.monkey.retromusic.fragments.mainactivity.GenresFragment;
-import code.name.monkey.retromusic.fragments.mainactivity.PlayingQueueFragment;
-import code.name.monkey.retromusic.fragments.mainactivity.PlaylistsFragment;
-import code.name.monkey.retromusic.fragments.mainactivity.SongsFragment;
-import code.name.monkey.retromusic.helper.MusicPlayerRemote;
-import code.name.monkey.retromusic.helper.SearchQueryHelper;
-import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder;
-import code.name.monkey.retromusic.helper.SortOrder.ArtistSortOrder;
-import code.name.monkey.retromusic.helper.SortOrder.SongSortOrder;
-import code.name.monkey.retromusic.interfaces.CabHolder;
-import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks;
-import code.name.monkey.retromusic.loaders.AlbumLoader;
-import code.name.monkey.retromusic.loaders.ArtistLoader;
-import code.name.monkey.retromusic.loaders.PlaylistSongsLoader;
-import code.name.monkey.retromusic.model.Song;
-import code.name.monkey.retromusic.service.MusicService;
-import code.name.monkey.retromusic.util.AppRater;
-import code.name.monkey.retromusic.util.NavigationUtil;
-import code.name.monkey.retromusic.util.PreferenceUtil;
-import code.name.monkey.retromusic.util.RetroColorUtil;
-import code.name.monkey.retromusic.util.RetroUtil;
-
-/**
- * Created by hemanths on 2020-02-19.
- */
-public class MainActivity extends AbsSlidingMusicPanelActivity
- implements CabHolder, SharedPreferences.OnSharedPreferenceChangeListener {
-
- public static final String TAG = MainActivity.class.getSimpleName();
-
- public static final int APP_INTRO_REQUEST = 100;
-
- public static final String EXPAND_PANEL = "expand_panel";
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(final Context context, final Intent intent) {
- String action = intent.getAction();
- if (action != null && action.equals(Intent.ACTION_SCREEN_OFF)) {
- if (PreferenceUtil.getInstance(context).getLockScreen() && MusicPlayerRemote.isPlaying()) {
- final Intent activity = new Intent(context, LockScreenActivity.class);
- activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
- ActivityCompat.startActivity(context, activity, null);
- }
- }
- }
- };
- private final IntentFilter mIntentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
- @Nullable
- MainActivityFragmentCallbacks currentFragment;
- private boolean blockRequestPermissions = false;
- private MaterialCab cab;
- private AppBarLayout mAppBarLayout;
- private MaterialTextView mAppTitle;
- private Toolbar mToolbar;
- private MaterialCardView mToolbarContainer;
-
- @Override
- protected void onCreate(@Nullable final Bundle savedInstanceState) {
- setDrawUnderStatusBar();
- super.onCreate(savedInstanceState);
- setStatusbarColorAuto();
- setNavigationbarColorAuto();
- setLightNavigationBar(true);
- setTaskDescriptionColorAuto();
- hideStatusBar();
- setBottomBarVisibility(View.VISIBLE);
-
- getBottomNavigationView().setSelectedItemId(PreferenceUtil.getInstance(this).getLastPage());
- getBottomNavigationView().setOnNavigationItemSelectedListener(item -> {
- PreferenceUtil.getInstance(MainActivity.this).setLastPage(item.getItemId());
- selectedFragment(item.getItemId());
- return true;
- });
-
- if (savedInstanceState == null) {
- selectedFragment(PreferenceUtil.getInstance(this).getLastPage());
- } else {
- restoreCurrentFragment();
- }
-
- mToolbarContainer = findViewById(R.id.toolbarContainer);
- mAppTitle = findViewById(R.id.appTitle);
- mToolbar = findViewById(R.id.toolbar);
- mAppBarLayout = findViewById(R.id.appBarLayout);
-
- checkShowChangelog();
- AppRater.appLaunched(this);
- setupToolbar();
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == APP_INTRO_REQUEST) {
- blockRequestPermissions = false;
- if (!hasPermissions()) {
- requestPermissions();
- }
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- registerReceiver(mBroadcastReceiver, mIntentFilter);
- PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this);
-
- if (getIntent().hasExtra(EXPAND_PANEL) && PreferenceUtil.getInstance(this).isExpandPanel()) {
- if (getIntent().getBooleanExtra(EXPAND_PANEL, false)) {
- expandPanel();
- getIntent().putExtra(EXPAND_PANEL, false);
- }
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- unregisterReceiver(mBroadcastReceiver);
- PreferenceUtil.getInstance(this).unregisterOnSharedPreferenceChangedListener(this);
- }
-
- public void addOnAppBarOffsetChangedListener(
- @NonNull AppBarLayout.OnOffsetChangedListener onOffsetChangedListener) {
- mAppBarLayout.addOnOffsetChangedListener(onOffsetChangedListener);
- }
-
- public int getTotalAppBarScrollingRange() {
- return mAppBarLayout.getTotalScrollRange();
- }
-
- @Override
- public boolean handleBackPress() {
- if (cab != null && cab.isActive()) {
- cab.finish();
- return true;
- }
- return super.handleBackPress() || (currentFragment != null && currentFragment.handleBackPress());
- }
-
- @Override
- public boolean onCreateOptionsMenu(final Menu menu) {
- getMenuInflater().inflate(R.menu.menu_main, menu);
- if (isPlaylistPage()) {
- menu.add(0, R.id.action_new_playlist, 0, R.string.new_playlist_title)
- .setIcon(R.drawable.ic_playlist_add_white_24dp)
- .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- }
- if (isHomePage()) {
- menu.add(0, R.id.action_search, 0, getString(R.string.action_search))
- .setIcon(R.drawable.ic_mic_white_24dp)
- .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM);
-
- }
- if (isFolderPage()) {
- menu.add(0, R.id.action_scan, 0, R.string.scan_media)
- .setIcon(R.drawable.ic_scanner_white_24dp)
- .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- menu.add(0, R.id.action_go_to_start_directory, 0, R.string.action_go_to_start_directory)
- .setIcon(R.drawable.ic_bookmark_music_white_24dp)
- .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- }
- Fragment fragment = getCurrentFragment();
- if (fragment instanceof AbsLibraryPagerRecyclerViewCustomGridSizeFragment) {
- AbsLibraryPagerRecyclerViewCustomGridSizeFragment currentFragment
- = (AbsLibraryPagerRecyclerViewCustomGridSizeFragment) fragment;
-
- MenuItem gridSizeItem = menu.findItem(R.id.action_grid_size);
- if (RetroUtil.isLandscape()) {
- gridSizeItem.setTitle(R.string.action_grid_size_land);
- }
- setUpGridSizeMenu(currentFragment, gridSizeItem.getSubMenu());
- MenuItem layoutItem = menu.findItem(R.id.action_layout_type);
- setupLayoutMenu(currentFragment, layoutItem.getSubMenu());
- setUpSortOrderMenu(currentFragment, menu.findItem(R.id.action_sort_order).getSubMenu());
- } else {
- menu.removeItem(R.id.action_layout_type);
- menu.removeItem(R.id.action_grid_size);
- menu.removeItem(R.id.action_sort_order);
- }
- menu.add(0, R.id.action_settings, 0, getString(R.string.action_settings))
- .setIcon(R.drawable.ic_settings_white_24dp)
- .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- return super.onCreateOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
- Fragment fragment = getCurrentFragment();
- if (fragment instanceof AbsLibraryPagerRecyclerViewCustomGridSizeFragment) {
- AbsLibraryPagerRecyclerViewCustomGridSizeFragment currentFragment
- = (AbsLibraryPagerRecyclerViewCustomGridSizeFragment) fragment;
- if (handleGridSizeMenuItem(currentFragment, item)) {
- return true;
- }
- if (handleLayoutResType(currentFragment, item)) {
- return true;
- }
- if (handleSortOrderMenuItem(currentFragment, item)) {
- return true;
- }
- }
- int id = item.getItemId();
- switch (id) {
- case R.id.action_search:
- ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, mToolbarContainer,
- getString(R.string.transition_toolbar));
- NavigationUtil.goToSearch(this, true, options);
- break;
- case R.id.action_new_playlist:
- CreatePlaylistDialog.create().show(getSupportFragmentManager(), "CREATE_PLAYLIST");
- return true;
- case R.id.action_settings:
- NavigationUtil.goToSettings(this);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public boolean onPrepareOptionsMenu(final Menu menu) {
- ToolbarContentTintHelper.handleOnPrepareOptionsMenu(this, mToolbar);
- return super.onPrepareOptionsMenu(menu);
- }
-
- @Override
- public void onServiceConnected() {
- super.onServiceConnected();
- handlePlaybackIntent(getIntent());
- }
-
- @Override
- public void onSharedPreferenceChanged(final @NonNull SharedPreferences sharedPreferences,
- final @NonNull String key) {
- if (key.equals(PreferenceUtil.GENERAL_THEME) || key.equals(PreferenceUtil.BLACK_THEME) ||
- key.equals(PreferenceUtil.ADAPTIVE_COLOR_APP) || key.equals(PreferenceUtil.DOMINANT_COLOR) ||
- key.equals(PreferenceUtil.USER_NAME) || key.equals(PreferenceUtil.TOGGLE_FULL_SCREEN) ||
- key.equals(PreferenceUtil.TOGGLE_VOLUME) || key.equals(PreferenceUtil.ROUND_CORNERS) ||
- key.equals(PreferenceUtil.CAROUSEL_EFFECT) || key.equals(PreferenceUtil.NOW_PLAYING_SCREEN_ID) ||
- key.equals(PreferenceUtil.TOGGLE_GENRE) || key.equals(PreferenceUtil.BANNER_IMAGE_PATH) ||
- key.equals(PreferenceUtil.PROFILE_IMAGE_PATH) || key.equals(PreferenceUtil.CIRCULAR_ALBUM_ART) ||
- key.equals(PreferenceUtil.KEEP_SCREEN_ON) || key.equals(PreferenceUtil.TOGGLE_SEPARATE_LINE) ||
- key.equals(PreferenceUtil.TOGGLE_HOME_BANNER) || key.equals(PreferenceUtil.TOGGLE_ADD_CONTROLS) ||
- key.equals(PreferenceUtil.ALBUM_COVER_STYLE) || key.equals(PreferenceUtil.HOME_ARTIST_GRID_STYLE) ||
- key.equals(PreferenceUtil.ALBUM_COVER_TRANSFORM) || key.equals(PreferenceUtil.DESATURATED_COLOR) ||
- key.equals(PreferenceUtil.TAB_TEXT_MODE) || key.equals(PreferenceUtil.LANGUAGE_NAME) ||
- key.equals(PreferenceUtil.LIBRARY_CATEGORIES)
- ) {
- postRecreate();
- }
- }
-
- @NotNull
- @Override
- public MaterialCab openCab(final int menuRes, @NotNull final Callback callback) {
- if (cab != null && cab.isActive()) {
- cab.finish();
- }
- cab = new MaterialCab(this, R.id.cab_stub)
- .setMenu(menuRes)
- .setCloseDrawableRes(R.drawable.ic_close_white_24dp)
- .setBackgroundColor(
- RetroColorUtil.shiftBackgroundColorForLightText(
- ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface)))
- .start(callback);
- return cab;
- }
-
- public void removeOnAppBarOffsetChangedListener(
- @NonNull AppBarLayout.OnOffsetChangedListener onOffsetChangedListener) {
- mAppBarLayout.removeOnOffsetChangedListener(onOffsetChangedListener);
- }
-
- public void setCurrentFragment(@NonNull Fragment fragment, @NonNull String tag) {
- String currentTag = null;
- if (getSupportFragmentManager().findFragmentByTag(tag) != null) {
- currentTag = getSupportFragmentManager().findFragmentByTag(tag).getTag();
- }
-
- if (!tag.equals(currentTag)) {
- getSupportFragmentManager()
- .beginTransaction()
- .replace(R.id.fragment_container, fragment, tag)
- .commit();
- currentFragment = (MainActivityFragmentCallbacks) fragment;
- }
- }
-
- @NotNull
- @Override
- protected View createContentView() {
- return wrapSlidingMusicPanel(R.layout.activity_main_content);
- }
-
- @Override
- protected void requestPermissions() {
- if (!blockRequestPermissions) {
- super.requestPermissions();
- }
- }
-
- private void checkShowChangelog() {
- try {
- final PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
- final int currentVersion = pInfo.versionCode;
- if (currentVersion != PreferenceUtil.getInstance(this).getLastChangelogVersion()) {
- startActivityForResult(new Intent(this, WhatsNewActivity.class), APP_INTRO_REQUEST);
- }
- } catch (NameNotFoundException e) {
- e.printStackTrace();
- }
- }
-
- @Nullable
- private Fragment getCurrentFragment() {
- return getSupportFragmentManager().findFragmentById(R.id.fragment_container);
- }
-
- private boolean handleGridSizeMenuItem(
- @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment,
- @NonNull MenuItem item) {
- int gridSize = 0;
- switch (item.getItemId()) {
- case R.id.action_grid_size_1:
- gridSize = 1;
- break;
- case R.id.action_grid_size_2:
- gridSize = 2;
- break;
- case R.id.action_grid_size_3:
- gridSize = 3;
- break;
- case R.id.action_grid_size_4:
- gridSize = 4;
- break;
- case R.id.action_grid_size_5:
- gridSize = 5;
- break;
- case R.id.action_grid_size_6:
- gridSize = 6;
- break;
- case R.id.action_grid_size_7:
- gridSize = 7;
- break;
- case R.id.action_grid_size_8:
- gridSize = 8;
- break;
- }
-
- if (gridSize > 0) {
- item.setChecked(true);
- fragment.setAndSaveGridSize(gridSize);
- return true;
- }
- return false;
- }
-
- private boolean handleLayoutResType(
- final AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment,
- final MenuItem item) {
- int layoutRes = -1;
- switch (item.getItemId()) {
- case R.id.action_layout_normal:
- layoutRes = R.layout.item_grid;
- break;
- case R.id.action_layout_card:
- layoutRes = R.layout.item_card;
- break;
- case R.id.action_layout_colored_card:
- layoutRes = R.layout.item_card_color;
- break;
- case R.id.action_layout_circular:
- layoutRes = R.layout.item_grid_circle;
- break;
- case R.id.action_layout_image:
- layoutRes = R.layout.image;
- break;
- case R.id.action_layout_gradient_image:
- layoutRes = R.layout.item_image_gradient;
- break;
- }
- if (layoutRes != -1) {
- item.setChecked(true);
- fragment.setAndSaveLayoutRes(layoutRes);
- return true;
- }
- return false;
- }
-
- private void handlePlaybackIntent(@Nullable Intent intent) {
- if (intent == null) {
- return;
- }
-
- Uri uri = intent.getData();
- String mimeType = intent.getType();
- boolean handled = false;
-
- if (intent.getAction() != null && intent.getAction()
- .equals(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH)) {
- final List songs = SearchQueryHelper.getSongs(this, intent.getExtras());
- if (MusicPlayerRemote.getShuffleMode() == MusicService.SHUFFLE_MODE_SHUFFLE) {
- MusicPlayerRemote.openAndShuffleQueue(songs, true);
- } else {
- MusicPlayerRemote.openQueue(songs, 0, true);
- }
- handled = true;
- }
-
- if (uri != null && uri.toString().length() > 0) {
- MusicPlayerRemote.playFromUri(uri);
- handled = true;
- } else if (MediaStore.Audio.Playlists.CONTENT_TYPE.equals(mimeType)) {
- final int id = (int) parseIdFromIntent(intent, "playlistId", "playlist");
- if (id >= 0) {
- int position = intent.getIntExtra("position", 0);
- List songs = new ArrayList<>(PlaylistSongsLoader.getPlaylistSongList(this, id));
- MusicPlayerRemote.openQueue(songs, position, true);
- handled = true;
- }
- } else if (MediaStore.Audio.Albums.CONTENT_TYPE.equals(mimeType)) {
- final int id = (int) parseIdFromIntent(intent, "albumId", "album");
- if (id >= 0) {
- int position = intent.getIntExtra("position", 0);
- MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).getSongs(), position, true);
- handled = true;
- }
- } else if (MediaStore.Audio.Artists.CONTENT_TYPE.equals(mimeType)) {
- final int id = (int) parseIdFromIntent(intent, "artistId", "artist");
- if (id >= 0) {
- int position = intent.getIntExtra("position", 0);
- MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).getSongs(), position, true);
- handled = true;
- }
- }
- if (handled) {
- setIntent(new Intent());
- }
- }
-
- private boolean handleSortOrderMenuItem(
- @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment
- fragment, @NonNull MenuItem item) {
- String sortOrder = null;
- if (fragment instanceof AlbumsFragment) {
- switch (item.getItemId()) {
- case R.id.action_album_sort_order_asc:
- sortOrder = AlbumSortOrder.ALBUM_A_Z;
- break;
- case R.id.action_album_sort_order_desc:
- sortOrder = AlbumSortOrder.ALBUM_Z_A;
- break;
- case R.id.action_album_sort_order_artist:
- sortOrder = AlbumSortOrder.ALBUM_ARTIST;
- break;
- case R.id.action_album_sort_order_year:
- sortOrder = AlbumSortOrder.ALBUM_YEAR;
- break;
- }
- } else if (fragment instanceof ArtistsFragment) {
- switch (item.getItemId()) {
- case R.id.action_artist_sort_order_asc:
- sortOrder = ArtistSortOrder.ARTIST_A_Z;
- break;
- case R.id.action_artist_sort_order_desc:
- sortOrder = ArtistSortOrder.ARTIST_Z_A;
- break;
- }
- } else if (fragment instanceof SongsFragment) {
- switch (item.getItemId()) {
- case R.id.action_song_sort_order_asc:
- sortOrder = SongSortOrder.SONG_A_Z;
- break;
- case R.id.action_song_sort_order_desc:
- sortOrder = SongSortOrder.SONG_Z_A;
- break;
- case R.id.action_song_sort_order_artist:
- sortOrder = SongSortOrder.SONG_ARTIST;
- break;
- case R.id.action_song_sort_order_album:
- sortOrder = SongSortOrder.SONG_ALBUM;
- break;
- case R.id.action_song_sort_order_year:
- sortOrder = SongSortOrder.SONG_YEAR;
- break;
- case R.id.action_song_sort_order_date:
- sortOrder = SongSortOrder.SONG_DATE;
- break;
- case R.id.action_song_sort_order_composer:
- sortOrder = SongSortOrder.COMPOSER;
- break;
- case R.id.action_song_sort_order_date_modified:
- sortOrder = SongSortOrder.SONG_DATE_MODIFIED;
- break;
- }
- }
-
- if (sortOrder != null) {
- item.setChecked(true);
- fragment.setAndSaveSortOrder(sortOrder);
- return true;
- }
-
- return false;
- }
-
- private boolean isFolderPage() {
- return getSupportFragmentManager().findFragmentByTag(FoldersFragment.TAG) instanceof FoldersFragment;
- }
-
- private boolean isHomePage() {
- return getSupportFragmentManager().findFragmentByTag(BannerHomeFragment.TAG) instanceof BannerHomeFragment;
- }
-
- private boolean isPlaylistPage() {
- return getSupportFragmentManager().findFragmentByTag(PlaylistsFragment.TAG) instanceof PlaylistsFragment;
- }
-
- private long parseIdFromIntent(@NonNull Intent intent, String longKey,
- String stringKey) {
- long id = intent.getLongExtra(longKey, -1);
- if (id < 0) {
- String idString = intent.getStringExtra(stringKey);
- if (idString != null) {
- try {
- id = Long.parseLong(idString);
- } catch (NumberFormatException e) {
- Log.e(TAG, e.getMessage());
- }
- }
- }
- return id;
- }
-
- private void restoreCurrentFragment() {
- currentFragment = (MainActivityFragmentCallbacks) getSupportFragmentManager()
- .findFragmentById(R.id.fragment_container);
- }
-
- private void selectedFragment(final int itemId) {
- switch (itemId) {
- case R.id.action_album:
- setCurrentFragment(AlbumsFragment.newInstance(), AlbumsFragment.TAG);
- break;
- case R.id.action_artist:
- setCurrentFragment(ArtistsFragment.newInstance(), ArtistsFragment.TAG);
- break;
- case R.id.action_playlist:
- setCurrentFragment(PlaylistsFragment.newInstance(), PlaylistsFragment.TAG);
- break;
- case R.id.action_genre:
- setCurrentFragment(GenresFragment.newInstance(), GenresFragment.TAG);
- break;
- case R.id.action_playing_queue:
- setCurrentFragment(PlayingQueueFragment.newInstance(), PlayingQueueFragment.TAG);
- break;
- case R.id.action_song:
- setCurrentFragment(SongsFragment.newInstance(), SongsFragment.TAG);
- break;
- case R.id.action_folder:
- setCurrentFragment(FoldersFragment.newInstance(this), FoldersFragment.TAG);
- break;
- default:
- case R.id.action_home:
- setCurrentFragment(BannerHomeFragment.newInstance(), BannerHomeFragment.TAG);
- break;
- }
- }
-
-
- private void setUpGridSizeMenu(@NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment,
- @NonNull SubMenu gridSizeMenu) {
-
- switch (fragment.getGridSize()) {
- case 1:
- gridSizeMenu.findItem(R.id.action_grid_size_1).setChecked(true);
- break;
- case 2:
- gridSizeMenu.findItem(R.id.action_grid_size_2).setChecked(true);
- break;
- case 3:
- gridSizeMenu.findItem(R.id.action_grid_size_3).setChecked(true);
- break;
- case 4:
- gridSizeMenu.findItem(R.id.action_grid_size_4).setChecked(true);
- break;
- case 5:
- gridSizeMenu.findItem(R.id.action_grid_size_5).setChecked(true);
- break;
- case 6:
- gridSizeMenu.findItem(R.id.action_grid_size_6).setChecked(true);
- break;
- case 7:
- gridSizeMenu.findItem(R.id.action_grid_size_7).setChecked(true);
- break;
- case 8:
- gridSizeMenu.findItem(R.id.action_grid_size_8).setChecked(true);
- break;
- }
- int maxGridSize = fragment.getMaxGridSize();
- if (maxGridSize < 8) {
- gridSizeMenu.findItem(R.id.action_grid_size_8).setVisible(false);
- }
- if (maxGridSize < 7) {
- gridSizeMenu.findItem(R.id.action_grid_size_7).setVisible(false);
- }
- if (maxGridSize < 6) {
- gridSizeMenu.findItem(R.id.action_grid_size_6).setVisible(false);
- }
- if (maxGridSize < 5) {
- gridSizeMenu.findItem(R.id.action_grid_size_5).setVisible(false);
- }
- if (maxGridSize < 4) {
- gridSizeMenu.findItem(R.id.action_grid_size_4).setVisible(false);
- }
- if (maxGridSize < 3) {
- gridSizeMenu.findItem(R.id.action_grid_size_3).setVisible(false);
- }
- }
-
- private void setUpSortOrderMenu(
- @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment,
- @NonNull SubMenu sortOrderMenu) {
- String currentSortOrder = fragment.getSortOrder();
- sortOrderMenu.clear();
-
- if (fragment instanceof AlbumsFragment) {
- sortOrderMenu.add(0, R.id.action_album_sort_order_asc, 0, R.string.sort_order_a_z)
- .setChecked(currentSortOrder.equals(AlbumSortOrder.ALBUM_A_Z));
- sortOrderMenu.add(0, R.id.action_album_sort_order_desc, 1, R.string.sort_order_z_a)
- .setChecked(currentSortOrder.equals(AlbumSortOrder.ALBUM_Z_A));
- sortOrderMenu.add(0, R.id.action_album_sort_order_artist, 2, R.string.sort_order_artist)
- .setChecked(currentSortOrder.equals(AlbumSortOrder.ALBUM_ARTIST));
- sortOrderMenu.add(0, R.id.action_album_sort_order_year, 3, R.string.sort_order_year)
- .setChecked(currentSortOrder.equals(AlbumSortOrder.ALBUM_YEAR));
- } else if (fragment instanceof ArtistsFragment) {
- sortOrderMenu.add(0, R.id.action_artist_sort_order_asc, 0, R.string.sort_order_a_z)
- .setChecked(currentSortOrder.equals(ArtistSortOrder.ARTIST_A_Z));
- sortOrderMenu.add(0, R.id.action_artist_sort_order_desc, 1, R.string.sort_order_z_a)
- .setChecked(currentSortOrder.equals(ArtistSortOrder.ARTIST_Z_A));
- } else if (fragment instanceof SongsFragment) {
- sortOrderMenu.add(0, R.id.action_song_sort_order_asc, 0, R.string.sort_order_a_z)
- .setChecked(currentSortOrder.equals(SongSortOrder.SONG_A_Z));
- sortOrderMenu.add(0, R.id.action_song_sort_order_desc, 1, R.string.sort_order_z_a)
- .setChecked(currentSortOrder.equals(SongSortOrder.SONG_Z_A));
- sortOrderMenu.add(0, R.id.action_song_sort_order_artist, 2, R.string.sort_order_artist)
- .setChecked(currentSortOrder.equals(SongSortOrder.SONG_ARTIST));
- sortOrderMenu.add(0, R.id.action_song_sort_order_album, 3, R.string.sort_order_album)
- .setChecked(currentSortOrder.equals(SongSortOrder.SONG_ALBUM));
- sortOrderMenu.add(0, R.id.action_song_sort_order_year, 4, R.string.sort_order_year)
- .setChecked(currentSortOrder.equals(SongSortOrder.SONG_YEAR));
- sortOrderMenu.add(0, R.id.action_song_sort_order_date, 5, R.string.sort_order_date)
- .setChecked(currentSortOrder.equals(SongSortOrder.SONG_DATE));
- sortOrderMenu.add(0, R.id.action_song_sort_order_date_modified, 6, R.string.sort_order_date_modified)
- .setChecked(currentSortOrder.equals(SongSortOrder.SONG_DATE_MODIFIED));
- sortOrderMenu.add(0, R.id.action_song_sort_order_composer, 7, R.string.sort_order_composer)
- .setChecked(currentSortOrder.equals(SongSortOrder.COMPOSER));
- }
- sortOrderMenu.setGroupCheckable(0, true, true);
- }
-
- private void setupLayoutMenu(
- @NonNull final AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment,
- @NonNull final SubMenu subMenu) {
- switch (fragment.itemLayoutRes()) {
- case R.layout.item_card:
- subMenu.findItem(R.id.action_layout_card).setChecked(true);
- break;
- case R.layout.item_grid:
- subMenu.findItem(R.id.action_layout_normal).setChecked(true);
- break;
- case R.layout.item_card_color:
- subMenu.findItem(R.id.action_layout_colored_card).setChecked(true);
- break;
- case R.layout.item_grid_circle:
- subMenu.findItem(R.id.action_layout_circular).setChecked(true);
- break;
- case R.layout.image:
- subMenu.findItem(R.id.action_layout_image).setChecked(true);
- break;
- case R.layout.item_image_gradient:
- subMenu.findItem(R.id.action_layout_gradient_image).setChecked(true);
- break;
- }
- }
-
- private void setupToolbar() {
- setTitle(null);
- mToolbar.setBackgroundColor(Color.TRANSPARENT);
- mToolbarContainer.setCardBackgroundColor(
- ColorStateList.valueOf(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface)));
- setSupportActionBar(mToolbar);
- mToolbar.setOnClickListener(v -> {
- ActivityOptions options = ActivityOptions
- .makeSceneTransitionAnimation(this, mToolbarContainer, getString(R.string.transition_toolbar));
- NavigationUtil.goToSearch(this, options);
- });
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- TransitionManager.beginDelayedTransition(mToolbar);
- Log.i(TAG, "run: " + Thread.currentThread().getName());
- mAppTitle.setVisibility(View.GONE);
- setTitle(R.string.action_search);
- }
- }, 3000);
-
- Locale[] locales = Locale.getAvailableLocales();
-
- for (Locale l : locales) {
- Log.d(TAG, "setupToolbar: " + l.toLanguageTag());
- }
- }
-}
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
new file mode 100644
index 000000000..e9cb29abe
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt
@@ -0,0 +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.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.provider.MediaStore
+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.extensions.*
+import code.name.monkey.retromusic.helper.MusicPlayerRemote
+import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs
+import code.name.monkey.retromusic.interfaces.IScrollHelper
+import code.name.monkey.retromusic.model.CategoryInfo
+import code.name.monkey.retromusic.model.Song
+import code.name.monkey.retromusic.repository.PlaylistSongsLoader
+import code.name.monkey.retromusic.service.MusicService
+import code.name.monkey.retromusic.util.PreferenceUtil
+import code.name.monkey.retromusic.util.logE
+import kotlinx.coroutines.Dispatchers.IO
+import kotlinx.coroutines.launch
+import org.koin.android.ext.android.get
+
+class MainActivity : AbsSlidingMusicPanelActivity() {
+ companion object {
+ const val TAG = "MainActivity"
+ const val EXPAND_PANEL = "expand_panel"
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setTaskDescriptionColorAuto()
+ hideStatusBar()
+ updateTabs()
+
+ 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()
+ }
+ }
+ }
+ navController.addOnDestinationChangedListener { _, destination, _ ->
+ if (destination.id == navGraph.startDestinationId) {
+ currentFragment(R.id.fragment_container)?.enterTransition = null
+ }
+ when (destination.id) {
+ R.id.action_home, R.id.action_song, R.id.action_album, R.id.action_artist, R.id.action_folder, R.id.action_playlist, R.id.action_genre, R.id.action_search -> {
+ // Save the last tab
+ if (PreferenceUtil.rememberLastTab) {
+ saveTab(destination.id)
+ }
+ // Show Bottom Navigation Bar
+ setBottomNavVisibility(visible = true, animate = true)
+ }
+ R.id.playing_queue_fragment -> {
+ setBottomNavVisibility(visible = false, hideBottomSheet = true)
+ }
+ else -> setBottomNavVisibility(
+ visible = false,
+ animate = true
+ ) // Hide Bottom Navigation Bar
+ }
+ }
+ }
+
+ private fun saveTab(id: Int) {
+ if (PreferenceUtil.libraryCategory.firstOrNull { it.category.id == id }?.visible == true) {
+ PreferenceUtil.lastTab = id
+ }
+ }
+
+ 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)
+ }
+ }
+
+ override fun onServiceConnected() {
+ super.onServiceConnected()
+ intent ?: return
+ handlePlaybackIntent(intent)
+ }
+
+ private fun handlePlaybackIntent(intent: Intent) {
+ lifecycleScope.launch(IO) {
+ val uri: Uri? = intent.data
+ val mimeType: String? = intent.type
+ var handled = false
+ if (intent.action != null &&
+ intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
+ ) {
+ val songs: List = getSongs(intent.extras!!)
+ if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) {
+ MusicPlayerRemote.openAndShuffleQueue(songs, true)
+ } else {
+ MusicPlayerRemote.openQueue(songs, 0, true)
+ }
+ handled = 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
+ }
+ }
+ if (handled) {
+ setIntent(Intent())
+ }
+ }
+ }
+
+ 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 = idString.toLong()
+ } catch (e: NumberFormatException) {
+ logE(e)
+ }
+ }
+ }
+ return id
+ }
+}
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 4541ecb56..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt
+++ /dev/null
@@ -1,245 +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 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() {
-
- recyclerView.layoutManager = LinearLayoutManager(this)
- if (playlist is AbsCustomPlaylist) {
- adapter = PlaylistSongAdapter(this, ArrayList(), R.layout.item_list, this)
- recyclerView.adapter = adapter
- } else {
- recyclerViewDragDropManager = RecyclerViewDragDropManager()
- val animator = RefactoredDefaultItemAnimator()
- adapter = OrderablePlaylistSongAdapter(this,
- ArrayList(),
- R.layout.item_list,
- 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: List) {
- 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 f2a5ee8e1..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.ATHUtil
-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 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?) {
- setDrawUnderStatusBar()
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_pro_version)
- setStatusbarColorAuto()
- setNavigationbarColorAuto()
- setLightNavigationBar(true)
- toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
- setSupportActionBar(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 494b6dd58..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/SearchActivity.kt
+++ /dev/null
@@ -1,226 +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
-import kotlin.collections.MutableList
-import kotlin.collections.emptyList
-
-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 a788e5673..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/SettingsActivity.kt
+++ /dev/null
@@ -1,80 +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 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
- )
- fragmentTransaction.replace(R.id.contentFrame, fragment, fragment.tag)
- fragmentTransaction.addToBackStack(null)
- fragmentTransaction.commit()
-
- 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
index ae6334708..546c9d794 100644
--- a/app/src/main/java/code/name/monkey/retromusic/activities/ShareInstagramStory.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/activities/ShareInstagramStory.kt
@@ -1,45 +1,51 @@
/*
- * Copyright (c) 2020 Hemanth Savarala.
+ * Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
- * This is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by
- * the Free Software Foundation either version 3 of the License, or (at your option) any later version.
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
+ *
*/
-
package 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.net.Uri
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.ThemeStore
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.activities.base.AbsBaseActivity
+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.glide.SongGlideRequest
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
-import kotlinx.android.synthetic.main.activity_share_instagram.*
/**
* Created by hemanths on 2020-02-02.
*/
-class ShareInstagramStory : AbsBaseActivity() {
+class ShareInstagramStory : AbsThemeActivity() {
+
+ private lateinit var binding: ActivityShareInstagramBinding
companion object {
const val EXTRA_SONG = "extra_song"
@@ -47,76 +53,59 @@ class ShareInstagramStory : AbsBaseActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
- onBackPressed()
+ onBackPressedDispatcher.onBackPressed()
return true
}
return super.onOptionsItemSelected(item)
}
override fun onCreate(savedInstanceState: Bundle?) {
- setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_share_instagram)
- setStatusbarColor(Color.TRANSPARENT)
- setNavigationbarColor(Color.BLACK)
+ binding = ActivityShareInstagramBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ setStatusBarColor(Color.TRANSPARENT)
- toolbar.setBackgroundColor(Color.TRANSPARENT)
- setSupportActionBar(toolbar)
+ binding.toolbar.setBackgroundColor(Color.TRANSPARENT)
+ setSupportActionBar(binding.toolbar)
- val song = intent.extras?.getParcelable(EXTRA_SONG)
+ val song = intent.extras?.let { BundleCompat.getParcelable(it, EXTRA_SONG, Song::class.java) }
song?.let { songFinal ->
- SongGlideRequest.Builder.from(Glide.with(this), songFinal)
- .checkIgnoreMediaStore(this@ShareInstagramStory)
- .generatePalette(this@ShareInstagramStory)
- .build()
- .into(object : RetroMusicColoredTarget(image) {
- override fun onColorReady(color: Int) {
- val isColorLight = ColorUtil.isColorLight(color)
- setColors(isColorLight, color)
+ Glide.with(this)
+ .asBitmapPalette()
+ .songCoverOptions(songFinal)
+ .load(RetroGlideExtension.getSongModel(songFinal))
+ .into(object : RetroMusicColoredTarget(binding.image) {
+ override fun onColorReady(colors: MediaNotificationProcessor) {
+ setColors(colors.backgroundColor)
}
})
- shareTitle.text = songFinal.title
- shareText.text = songFinal.artistName
- shareButton.setOnClickListener {
+ binding.shareTitle.text = songFinal.title
+ binding.shareText.text = songFinal.artistName
+ binding.shareButton.setOnClickListener {
val path: String = Media.insertImage(
contentResolver,
- mainContent.drawToBitmap(Bitmap.Config.ARGB_8888),
+ binding.mainContent.drawToBitmap(Bitmap.Config.ARGB_8888),
"Design", null
)
- val uri = Uri.parse(path)
Share.shareStoryToSocial(
this@ShareInstagramStory,
- uri
+ path.toUri()
)
}
}
- shareButton.setTextColor(
+ binding.shareButton.setTextColor(
MaterialValueHelper.getPrimaryTextColor(
this,
- ColorUtil.isColorLight(ThemeStore.accentColor(this))
+ ColorUtil.isColorLight(accentColor())
)
)
- shareButton.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
+ binding.shareButton.backgroundTintList =
+ ColorStateList.valueOf(accentColor())
}
- private fun setColors(colorLight: Boolean, color: Int) {
- setLightStatusbar(colorLight)
- toolbar.setTitleTextColor(
- MaterialValueHelper.getPrimaryTextColor(
- this@ShareInstagramStory,
- colorLight
- )
- )
- toolbar.navigationIcon?.setTintList(
- ColorStateList.valueOf(
- MaterialValueHelper.getPrimaryTextColor(
- this@ShareInstagramStory,
- colorLight
- )
- )
- )
- mainContent.background =
+ 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 010b18081..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt
+++ /dev/null
@@ -1,262 +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.MaterialUtil
-import code.name.monkey.appthemehelper.util.TintHelper
-import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
-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.dialogs.UpiPaymentBottomSheetDialogFragment
-import code.name.monkey.retromusic.extensions.textColorPrimary
-import code.name.monkey.retromusic.extensions.textColorSecondary
-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_about.toolbar
-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))
-
- MaterialUtil.setTint(upiClick)
- upiClick.setOnClickListener {
- UpiPaymentBottomSheetDialogFragment().show(
- supportFragmentManager,
- UpiPaymentBottomSheetDialogFragment.TAG
- )
- }
- }
-
- private fun setupToolbar() {
- val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
- toolbar.setBackgroundColor(toolbarColor)
- ToolbarContentTintHelper.colorBackButton(toolbar)
- setSupportActionBar(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() {
- billingProcessor?.release()
- 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
- 7 -> R.drawable.ic_food_croissant_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 textColorPrimary(donationsDialog)
- val contentTextColor =
- if (purchased) titleTextColor else 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 739bd7713..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/UserInfoActivity.kt
+++ /dev/null
@@ -1,267 +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.ATHUtil
-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.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 kotlinx.android.synthetic.main.activity_user_info.*
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.File
-import java.io.FileOutputStream
-import java.io.IOException
-
-class UserInfoActivity : AbsBaseActivity() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_user_info)
- setStatusbarColorAuto()
- setNavigationbarColorAuto()
- setTaskDescriptionColorAuto()
- setLightNavigationBar(true)
-
- toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
- setSupportActionBar(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) {
- CoroutineScope(Dispatchers.IO).launch {
- withContext(Dispatchers.IO) {
- val bitmap = Compressor(this@UserInfoActivity).setQuality(100)
- .setCompressFormat(Bitmap.CompressFormat.WEBP)
- .compressToBitmap(File(profileImagePath, USER_BANNER))
- withContext(Dispatchers.Main) { bannerImage.setImageBitmap(bitmap) }
- }
- }
- }
-
- private fun loadImageFromStorage(path: String) {
- CoroutineScope(Dispatchers.IO).launch {
- withContext(Dispatchers.IO) {
- val bitmap = Compressor(this@UserInfoActivity)
- .setMaxHeight(300)
- .setMaxWidth(300)
- .setQuality(75)
- .setCompressFormat(Bitmap.CompressFormat.WEBP)
- .compressToBitmap(File(path, USER_PROFILE))
- withContext(Dispatchers.Main) { userImage.setImageBitmap(bitmap) }
- }
- }
- }
-
- 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 631db15ca..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.java
+++ /dev/null
@@ -1,102 +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 androidx.core.widget.NestedScrollView;
-
-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.ATHUtil;
-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;
-
-public class WhatsNewActivity extends AbsBaseActivity {
-
- AppBarLayout appBarLayout;
-
- Toolbar toolbar;
-
- WebView webView;
-
- 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
- }
-
- 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();
- }
- }
-
- @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(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface));
- //setSupportActionBar(toolbar);
-
- toolbar.setNavigationOnClickListener(v -> onBackPressed());
- ToolbarContentTintHelper.colorBackButton(toolbar);
- NestedScrollView nestedScrollView = findViewById(R.id.container);
-
- try {
- StringBuilder buf = new StringBuilder();
- InputStream json = getAssets().open("retro-changelog.html");
- BufferedReader in = new BufferedReader(new InputStreamReader(json, StandardCharsets.UTF_8));
- String str;
- while ((str = in.readLine()) != null) {
- buf.append(str);
- }
- in.close();
-
- // Inject color values for WebView body background and links
- final boolean isDark = ATHUtil.INSTANCE.isWindowBackgroundDark(this);
- final String backgroundColor = colorToCSS(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface,
- Color.parseColor(isDark ? "#424242" : "#ffffff")));
- final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000"));
- final String changeLog = buf.toString()
- .replace("{style-placeholder}",
- String.format("body { background-color: %s; color: %s; }", backgroundColor, contentColor))
- .replace("{link-color}", colorToCSS(ThemeStore.Companion.accentColor(this)))
- .replace("{link-color-active}",
- colorToCSS(ColorUtil.INSTANCE.lightenColor(ThemeStore.Companion.accentColor(this))));
-
- webView.loadData(changeLog, "text/html", "UTF-8");
- } catch (Throwable e) {
- webView.loadData("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 7cd90a8b4..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,18 +1,39 @@
+/*
+ * 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.Build
import android.os.Bundle
import android.provider.Settings
import android.view.KeyEvent
+import android.view.MotionEvent
import android.view.View
+import android.view.inputmethod.InputMethodManager
+import android.widget.EditText
import 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() {
@@ -33,7 +54,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
}
private val snackBarContainer: View
- get() = window.decorView
+ get() = rootView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -43,19 +64,12 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (VersionUtils.hasMarshmallow()) {
onHasPermissionsChanged(hasPermissions)
}
}
@@ -63,6 +77,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
protected open fun onHasPermissionsChanged(hasPermissions: Boolean) {
// implemented by sub classes
+ logD(hasPermissions)
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
@@ -77,17 +92,15 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
}
protected open fun requestPermissions() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- requestPermissions(permissions, PERMISSION_REQUEST)
- }
+ ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST)
}
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
- }
+ for (permission in permissions) {
+ if (ActivityCompat.checkSelfPermission(this,
+ permission) != PackageManager.PERMISSION_GRANTED
+ ) {
+ return false
}
}
return true
@@ -96,51 +109,96 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array,
- grantResults: IntArray
+ 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
+ this@AbsBaseActivity, Manifest.permission.READ_EXTERNAL_STORAGE,
+ ) || ActivityCompat.shouldShowRequestPermissionRationale(
+ this@AbsBaseActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
)
) {
- //User has deny from permission dialog
+ // User has deny from permission dialog
Snackbar.make(
snackBarContainer,
permissionDeniedMessage!!,
- Snackbar.LENGTH_INDEFINITE
+ Snackbar.LENGTH_SHORT
)
- .setAction(code.name.monkey.retromusic.R.string.action_grant) { requestPermissions() }
- .setActionTextColor(ThemeStore.accentColor(this)).show()
+ .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(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()
+ )
+ .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()
+ }
+ }
+ }
}
}
companion object {
const val PERMISSION_REQUEST = 100
+ const val BLUETOOTH_PERMISSION_REQUEST = 101
+ }
+
+ // 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 c545b338e..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,20 +1,49 @@
+/*
+ * Copyright (c) 2020 Hemanth Savarla.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
package code.name.monkey.retromusic.activities.base
import android.Manifest
import android.content.*
import android.os.Bundle
import android.os.IBinder
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.lifecycleScope
+import code.name.monkey.appthemehelper.util.VersionUtils
import 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 {
-
- private val mMusicServiceEventListeners = ArrayList()
+abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventListener {
+ 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
@@ -43,15 +72,15 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
}
}
- fun addMusicServiceEventListener(listener: MusicServiceEventListener?) {
- if (listener != null) {
- mMusicServiceEventListeners.add(listener)
+ fun addMusicServiceEventListener(listenerI: IMusicServiceEventListener?) {
+ if (listenerI != null) {
+ mMusicServiceEventListeners.add(listenerI)
}
}
- fun removeMusicServiceEventListener(listener: MusicServiceEventListener?) {
- if (listener != null) {
- mMusicServiceEventListeners.remove(listener)
+ fun removeMusicServiceEventListener(listenerI: IMusicServiceEventListener?) {
+ if (listenerI != null) {
+ mMusicServiceEventListeners.remove(listenerI)
}
}
@@ -68,8 +97,7 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
filter.addAction(MEDIA_STORE_CHANGED)
filter.addAction(FAVORITE_STATE_CHANGED)
- registerReceiver(musicStateReceiver, filter)
-
+ ContextCompat.registerReceiver(this, musicStateReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED)
receiverRegistered = true
}
@@ -93,6 +121,16 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
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()
+
+ repository.upsertSongInPlayCount(song)
+ }
}
override fun onQueueChanged() {
@@ -125,6 +163,12 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
}
}
+ override fun onFavoriteStateChanged() {
+ for (listener in mMusicServiceEventListeners) {
+ listener.onFavoriteStateChanged()
+ }
+ }
+
override fun onHasPermissionsChanged(hasPermissions: Boolean) {
super.onHasPermissionsChanged(hasPermissions)
val intent = Intent(MEDIA_STORE_CHANGED)
@@ -133,14 +177,21 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
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,
- Manifest.permission.BLUETOOTH
- )
+ 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() {
@@ -152,7 +203,8 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
val activity = reference.get()
if (activity != null && action != null) {
when (action) {
- FAVORITE_STATE_CHANGED, META_CHANGED -> activity.onPlayingMetaChanged()
+ FAVORITE_STATE_CHANGED -> activity.onFavoriteStateChanged()
+ META_CHANGED -> activity.onPlayingMetaChanged()
QUEUE_CHANGED -> activity.onQueueChanged()
PLAY_STATE_CHANGED -> activity.onPlayStateChanged()
REPEAT_MODE_CHANGED -> activity.onRepeatModeChanged()
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 3a84f55bc..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,112 +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 android.view.animation.PathInterpolator
import android.widget.FrameLayout
-import androidx.annotation.LayoutRes
-import androidx.fragment.app.Fragment
-import code.name.monkey.appthemehelper.util.ATHUtil
-import code.name.monkey.appthemehelper.util.ColorUtil
+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 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 {
+ SharedPreferences.OnSharedPreferenceChangeListener {
companion object {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
}
+ var fromNotification = false
+ private var windowInsets: WindowInsetsCompat? = null
+ protected val libraryViewModel by viewModel()
private lateinit var bottomSheetBehavior: BottomSheetBehavior
+ private lateinit var playerFragment: AbsPlayerFragment
private 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)
}
}
@@ -114,264 +228,354 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
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 :
+ 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.elevation = 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()
- CIRCLE -> CirclePlayerFragment()
- 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 == BLUR || currentNowPlayingScreen == BLUR_CARD) {
- super.setLightStatusbar(false)
- super.setLightNavigationBar(true)
- super.setNavigationbarColor(Color.BLACK)
- } else if (currentNowPlayingScreen == COLOR || currentNowPlayingScreen == TINY) {
- super.setNavigationbarColor(paletteColor)
- super.setLightNavigationBar(isColorLight)
- super.setLightStatusbar(isColorLight)
- } else if (currentNowPlayingScreen == FIT) {
- super.setLightStatusbar(false)
- } 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)
}
}
- 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 14550e5ef..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,54 +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.content.Context
-import android.graphics.Color
-import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Handler
+import android.os.Looper
import android.view.KeyEvent
-import android.view.View
-import android.view.WindowManager
-import androidx.annotation.ColorInt
+import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
-import androidx.core.content.ContextCompat
-import code.name.monkey.appthemehelper.ATH
-import code.name.monkey.appthemehelper.ThemeStore
+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.LanguageContextWrapper
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.theme.ThemeManager
-import java.util.*
+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?) {
+ updateLocale()
updateTheme()
hideStatusBar()
super.onCreate(savedInstanceState)
- setImmersiveFullscreen()
- registerSystemUiVisibility()
- toggleScreenOn()
+ setEdgeToEdgeOrImmersive()
+ maybeSetScreenOn()
+ setLightNavigationBarAuto()
+ setLightStatusBarAuto(surfaceColor())
+ if (VersionUtils.hasQ()) {
+ window.decorView.isForceDarkAllowed = false
+ }
}
-
private fun updateTheme() {
- setTheme(ThemeManager.getThemeResValue(this))
- setDefaultNightMode(ThemeManager.getNightMode(this))
+ setTheme(getThemeResValue())
+ if (PreferenceUtil.materialYou) {
+ setDefaultNightMode(getNightMode())
+ }
+
+ if (PreferenceUtil.isCustomFont) {
+ setTheme(R.style.FontThemeOverlay)
+ }
}
- 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 updateLocale() {
+ val localeCode = PreferenceUtil.languageCode
+ if (PreferenceUtil.isLocaleAutoStorageEnabled) {
+ AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(localeCode))
+ PreferenceUtil.isLocaleAutoStorageEnabled = true
}
}
@@ -63,131 +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()
}
@@ -199,7 +89,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
public override fun onDestroy() {
super.onDestroy()
- unregisterSystemUiVisibility()
exitFullscreen()
}
@@ -212,9 +101,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
}
override fun attachBaseContext(newBase: Context?) {
- val code = PreferenceUtil.getInstance(newBase).languageCode
- if (code != "auto") {
- super.attachBaseContext(LanguageContextWrapper.wrap(newBase, Locale(code)))
- } else super.attachBaseContext(newBase)
+ super.attachBaseContext(newBase)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt
index 4ee68b9b7..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 5a2661277..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.java
+++ /dev/null
@@ -1,130 +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 java.util.Locale;
-
-import code.name.monkey.retromusic.util.PreferenceUtil;
-
-public class DeviceInfo {
-
- @SuppressLint("NewApi")
- @SuppressWarnings("deprecation")
- private final String[] abis = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
- Build.SUPPORTED_ABIS : new String[]{Build.CPU_ABI, Build.CPU_ABI2};
-
- @SuppressLint("NewApi")
- 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;
-
- private final String baseTheme;
-
- private final String brand = Build.BRAND;
-
- private final String buildID = Build.DISPLAY;
-
- private final String buildVersion = Build.VERSION.INCREMENTAL;
-
- private final String device = Build.DEVICE;
-
- private final String hardware = Build.HARDWARE;
-
- private final boolean isAdaptive;
-
- private final String manufacturer = Build.MANUFACTURER;
-
- private final String model = Build.MODEL;
-
- private final String nowPlayingTheme;
-
- private final String product = Build.PRODUCT;
-
- private final String releaseVersion = Build.VERSION.RELEASE;
-
- @IntRange(from = 0)
- private final int sdkVersion = Build.VERSION.SDK_INT;
-
- private final int versionCode;
-
- private final String versionName;
- private final String selectedLang;
-
- public DeviceInfo(Context context) {
- PackageInfo packageInfo;
- try {
- packageInfo = context.getPackageManager()
- .getPackageInfo(context.getPackageName(), 0);
- } catch (PackageManager.NameNotFoundException e) {
- packageInfo = null;
- }
- if (packageInfo != null) {
- versionCode = packageInfo.versionCode;
- versionName = packageInfo.versionName;
- } else {
- versionCode = -1;
- versionName = null;
- }
- baseTheme = PreferenceUtil.getInstance(context).getBaseTheme();
- nowPlayingTheme = context.getString(PreferenceUtil.getInstance(context).getNowPlayingScreen().getTitleRes());
- isAdaptive = PreferenceUtil.getInstance(context).getAdaptiveColor();
- selectedLang = PreferenceUtil.getInstance(context).getLanguageCode();
- }
-
- 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"
- + "Language " + selectedLang + " \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 + "\n"
- + "System language: " + Locale.getDefault().toLanguageTag() + "\n"
- + "In-App Language: " + selectedLang;
- }
-}
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 1da9313bb..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/Report.java
+++ /dev/null
@@ -1,33 +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 description;
-
- private final DeviceInfo deviceInfo;
-
- private final ExtraInfo extraInfo;
-
- private final String title;
-
- public Report(String title, String description, DeviceInfo deviceInfo, ExtraInfo extraInfo) {
- this.title = title;
- this.description = description;
- this.deviceInfo = deviceInfo;
- this.extraInfo = extraInfo;
- }
-
- public String getDescription() {
- return description + "\n\n"
- + "-\n\n"
- + deviceInfo.toMarkdown() + "\n\n"
- + extraInfo.toMarkdown();
- }
-
- public String getTitle() {
- return title;
- }
-}
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 ec27388cb..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/ExtraInfo.java
+++ /dev/null
@@ -1,62 +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 e388249cb..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/GithubLogin.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package code.name.monkey.retromusic.activities.bugreport.model.github;
-
-import android.text.TextUtils;
-
-public class GithubLogin {
-
- private final String apiToken;
-
- private final String password;
-
- private final String username;
-
- 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 getApiToken() {
- return apiToken;
- }
-
- public String getPassword() {
- return password;
- }
-
- public String getUsername() {
- return username;
- }
-
- public boolean shouldUseApiToken() {
- return TextUtils.isEmpty(username) || TextUtils.isEmpty(password);
- }
-
-}
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 21126d30c..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/github/GithubTarget.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package code.name.monkey.retromusic.activities.bugreport.model.github;
-
-public class GithubTarget {
-
- private final String repository;
-
- private final String username;
-
- public GithubTarget(String username, String repository) {
- this.username = username;
- this.repository = repository;
- }
-
- public String getRepository() {
- return repository;
- }
-
- public String getUsername() {
- return username;
- }
-}
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 a5f2d9083..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,49 +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;
+ public static final int REQUEST_CODE_SAF_GUIDE = 98;
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- setButtonCtaVisible(false);
- setButtonNextVisible(false);
- setButtonBackVisible(false);
+ setButtonCtaVisible(false);
+ setButtonNextVisible(false);
+ setButtonBackVisible(false);
- setButtonCtaTintMode(BUTTON_CTA_TINT_MODE_TEXT);
+ setButtonCtaTintMode(BUTTON_CTA_TINT_MODE_TEXT);
- String title = String.format(getString(R.string.saf_guide_slide1_title), getString(R.string.app_name));
+ String title =
+ String.format(getString(R.string.saf_guide_slide1_title), getString(R.string.app_name));
- addSlide(new SimpleSlide.Builder()
- .title(title)
- .description(Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
- ? R.string.saf_guide_slide1_description_before_o : R.string.saf_guide_slide1_description)
- .image(R.drawable.saf_guide_1)
- .background(R.color.md_deep_purple_300)
- .backgroundDark(R.color.md_deep_purple_400)
- .layout(R.layout.fragment_simple_slide_large_image)
- .build());
- addSlide(new SimpleSlide.Builder()
- .title(R.string.saf_guide_slide2_title)
- .description(R.string.saf_guide_slide2_description)
- .image(R.drawable.saf_guide_2)
- .background(R.color.md_deep_purple_500)
- .backgroundDark(R.color.md_deep_purple_600)
- .layout(R.layout.fragment_simple_slide_large_image)
- .build());
- addSlide(new SimpleSlide.Builder()
- .title(R.string.saf_guide_slide3_title)
- .description(R.string.saf_guide_slide3_description)
- .image(R.drawable.saf_guide_3)
- .background(R.color.md_deep_purple_700)
- .backgroundDark(R.color.md_deep_purple_800)
- .layout(R.layout.fragment_simple_slide_large_image)
- .build());
- }
+ addSlide(
+ new SimpleSlide.Builder()
+ .title(title)
+ .description(
+ Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
+ ? R.string.saf_guide_slide1_description_before_o
+ : R.string.saf_guide_slide1_description)
+ .image(R.drawable.saf_guide_1)
+ .background(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 ed170e63b..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,75 +1,105 @@
+/*
+ * Copyright (c) 2020 Hemanth Savarla.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
package code.name.monkey.retromusic.activities.tageditor
import android.app.Activity
import android.app.SearchManager
import android.content.Intent
-import android.content.res.ColorStateList
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
-import android.os.Build
import android.os.Bundle
+import android.provider.MediaStore
import android.util.Log
+import android.view.LayoutInflater
import android.view.MenuItem
-import android.view.View
import android.view.animation.OvershootInterpolator
-import code.name.monkey.appthemehelper.ThemeStore
-import code.name.monkey.appthemehelper.util.ATHUtil
-import code.name.monkey.appthemehelper.util.ColorUtil
-import code.name.monkey.appthemehelper.util.MaterialValueHelper
-import code.name.monkey.appthemehelper.util.TintHelper
+import 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.R.drawable
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
-import code.name.monkey.retromusic.activities.saf.SAFGuideActivity
-import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.RetroUtil
-import code.name.monkey.retromusic.util.SAFUtil
-import com.afollestad.materialdialogs.LayoutMode
-import com.afollestad.materialdialogs.MaterialDialog
-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 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
+ lateinit var saveFab: MaterialButton
+ protected var id: Long = 0
private set
private var paletteColorPrimary: Int = 0
- private var isInNoImageMode: Boolean = false
private var songPaths: List? = null
- lateinit var saveFab: MaterialButton
-
private var savedSongPaths: List? = null
private val currentSongPath: String? = null
private var savedTags: Map? = null
private var savedArtworkInfo: ArtworkInfo? = null
+ private var _binding: VB? = null
+ protected val binding: VB get() = _binding!!
+ private var cacheFiles = listOf()
- protected 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()
+ abstract val bindingInflater: (LayoutInflater) -> VB
+
+ private lateinit var launcher: ActivityResultLauncher
+
+ 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()
+ }
}
- }
- }
- protected abstract val contentViewLayout: Int
+ .setNegativeButton(R.string.action_cancel, null)
+ .show()
+ .colorButtons()
internal val albumArtist: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
- } catch (ignored: Exception) {
+ } catch (e: Exception) {
+ logE(e)
null
}
}
@@ -78,7 +108,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TITLE)
- } catch (ignored: Exception) {
+ } catch (e: Exception) {
+ logE(e)
null
}
}
@@ -86,7 +117,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.COMPOSER)
- } catch (ignored: Exception) {
+ } catch (e: Exception) {
+ logE(e)
null
}
}
@@ -95,7 +127,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM)
- } catch (ignored: Exception) {
+ } catch (e: Exception) {
+ logE(e)
null
}
}
@@ -104,7 +137,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ARTIST)
- } catch (ignored: Exception) {
+ } catch (e: Exception) {
+ logE(e)
null
}
}
@@ -113,7 +147,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
- } catch (ignored: Exception) {
+ } catch (e: Exception) {
+ logE(e)
null
}
}
@@ -122,7 +157,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.GENRE)
- } catch (ignored: Exception) {
+ } catch (e: Exception) {
+ logE(e)
null
}
}
@@ -131,7 +167,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.YEAR)
- } catch (ignored: Exception) {
+ } catch (e: Exception) {
+ logE(e)
null
}
}
@@ -140,7 +177,18 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TRACK)
- } catch (ignored: Exception) {
+ } 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
}
}
@@ -149,7 +197,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.LYRICS)
- } catch (ignored: Exception) {
+ } catch (e: Exception) {
+ logE(e)
null
}
}
@@ -167,62 +216,58 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
)
}
return null
- } catch (ignored: Exception) {
+ } catch (e: Exception) {
+ logE(e)
return null
}
}
+ private val pickArtworkImage =
+ registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
+ loadImageFromFile(uri)
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(contentViewLayout)
+ _binding = bindingInflater.invoke(layoutInflater)
+ setContentView(binding.root)
+ setTaskDescriptionColorAuto()
saveFab = findViewById(R.id.saveTags)
getIntentExtras()
songPaths = getSongPaths()
+ logD(songPaths?.size)
if (songPaths!!.isEmpty()) {
finish()
- return
}
-
setUpViews()
-
- setStatusbarColorAuto()
- setNavigationbarColorAuto()
- setTaskDescriptionColorAuto()
+ launcher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) {
+ if (it.resultCode == Activity.RESULT_OK) {
+ writeToFiles(getSongUris(), cacheFiles)
+ }
+ }
}
private fun setUpViews() {
- setUpScrollView()
setUpFab()
setUpImageView()
}
- private fun setUpScrollView() {
- //observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
- }
-
private lateinit var items: List
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)
+ getString(R.string.pick_from_local_storage),
+ getString(R.string.web_search),
+ getString(R.string.remove_cover)
)
- editorImage?.setOnClickListener { show }
+ editorImage.setOnClickListener { show }
}
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
- )
+ pickArtworkImage.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
protected abstract fun loadCurrentImage()
@@ -232,26 +277,12 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
protected abstract fun deleteImage()
private fun setUpFab() {
- saveFab.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
- ColorStateList.valueOf(
- MaterialValueHelper.getPrimaryTextColor(
- this,
- ColorUtil.isColorLight(
- ThemeStore.accentColor(
- this
- )
- )
- )
- ).apply {
- saveFab.setTextColor(this)
- saveFab.iconTint = this
- }
+ saveFab.accentColor()
saveFab.apply {
scaleX = 0f
scaleY = 0f
isEnabled = false
setOnClickListener { save() }
- TintHelper.setTintAuto(this, ThemeStore.accentColor(this@AbsTagEditorActivity), true)
}
}
@@ -260,12 +291,14 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private fun getIntentExtras() {
val intentExtras = intent.extras
if (intentExtras != null) {
- id = intentExtras.getInt(EXTRA_ID)
+ id = intentExtras.getLong(EXTRA_ID)
}
}
protected abstract fun getSongPaths(): List
+ protected abstract fun getSongUris(): List
+
protected fun searchWebFor(vararg keys: String) {
val stringBuilder = StringBuilder()
for (key in keys) {
@@ -282,27 +315,13 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
- super.onBackPressed()
+ onBackPressedDispatcher.onBackPressed()
return true
}
}
return super.onOptionsItemSelected(item)
}
- protected fun setNoImageMode() {
- isInNoImageMode = true
- imageContainer?.visibility = View.GONE
- editorImage?.visibility = View.GONE
- editorImage?.isEnabled = false
-
- setColors(
- intent.getIntExtra(
- EXTRA_PALETTE,
- ATHUtil.resolveColor(this, R.attr.colorPrimary)
- )
- )
- }
-
protected fun dataChanged() {
showFab()
}
@@ -321,7 +340,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) {
if (bitmap == null) {
- editorImage.setImageResource(drawable.default_audio_art)
+ editorImage.setImageResource(R.drawable.default_audio_art)
} else {
editorImage.setImageBitmap(bitmap)
}
@@ -333,86 +352,106 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
}
protected fun writeValuesToFiles(
- fieldKeyValueMap: Map, artworkInfo: ArtworkInfo?
+ fieldKeyValueMap: Map,
+ artworkInfo: ArtworkInfo?
) {
- RetroUtil.hideSoftKeyboard(this)
+ hideSoftKeyboard()
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
+ logD(fieldKeyValueMap)
+ GlobalScope.launch {
+ if (VersionUtils.hasR()) {
+ cacheFiles = TagWriter.writeTagsToFilesR(
+ this@AbsTagEditorActivity, AudioTagInfo(
+ songPaths,
+ fieldKeyValueMap,
+ artworkInfo
)
+ )
+
+ if (cacheFiles.isNotEmpty()) {
+ val pendingIntent =
+ MediaStore.createWriteRequest(contentResolver, getSongUris())
+ launcher.launch(IntentSenderRequest.Builder(pendingIntent).build())
}
+ } else {
+ TagWriter.writeTagsToFiles(
+ this@AbsTagEditorActivity, AudioTagInfo(
+ songPaths,
+ fieldKeyValueMap,
+ artworkInfo
+ )
+ )
}
}
}
private fun writeTags(paths: List?) {
- WriteTagsAsyncTask(this).execute(
- WriteTagsAsyncTask.LoadingInfo(
- paths,
- savedTags,
- savedArtworkInfo
- )
- )
- }
+ GlobalScope.launch {
+ if (VersionUtils.hasR()) {
+ cacheFiles = TagWriter.writeTagsToFilesR(
+ this@AbsTagEditorActivity, AudioTagInfo(
+ paths,
+ savedTags,
+ savedArtworkInfo
+ )
+ )
+ val pendingIntent = MediaStore.createWriteRequest(contentResolver, getSongUris())
- 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))
- }
+ launcher.launch(IntentSenderRequest.Builder(pendingIntent).build())
+ } else {
+ TagWriter.writeTagsToFiles(
+ this@AbsTagEditorActivity, AudioTagInfo(
+ paths,
+ savedTags,
+ savedArtworkInfo
+ )
+ )
}
}
}
- protected abstract fun loadImageFromFile(selectedFile: Uri?)
+ private lateinit var audioFile: AudioFile
private fun getAudioFile(path: String): AudioFile {
return try {
- AudioFileIO.read(File(path))
+ if (!this::audioFile.isInitialized) {
+ audioFile = AudioFileIO.read(File(path))
+ }
+ audioFile
} catch (e: Exception) {
Log.e(TAG, "Could not read audio file $path", e)
AudioFile()
}
}
- class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?)
+ 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())
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ // Delete Cache Files
+ cacheFiles.forEach { file ->
+ file.delete()
+ }
+ }
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 b29684045..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,31 +22,36 @@ 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 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.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.model.ArtworkInfo
+import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.ImageUtil
+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 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 val bindingInflater: (LayoutInflater) -> ActivityAlbumTagEditorBinding =
+ ActivityAlbumTagEditorBinding::inflate
private fun windowEnterTransition() {
val slide = Slide()
@@ -44,54 +63,19 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
window.enterTransition = slide
}
- override fun loadImageFromFile(selectedFileUri: Uri?) {
-
- 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)
- }
-
- override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
- super.onLoadFailed(e, errorDrawable)
- Toast.makeText(this@AlbumTagEditorActivity, e.toString(), Toast.LENGTH_LONG)
- .show()
- }
- })
- }
-
private var albumArtBitmap: Bitmap? = null
private var deleteAlbumArt: Boolean = false
private fun setupToolbar() {
- toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
- setSupportActionBar(toolbar)
+ setSupportActionBar(binding.toolbar)
+ binding.appBarLayout?.statusBarForeground =
+ MaterialShapeDrawable.createWithElevationOverlay(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
- setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
window.sharedElementsUseOverlay = true
- imageContainer?.transitionName = "${getString(R.string.transition_album_art)}_$id"
+ binding.imageContainer.transitionName = getString(R.string.transition_album_art)
windowEnterTransition()
setUpViews()
setupToolbar()
@@ -100,22 +84,23 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
private fun setUpViews() {
fillViewsWithFileTags()
- MaterialUtil.setTint(yearContainer, false)
- MaterialUtil.setTint(genreContainer, false)
- MaterialUtil.setTint(albumTitleContainer, false)
- MaterialUtil.setTint(albumArtistContainer, false)
+ binding.yearContainer.setTint(false)
+ binding.genreContainer.setTint(false)
+ binding.albumTitleContainer.setTint(false)
+ binding.albumArtistContainer.setTint(false)
- albumText.appHandleColor().addTextChangedListener(this)
- albumArtistText.appHandleColor().addTextChangedListener(this)
- genreTitle.appHandleColor().addTextChangedListener(this)
- yearTitle.appHandleColor().addTextChangedListener(this)
+ binding.albumText.appHandleColor().doAfterTextChanged { dataChanged() }
+ binding.albumArtistText.appHandleColor().doAfterTextChanged { dataChanged() }
+ binding.genreTitle.appHandleColor().doAfterTextChanged { dataChanged() }
+ binding.yearTitle.appHandleColor().doAfterTextChanged { dataChanged() }
}
private fun fillViewsWithFileTags() {
- albumText.setText(albumTitle)
- albumArtistText.setText(albumArtistName)
- genreTitle.setText(genreName)
- yearTitle.setText(songYear)
+ binding.albumText.setText(albumTitle)
+ binding.albumArtistText.setText(albumArtistName)
+ binding.genreTitle.setText(genreName)
+ binding.yearTitle.setText(songYear)
+ logD(albumTitle + albumArtistName)
}
override fun loadCurrentImage() {
@@ -124,73 +109,109 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
bitmap,
getColor(
generatePalette(bitmap),
- ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
+ defaultFooterColor()
)
)
deleteAlbumArt = false
}
private fun toastLoadingFailed() {
- Toast.makeText(
- this@AlbumTagEditorActivity,
- R.string.could_not_download_album_cover,
- Toast.LENGTH_SHORT
- ).show()
+ showToast(R.string.could_not_download_album_cover)
}
override fun searchImageOnWeb() {
- searchWebFor(albumText.text.toString(), albumArtistText.text.toString())
+ searchWebFor(binding.albumText.text.toString(), binding.albumArtistText.text.toString())
}
override fun deleteImage() {
setImageBitmap(
BitmapFactory.decodeResource(resources, R.drawable.default_audio_art),
- ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
+ defaultFooterColor()
)
deleteAlbumArt = true
dataChanged()
}
+ 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)
+ }
+
+ override fun onLoadFailed(errorDrawable: Drawable?) {
+ super.onLoadFailed(errorDrawable)
+ showToast(R.string.error_load_failed, Toast.LENGTH_LONG)
+ }
+
+ override fun setResource(resource: BitmapPaletteWrapper?) {}
+ })
+ }
+
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()
+ 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()
writeValuesToFiles(
fieldKeyValueMap,
- if (deleteAlbumArt) ArtworkInfo(id, null)
- else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)
+ when {
+ deleteAlbumArt -> ArtworkInfo(id, null)
+ albumArtBitmap == null -> null
+ else -> ArtworkInfo(id, albumArtBitmap!!)
+ }
)
}
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
+ return repository.albumById(id).songs
+ .map(Song::data)
}
- 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 getSongUris(): List = repository.albumById(id).songs.map {
+ MusicUtil.getSongFileUri(it.id)
}
override fun setColors(color: Int) {
super.setColors(color)
saveFab.backgroundTintList = ColorStateList.valueOf(color)
+ saveFab.backgroundTintList = ColorStateList.valueOf(color)
+ ColorStateList.valueOf(
+ MaterialValueHelper.getPrimaryTextColor(
+ this,
+ color.isColorLight
+ )
+ ).also {
+ saveFab.iconTint = it
+ saveFab.setTextColor(it)
+ }
}
+
+ override val editorImage: ImageView
+ get() = binding.editorImage
+
companion object {
val TAG: String = AlbumTagEditorActivity::class.java.simpleName
diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt
index d99bb70cd..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,112 +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.ATHUtil
-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.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()
- toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
- setSupportActionBar(toolbar)
+ 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 beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
- }
+ override fun onLoadFailed(errorDrawable: Drawable?) {
+ super.onLoadFailed(errorDrawable)
+ showToast(R.string.error_load_failed, Toast.LENGTH_LONG)
+ }
- 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 81a8a7a59..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/WriteTagsAsyncTask.java
+++ /dev/null
@@ -1,193 +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);
- }
-
- @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 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 onCancelled(String[] toBeScanned) {
- super.onCancelled(toBeScanned);
- scan(toBeScanned);
- }
-
- @Override
- protected void onPostExecute(String[] toBeScanned) {
- super.onPostExecute(toBeScanned);
- scan(toBeScanned);
- }
-
- @Override
- protected void onProgressUpdate(@NonNull Dialog dialog, Integer... values) {
- super.onProgressUpdate(dialog, values);
- //((MaterialDialog) dialog).setMaxProgress(values[1]);
- //((MaterialDialog) dialog).setProgress(values[0]);
- }
-
- private void scan(String[] toBeScanned) {
- Activity activity = this.activity.get();
- if (activity != null) {
- MediaScannerConnection.scanFile(activity, toBeScanned, null,
- new UpdateToastMediaScannerCompletionListener(activity, toBeScanned));
- }
- }
-
- public static class LoadingInfo {
-
- @Nullable
- final Map fieldKeyValueMap;
-
- final Collection filePaths;
-
- @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 426eafb1f..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java
+++ /dev/null
@@ -1,141 +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);
- }
-
- public void attachToRecyclerView(RecyclerView recyclerView) {
- touchHelper.attachToRecyclerView(recyclerView);
- }
-
- @NonNull
- public List getCategoryInfos() {
- return categoryInfos;
- }
-
- public void setCategoryInfos(@NonNull List categoryInfos) {
- this.categoryInfos = categoryInfos;
- notifyDataSetChanged();
- }
-
- @Override
- public int getItemCount() {
- return categoryInfos.size();
- }
-
- @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
- @NonNull
- public CategoryInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- View view = LayoutInflater.from(parent.getContext())
- .inflate(R.layout.preference_dialog_library_categories_listitem, parent, false);
- return new ViewHolder(view);
- }
-
- @Override
- public void onViewMoved(int oldPosition, int newPosition) {
- CategoryInfo categoryInfo = categoryInfos.get(oldPosition);
- categoryInfos.remove(oldPosition);
- categoryInfos.add(newPosition, categoryInfo);
- notifyItemMoved(oldPosition, newPosition);
- }
-
- 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;
-
- View dragView;
-
- TextView title;
-
- ViewHolder(View view) {
- super(view);
- checkBox = view.findViewById(R.id.checkbox);
- checkBox.setButtonTintList(
- ColorStateList.valueOf(ThemeStore.Companion.accentColor(checkBox.getContext())));
- title = view.findViewById(R.id.title);
- dragView = view.findViewById(R.id.drag_view);
- }
- }
-}
\ 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 dcd0f7bd0..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-package code.name.monkey.retromusic.adapter
-
-import android.app.Activity
-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 code.name.monkey.retromusic.model.Contributor
-import code.name.monkey.retromusic.util.RetroUtil.openUrl
-import code.name.monkey.retromusic.views.RetroShapeableImageView
-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: RetroShapeableImageView = itemView.findViewById(R.id.icon)
-
- internal fun bindData(contributor: Contributor) {
- title.text = contributor.name
- text.text = contributor.summary
- 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 570912a30..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,41 +39,74 @@ import java.util.*
*/
class GenreAdapter(
- private val activity: Activity,
+ private val activity: FragmentActivity,
var dataSet: List,
- private val mItemLayoutRes: Int
+ private val listener: IGenreClickListener
) : RecyclerView.Adapter() {
+ init {
+ 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(
+ 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
}
+ @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[layoutPosition]
- 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 c186a14b7..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,31 +1,47 @@
+/*
+ * 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 = listOf()
@@ -34,44 +50,75 @@ class HomeAdapter(
}
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) {
+ 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)
+ )
+ }
}
}
}
@@ -80,102 +127,87 @@ class HomeAdapter(
return list.size
}
+ @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 =
- LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
- val artistAdapter = ArtistAdapter(
- activity,
- list,
- PreferenceUtil.getInstance(activity).getHomeGridStyle(activity),
- 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, 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 0b257978d..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,122 +1,176 @@
+/*
+ * 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.AlbumGlideRequest
-import code.name.monkey.retromusic.glide.ArtistGlideRequest
+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.loaders.PlaylistSongsLoader
-import code.name.monkey.retromusic.model.*
-import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
+import code.name.monkey.retromusic.model.Album
+import code.name.monkey.retromusic.model.Artist
+import code.name.monkey.retromusic.model.Genre
+import code.name.monkey.retromusic.model.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
- if (dataSet!![position] is Playlist) return PLAYLIST
- 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(
+ 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
- AlbumGlideRequest.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?.get(position) as Playlist
- holder.title?.text = playlist.name
- holder.text?.text = MusicUtil.getPlaylistInfoString(activity, getSongs(playlist))
+ val playlist = dataSet[position] as PlaylistWithSongs
+ holder.title?.text = playlist.playlistEntity.playlistName
+ //holder.text?.text = MusicUtil.playlistInfoString(activity, playlist.songs)
}
+
+ 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))
}
}
}
- private fun getSongs(playlist: Playlist): java.util.ArrayList {
- val songs = java.util.ArrayList()
- if (playlist is AbsSmartPlaylist) {
- songs.addAll(playlist.getSongs(activity))
- } else {
- songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
- }
- return songs
- }
-
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!![layoutPosition] as Song
+ get() = dataSet[layoutPosition] as Song
})
} else {
- menu?.visibility = View.GONE
+ menu?.isVisible = false
}
when (itemViewType) {
@@ -124,38 +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!![layoutPosition]
+ val item = dataSet[layoutPosition]
when (itemViewType) {
ALBUM -> {
- val options = ActivityOptions.makeSceneTransitionAnimation(
- activity,
- UtilPair.create(image, activity.getString(R.string.transition_album_art))
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.albumDetailsFragment,
+ bundleOf(EXTRA_ALBUM_ID to (item as Album).id)
)
- NavigationUtil.goToAlbumOptions(activity, (item as Album).id, options)
}
+
ARTIST -> {
- val options = ActivityOptions.makeSceneTransitionAnimation(
- activity,
- UtilPair.create(image, activity.getString(R.string.transition_artist_image))
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.artistDetailsFragment,
+ bundleOf(EXTRA_ARTIST_ID to (item as Artist).id)
)
- NavigationUtil.goToArtistOptions(activity, (item as Artist).id, options)
}
+
+ ALBUM_ARTIST -> {
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.albumArtistDetailsFragment,
+ bundleOf(EXTRA_ARTIST_NAME to (item as Artist).name)
+ )
+ }
+
GENRE -> {
- NavigationUtil.goToGenre(activity, item as Genre)
+ activity.findNavController(R.id.fragment_container).navigate(
+ R.id.genreDetailsFragment,
+ bundleOf(EXTRA_GENRE to (item as Genre))
+ )
}
+
PLAYLIST -> {
- NavigationUtil.goToPlaylistNew(activity, item as 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()
}
}
}
@@ -168,5 +236,6 @@ class SearchAdapter(
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 4909ad372..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,32 +20,31 @@ 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.interfaces.ICallbacks
import code.name.monkey.retromusic.util.MusicUtil
-import code.name.monkey.retromusic.util.RetroUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.MediaStoreSignature
import me.zhanghai.android.fastscroll.PopupTextProvider
import java.io.File
import java.text.DecimalFormat
-import java.util.*
import kotlin.math.log10
import kotlin.math.pow
class SongFileAdapter(
- private val activity: AppCompatActivity,
+ override val activity: AppCompatActivity,
private var dataSet: List,
private val itemLayoutRes: Int,
- private val callbacks: Callbacks?,
- cabHolder: CabHolder?
+ private val iCallbacks: ICallbacks?
) : AbsMultiSelectAdapter(
- activity, cabHolder, R.menu.menu_media_selection
+ activity, R.menu.menu_media_selection
), PopupTextProvider {
init {
@@ -63,7 +76,7 @@ class SongFileAdapter(
if (holder.itemViewType == FILE) {
holder.text?.text = getFileText(file)
} else {
- holder.text?.visibility = View.GONE
+ holder.text?.isVisible = false
}
}
@@ -81,30 +94,28 @@ 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
+ com.google.android.material.R.attr.colorSurface
)
)
} else {
- val error = RetroUtil.getTintedVectorDrawable(
- activity, R.drawable.ic_file_music_white_24dp, iconColor
- )
+ val error = activity.getTintedDrawable(R.drawable.ic_audio_file, iconColor)
Glide.with(activity)
.load(AudioFileCover(file.path))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.error(error)
.placeholder(error)
- .animate(android.R.anim.fade_in)
+ .transition(RetroGlideExtension.getDefaultTransition())
.signature(MediaStoreSignature("", file.lastModified(), 0))
- .into(holder.image)
+ .into(holder.image!!)
}
}
@@ -112,43 +123,35 @@ class SongFileAdapter(
return dataSet.size
}
- override fun getIdentifier(position: Int): File? {
+ 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 getPopupText(position: Int): String {
- return getSectionName(position)
+ return if (position >= dataSet.lastIndex) "" else getSectionName(position)
}
private fun getSectionName(position: Int): String {
return MusicUtil.getSectionName(dataSet[position].name)
}
- interface Callbacks {
- fun onFileSelected(file: File)
-
- fun onFileMenuClicked(file: File, view: View)
-
- fun onMultipleItemAction(item: MenuItem, files: ArrayList)
- }
-
- inner class ViewHolder(itemView: View) : 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 = layoutPosition
if (isPositionInRange(position)) {
- callbacks.onFileMenuClicked(dataSet[position], v)
+ iCallbacks.onFileMenuClicked(dataSet[position], v)
}
}
}
@@ -163,7 +166,7 @@ class SongFileAdapter(
if (isInQuickSelectMode) {
toggleChecked(position)
} else {
- callbacks?.onFileSelected(dataSet[position])
+ iCallbacks?.onFileSelected(dataSet[position])
}
}
}
@@ -190,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/TranslatorsAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/TranslatorsAdapter.kt
deleted file mode 100644
index 90585c364..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/TranslatorsAdapter.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-package code.name.monkey.retromusic.adapter
-
-import android.app.Activity
-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 code.name.monkey.retromusic.extensions.hide
-import code.name.monkey.retromusic.model.Contributor
-import code.name.monkey.retromusic.util.RetroUtil
-import code.name.monkey.retromusic.views.RetroShapeableImageView
-
-class TranslatorsAdapter(
- private var contributors: List
-) : RecyclerView.Adapter() {
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- return ViewHolder(
- LayoutInflater.from(parent.context).inflate(
- R.layout.item_contributor,
- parent,
- false
- )
- )
- }
-
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val contributor = contributors[position]
- holder.bindData(contributor)
- holder.itemView.setOnClickListener {
- RetroUtil.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: RetroShapeableImageView = itemView.findViewById(R.id.icon)
-
- internal fun bindData(contributor: Contributor) {
- title.text = contributor.name
- text.text = contributor.summary
- image.hide()
- }
- }
-}
\ 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 4cdd335b2..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,40 +1,51 @@
+/*
+ * 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.AlbumGlideRequest
+import code.name.monkey.retromusic.glide.RetroGlideExtension
+import code.name.monkey.retromusic.glide.RetroGlideExtension.albumCoverOptions
+import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
-import code.name.monkey.retromusic.helper.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 me.zhanghai.android.fastscroll.PopupTextProvider
open class AlbumAdapter(
- protected val activity: AppCompatActivity,
+ override val activity: FragmentActivity,
var dataSet: List,
- protected var itemLayoutRes: Int,
- cabHolder: CabHolder?
+ var itemLayoutRes: Int,
+ val listener: IAlbumClickListener?
) : AbsMultiSelectAdapter(
activity,
- cabHolder,
R.menu.menu_media_selection
), PopupTextProvider {
@@ -56,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) {
@@ -70,54 +87,39 @@ 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
}
-
- AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
- .checkIgnoreMediaStore(activity)
- .generatePalette(activity)
- .build()
+ val song = album.safeGetFirstSong()
+ Glide.with(activity)
+ .asBitmapPalette()
+ .albumCoverOptions(song)
+ //.checkIgnoreMediaStore()
+ .load(RetroGlideExtension.getSongModel(song))
.into(object : RetroMusicColoredTarget(holder.image!!) {
- override fun onLoadCleared(placeholder: Drawable?) {
- super.onLoadCleared(placeholder)
- //setColors(defaultFooterColor, holder)
- }
-
- override fun onColorReady(color: Int) {
- setColors(color, holder)
+ override fun onColorReady(colors: MediaNotificationProcessor) {
+ setColors(colors, holder)
}
})
}
@@ -127,27 +129,28 @@ 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
}
@@ -158,23 +161,22 @@ open class AlbumAdapter(
private fun getSectionName(position: Int): String {
var sectionName: String? = null
- when (PreferenceUtil.getInstance(activity).albumSortOrder) {
+ when (PreferenceUtil.albumSortOrder) {
SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName =
dataSet[position].title
- SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].artistName
+
+ SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].albumArtist
SortOrder.AlbumSortOrder.ALBUM_YEAR -> return MusicUtil.getYearString(
dataSet[position].year
)
}
-
return MusicUtil.getSectionName(sectionName)
}
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init {
- setImageTransitionName(activity.getString(R.string.transition_album_art))
- menu?.visibility = View.GONE
+ menu?.isVisible = false
}
override fun onClick(v: View?) {
@@ -182,22 +184,14 @@ open class AlbumAdapter(
if (isInQuickSelectMode) {
toggleChecked(layoutPosition)
} else {
- val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
- activity,
- imageContainerCard ?: image,
- "${activity.getString(R.string.transition_album_art)}_${dataSet[layoutPosition].id}"
- )
- NavigationUtil.goToAlbumOptions(
- activity,
- dataSet[layoutPosition].id,
- activityOptions
- )
+ image?.let {
+ listener?.onAlbumClick(dataSet[layoutPosition].id, imageContainer ?: it)
+ }
}
}
override fun onLongClick(v: View?): Boolean {
- toggleChecked(layoutPosition)
- 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 441a65884..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,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.album
import android.os.Bundle
@@ -5,22 +19,35 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
+import androidx.core.os.BundleCompat
+import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
+import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.fragments.AlbumCoverStyle
+import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
+import code.name.monkey.retromusic.fragments.base.goToLyrics
+import code.name.monkey.retromusic.glide.RetroGlideExtension
+import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
+import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
-import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter
import code.name.monkey.retromusic.model.Song
-import code.name.monkey.retromusic.util.NavigationUtil
+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(
fragmentManager: FragmentManager,
- private val dataSet: ArrayList
+ private val dataSet: List
) : CustomFragmentStatePagerAdapter(fragmentManager) {
private var currentColorReceiver: AlbumCoverFragment.ColorReceiver? = null
@@ -61,31 +88,17 @@ class AlbumCoverPagerAdapter(
class AlbumCoverFragment : Fragment() {
- lateinit var albumCover: ImageView
private var isColorReady: Boolean = false
- private var color: Int = 0
+ private lateinit var color: MediaNotificationProcessor
private lateinit var song: Song
private var colorReceiver: ColorReceiver? = null
private var request: Int = 0
-
- private val layout: Int
- get() {
- return when (PreferenceUtil.getInstance(requireContext()).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
- }
- }
+ private val mainActivity get() = activity as MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (arguments != null) {
- song = requireArguments().getParcelable(SONG_ARG)!!
+ song = BundleCompat.getParcelable(requireArguments(), SONG_ARG, Song::class.java)!!
}
}
@@ -94,21 +107,58 @@ class AlbumCoverPagerAdapter(
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- val finalLayout = when {
- PreferenceUtil.getInstance(requireContext()).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 {
- NavigationUtil.goToLyrics(requireActivity())
+ val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
+ view.setOnClickListener {
+ if (mainActivity.getBottomSheetBehavior().state == STATE_EXPANDED) {
+ showLyricsDialog()
+ }
}
return view
}
+ private fun showLyricsDialog() {
+ lifecycleScope.launch(Dispatchers.IO) {
+ val data: String? = MusicUtil.getLyrics(song)
+ withContext(Dispatchers.Main) {
+ MaterialAlertDialogBuilder(
+ requireContext(),
+ com.google.android.material.R.style.ThemeOverlay_MaterialComponents_Dialog_Alert
+ ).apply {
+ setTitle(song.title)
+ setMessage(if (data.isNullOrEmpty()) "No lyrics found" else data)
+ setNegativeButton(R.string.synced_lyrics) { _, _ ->
+ goToLyrics(requireActivity())
+ }
+ show()
+ }
+ }
+ }
+ }
+
+ private fun getLayoutWithPlayerTheme(): Int {
+ return when (PreferenceUtil.nowPlayingScreen) {
+ Card, Fit, Tiny, Classic, Gradient, Full -> R.layout.fragment_album_full_cover
+ Peek -> R.layout.fragment_peek_album_cover
+ else -> {
+ if (PreferenceUtil.isCarouselEffect) {
+ R.layout.fragment_album_carousel_cover
+ } else {
+ when (PreferenceUtil.albumCoverStyle) {
+ AlbumCoverStyle.Normal -> R.layout.fragment_album_cover
+ AlbumCoverStyle.Flat -> R.layout.fragment_album_flat_cover
+ AlbumCoverStyle.Circle -> R.layout.fragment_album_circle_cover
+ AlbumCoverStyle.Card -> R.layout.fragment_album_card_cover
+ AlbumCoverStyle.Full -> R.layout.fragment_album_full_cover
+ AlbumCoverStyle.FullCard -> R.layout.fragment_album_full_card_cover
+ }
+ }
+ }
+ }
+ }
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- loadAlbumCover()
+ loadAlbumCover(albumCover = view.findViewById(R.id.player_image))
}
override fun onDestroyView() {
@@ -116,18 +166,21 @@ class AlbumCoverPagerAdapter(
colorReceiver = null
}
- private fun loadAlbumCover() {
- SongGlideRequest.Builder.from(Glide.with(requireContext()), song)
- .checkIgnoreMediaStore(requireContext())
- .generatePalette(requireContext()).build()
+ private fun loadAlbumCover(albumCover: ImageView) {
+ Glide.with(this)
+ .asBitmapPalette()
+ .songCoverOptions(song)
+ //.checkIgnoreMediaStore()
+ .load(RetroGlideExtension.getSongModel(song))
+ .dontAnimate()
.into(object : RetroMusicColoredTarget(albumCover) {
- override fun onColorReady(color: Int) {
- setColor(color)
+ override fun onColorReady(colors: MediaNotificationProcessor) {
+ setColor(colors)
}
})
}
- private fun setColor(color: Int) {
+ private fun setColor(color: MediaNotificationProcessor) {
this.color = color
isColorReady = true
if (colorReceiver != null) {
@@ -146,7 +199,7 @@ class AlbumCoverPagerAdapter(
}
interface ColorReceiver {
- fun onColorReady(color: Int, request: Int)
+ fun onColorReady(color: MediaNotificationProcessor, request: Int)
}
companion object {
@@ -155,9 +208,7 @@ class AlbumCoverPagerAdapter(
fun newInstance(song: Song): AlbumCoverFragment {
val frag = AlbumCoverFragment()
- val args = Bundle()
- args.putParcelable(SONG_ARG, song)
- frag.arguments = args
+ frag.arguments = bundleOf(SONG_ARG to song)
return frag
}
}
@@ -167,4 +218,3 @@ class AlbumCoverPagerAdapter(
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 8c3b9df8e..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumFullWidthAdapter.kt
+++ /dev/null
@@ -1,105 +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.Activity
-import android.app.ActivityOptions
-import android.util.DisplayMetrics
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.glide.AlbumGlideRequest
-import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
-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: List,
- 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
- }
- AlbumGlideRequest.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,
- imageContainerCard ?: image,
- "${activity.getString(R.string.transition_album_art)}_${dataSet[layoutPosition].id}"
- )
- NavigationUtil.goToAlbumOptions(activity, dataSet[layoutPosition].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 e81502135..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,24 +1,39 @@
+/*
+ * 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.ATHUtil
-import code.name.monkey.retromusic.glide.AlbumGlideRequest
+import androidx.fragment.app.FragmentActivity
+import code.name.monkey.retromusic.glide.RetroGlideExtension
+import code.name.monkey.retromusic.glide.RetroGlideExtension.albumCoverOptions
+import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.HorizontalAdapterHelper
-import code.name.monkey.retromusic.interfaces.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
class HorizontalAlbumAdapter(
- activity: AppCompatActivity,
+ activity: FragmentActivity,
dataSet: List,
- cabHolder: CabHolder?
+ albumClickListener: IAlbumClickListener
) : AlbumAdapter(
- activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, cabHolder
+ activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, albumClickListener
) {
override fun createViewHolder(view: View, viewType: Int): ViewHolder {
@@ -27,35 +42,30 @@ class HorizontalAlbumAdapter(
return ViewHolder(view)
}
- override fun setColors(color: Int, holder: ViewHolder) {
- holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
- holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
+ 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
- AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
- .checkIgnoreMediaStore(activity)
- .generatePalette(activity)
- .build()
+ Glide.with(activity)
+ .asBitmapPalette()
+ .albumCoverOptions(album.safeGetFirstSong())
+ .load(RetroGlideExtension.getSongModel(album.safeGetFirstSong()))
.into(object : RetroMusicColoredTarget(holder.image!!) {
- override fun onLoadCleared(placeholder: Drawable?) {
- super.onLoadCleared(placeholder)
- setColors(albumArtistFooterColor, holder)
- }
-
- override fun onColorReady(color: Int) {
- setColors(color, holder)
+ override fun onColorReady(colors: MediaNotificationProcessor) {
+ setColors(colors, holder)
}
})
}
- override fun getAlbumText(album: Album): String? {
+ override fun getAlbumText(album: Album): String {
return MusicUtil.getYearString(album.year)
}
override fun getItemViewType(position: Int): Int {
- return HorizontalAdapterHelper.getItemViewtype(position, itemCount)
+ return HorizontalAdapterHelper.getItemViewType(position, itemCount)
}
override fun getItemCount(): Int {
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 e54aa8332..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,55 +1,79 @@
+/*
+ * 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.content.res.Resources
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.extensions.hide
-import code.name.monkey.retromusic.glide.ArtistGlideRequest
+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.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.NavigationUtil
+import code.name.monkey.retromusic.util.PreferenceUtil
+import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import me.zhanghai.android.fastscroll.PopupTextProvider
-import java.util.*
class ArtistAdapter(
- val activity: AppCompatActivity,
+ override val activity: FragmentActivity,
var dataSet: List,
var itemLayoutRes: Int,
- cabHolder: CabHolder?
-) : AbsMultiSelectAdapter(
- activity, cabHolder, R.menu.menu_media_selection
-), PopupTextProvider {
+ val IArtistClickListener: IArtistClickListener,
+ val IAlbumArtistClickListener: IAlbumArtistClickListener? = null
+) : AbsMultiSelectAdapter(activity, R.menu.menu_media_selection),
+ PopupTextProvider {
+
+ var albumArtistsOnly = false
init {
this.setHasStableIds(true)
}
+ @SuppressLint("NotifyDataSetChanged")
fun swapDataSet(dataSet: List) {
this.dataSet = dataSet
notifyDataSetChanged()
+ albumArtistsOnly = PreferenceUtil.albumArtistsOnly
}
override fun getItemId(position: Int): Long {
- return dataSet[position].id.toLong()
+ return dataSet[position].id
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
+ 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)
}
@@ -63,39 +87,37 @@ class ArtistAdapter(
holder.itemView.isActivated = isChecked
holder.title?.text = artist.name
holder.text?.hide()
+ val transitionName =
+ if (albumArtistsOnly) artist.name else artist.id.toString()
+ if (holder.imageContainer != null) {
+ holder.imageContainer?.transitionName = transitionName
+ } else {
+ holder.image?.transitionName = transitionName
+ }
loadArtistImage(artist, holder)
}
- fun setColors(color: Int, holder: ViewHolder) {
+ private fun setColors(processor: MediaNotificationProcessor, holder: ViewHolder) {
+ holder.mask?.backgroundTintList = ColorStateList.valueOf(processor.primaryTextColor)
if (holder.paletteColorContainer != null) {
- holder.paletteColorContainer?.setBackgroundColor(color)
- holder.title?.setTextColor(
- MaterialValueHelper.getPrimaryTextColor(
- activity, ColorUtil.isColorLight(
- color
- )
- )
- )
+ holder.paletteColorContainer?.setBackgroundColor(processor.backgroundColor)
+ holder.title?.setTextColor(processor.primaryTextColor)
}
- holder.imageContainerCard?.setCardBackgroundColor(color)
- holder.mask?.backgroundTintList = ColorStateList.valueOf(color)
+ 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()
+ Glide.with(activity)
+ .asBitmapPalette()
+ .artistImageOptions(artist)
+ .load(RetroGlideExtension.getArtistModel(artist))
+ .transition(RetroGlideExtension.getDefaultTransition())
.into(object : RetroMusicColoredTarget(holder.image!!) {
- override fun onLoadCleared(placeholder: Drawable?) {
- super.onLoadCleared(placeholder)
- setColors(defaultFooterColor, holder)
- }
-
- override fun onColorReady(color: Int) {
- setColors(color, holder)
+ override fun onColorReady(colors: MediaNotificationProcessor) {
+ setColors(colors, holder)
}
})
}
@@ -104,21 +126,22 @@ class ArtistAdapter(
return dataSet.size
}
- override fun getIdentifier(position: Int): Artist? {
+ override fun getIdentifier(position: Int): Artist {
return dataSet[position]
}
- override fun getName(artist: Artist): String {
- return artist.name
+ override fun getName(model: Artist): String {
+ return model.name
}
override fun onMultipleItemAction(
- menuItem: MenuItem, selection: ArrayList
+ menuItem: MenuItem,
+ selection: List
) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
}
- private fun getSongList(artists: List): ArrayList {
+ private fun getSongList(artists: List): List {
val songs = ArrayList()
for (artist in artists) {
songs.addAll(artist.songs) // maybe async in future?
@@ -134,11 +157,10 @@ class ArtistAdapter(
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
+ menu?.isVisible = false
}
override fun onClick(v: View?) {
@@ -146,20 +168,19 @@ class ArtistAdapter(
if (isInQuickSelectMode) {
toggleChecked(layoutPosition)
} else {
- val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
- activity,
- imageContainerCard ?: image,
- "${activity.getString(R.string.transition_artist_image)}_${dataSet[layoutPosition].id}"
- )
- NavigationUtil.goToArtistOptions(
- activity, dataSet[layoutPosition].id, activityOptions
- )
+ 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(layoutPosition)
- return super.onLongClick(v)
+ 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 f98fa1110..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.java
+++ /dev/null
@@ -1,133 +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;
- }
-
- @Override
- public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
- return true;
- }
-
- @Override
- public boolean onCabFinished(MaterialCab materialCab) {
- clearChecked();
- return true;
- }
-
- @Override
- public boolean onCabItemClicked(MenuItem menuItem) {
- if (menuItem.getItemId() == R.id.action_multi_select_adapter_check_all) {
- checkAll();
- } else {
- onMultipleItemAction(menuItem, new ArrayList<>(checked));
- cab.finish();
- clearChecked();
- }
- return true;
- }
-
- protected void checkAll() {
- if (cabHolder != null) {
- checked.clear();
- for (int i = 0; i < getItemCount(); i++) {
- I identifier = getIdentifier(i);
- if (identifier != null) {
- checked.add(identifier);
- }
- }
- notifyDataSetChanged();
- updateCab();
- }
- }
-
- @Nullable
- protected abstract I getIdentifier(int position);
-
- protected String getName(I object) {
- return object.toString();
- }
-
- protected boolean isChecked(I identifier) {
- return checked.contains(identifier);
- }
-
- protected boolean isInQuickSelectMode() {
- return cab != null && cab.isActive();
- }
-
- protected abstract void onMultipleItemAction(MenuItem menuItem, ArrayList selection);
-
- 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;
- }
-
- private void clearChecked() {
- checked.clear();
- notifyDataSetChanged();
- }
-
- 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));
- }
- }
- }
-}
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 42a76d011..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
@@ -16,14 +16,13 @@ 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;
@@ -42,15 +41,12 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
@Nullable
public ImageView image;
- @Nullable
- public ImageView playerImage;
-
- @Nullable
- public ViewGroup imageContainer;
-
@Nullable
public MaterialCardView imageContainerCard;
+ @Nullable
+ public FrameLayout imageContainer;
+
@Nullable
public TextView imageText;
@@ -61,20 +57,17 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
public View mask;
@Nullable
- public View menu;
+ public AppCompatImageView menu;
@Nullable
public View paletteColorContainer;
- @Nullable
- public ImageButton playSongs;
-
- @Nullable
- public RecyclerView recyclerView;
-
@Nullable
public TextView text;
+ @Nullable
+ public TextView text2;
+
@Nullable
public TextView time;
@@ -85,22 +78,20 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
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);
- playerImage = itemView.findViewById(R.id.player_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) {
@@ -110,6 +101,7 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
itemView.setOnLongClickListener(this);
}
+ @Nullable
@Override
public View getSwipeableContainerView() {
return null;
@@ -117,7 +109,6 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
@Override
public void onClick(View v) {
-
}
@Override
@@ -126,11 +117,12 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
}
public void setImageTransitionName(@NonNull String transitionName) {
- if (imageContainerCard != null) {
- imageContainerCard.setTransitionName(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 a550a1fb3..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,64 +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.Bitmap
import android.graphics.Color
import android.graphics.drawable.Drawable
-import android.os.AsyncTask
-import android.text.TextUtils
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
-import androidx.appcompat.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.extensions.hide
-import code.name.monkey.retromusic.extensions.show
+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.AutoGeneratedPlaylistBitmap
import code.name.monkey.retromusic.util.MusicUtil
-import code.name.monkey.retromusic.util.NavigationUtil
-import code.name.monkey.retromusic.util.RetroColorUtil
-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: List,
+ override val activity: FragmentActivity,
+ var dataSet: List,
private var itemLayoutRes: Int,
- cabHolder: CabHolder?
-) : AbsMultiSelectAdapter(
+ private val listener: IPlaylistClickListener
+) : AbsMultiSelectAdapter(
activity,
- cabHolder,
R.menu.menu_playlists_selection
-) {
-
+), PopupTextProvider {
init {
setHasStableIds(true)
}
- fun swapDataSet(dataSet: List) {
+ 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 {
@@ -66,83 +72,66 @@ class PlaylistAdapter(
return createViewHolder(view)
}
- fun createViewHolder(view: View): ViewHolder {
+ private fun createViewHolder(view: View): ViewHolder {
return ViewHolder(view)
}
- private fun getPlaylistTitle(playlist: Playlist): String {
- return if (TextUtils.isEmpty(playlist.name)) "-" else playlist.name
+ private fun getPlaylistTitle(playlist: PlaylistEntity): String {
+ return playlist.playlistName.ifEmpty { "-" }
}
- private 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))
- val isChecked = isChecked(playlist)
- if (isChecked) {
- holder.menu?.hide()
+ holder.menu?.isGone = isChecked(playlist)
+ if (itemLayoutRes == R.layout.item_list) {
+ holder.image?.setPadding(activity.dipToPix(8F).toInt())
+ holder.image?.setImageDrawable(getIconRes())
} else {
- holder.menu?.show()
+ Glide.with(activity)
+ .load(PlaylistPreview(playlist))
+ .playlistOptions()
+ .into(holder.image!!)
}
- //PlaylistBitmapLoader(this, holder, playlist).execute()
}
- 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),
@@ -151,60 +140,21 @@ class PlaylistAdapter(
}
}
- private fun getSongList(playlists: List): ArrayList {
- val songs = ArrayList()
- for (playlist in playlists) {
- if (playlist is AbsCustomPlaylist) {
- songs.addAll(playlist.getSongs(activity))
- } else {
- songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
- }
+ private fun getSongList(playlists: List): List {
+ val songs = mutableListOf()
+ playlists.forEach {
+ songs.addAll(it.songs.toSongs())
}
return songs
}
- private fun getSongs(playlist: Playlist): ArrayList {
- val songs = ArrayList()
- if (playlist is AbsSmartPlaylist) {
- songs.addAll(playlist.getSongs(activity))
- } else {
- songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
- }
- return songs
- }
-
- inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
+ inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) {
init {
-
- image?.apply {
- val iconPadding =
- activity.resources.getDimensionPixelSize(R.dimen.list_item_image_icon_padding)
- setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
- }
-
menu?.setOnClickListener { view ->
- val playlist = dataSet[layoutPosition]
val popupMenu = PopupMenu(activity, view)
- popupMenu.inflate(
- if (itemViewType == SMART_PLAYLIST) R.menu.menu_item_smart_playlist
- else R.menu.menu_item_playlist
- )
- if (playlist is LastAddedPlaylist) {
- popupMenu.menu.findItem(R.id.action_clear_playlist).isVisible = false
- }
+ popupMenu.inflate(R.menu.menu_item_playlist)
popupMenu.setOnMenuItemClickListener { item ->
- if (item.itemId == R.id.action_clear_playlist) {
- if (playlist is AbsSmartPlaylist) {
- ClearSmartPlaylistDialog.create(playlist).show(
- activity.supportFragmentManager,
- "CLEAR_SMART_PLAYLIST_" + playlist.name
- )
- return@setOnMenuItemClickListener true
- }
- }
- PlaylistMenuHelper.handleMenuClick(
- activity, dataSet[layoutPosition], item
- )
+ PlaylistMenuHelper.handleMenuClick(activity, dataSet[layoutPosition], item)
}
popupMenu.show()
}
@@ -219,8 +169,8 @@ class PlaylistAdapter(
if (isInQuickSelectMode) {
toggleChecked(layoutPosition)
} else {
- val playlist = dataSet[layoutPosition]
- NavigationUtil.goToPlaylistNew(activity, playlist)
+ itemView.transitionName = "playlist"
+ listener.onPlaylistClick(dataSet[layoutPosition], itemView)
}
}
@@ -230,33 +180,7 @@ class PlaylistAdapter(
}
}
- class PlaylistBitmapLoader(
- private var adapter: PlaylistAdapter,
- private var viewHolder: ViewHolder,
- private var playlist: Playlist
- ) : AsyncTask() {
-
- override fun doInBackground(vararg params: Void?): Bitmap {
- val songs = PlaylistSongsLoader.getPlaylistSongList(adapter.activity, playlist)
- return AutoGeneratedPlaylistBitmap.getBitmap(adapter.activity, songs, false, false)
- }
-
- override fun onPostExecute(result: Bitmap?) {
- super.onPostExecute(result)
- viewHolder.image?.setImageBitmap(result)
- val color = RetroColorUtil.getColor(
- RetroColorUtil.generatePalette(
- result
- ),
- ATHUtil.resolveColor(adapter.activity, R.attr.colorSurface)
- )
- viewHolder.paletteColorContainer?.setBackgroundColor(color)
- }
- }
-
companion object {
val TAG: String = PlaylistAdapter::class.java.simpleName
- private const val SMART_PLAYLIST = 0
- private const val DEFAULT_PLAYLIST = 1
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt
index d1141341c..2d5fd724f 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt
@@ -1,21 +1,33 @@
+/*
+ * Copyright (c) 2020 Hemanth Savarla.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
package code.name.monkey.retromusic.adapter.song
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
-import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote
-import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song
abstract class AbsOffsetSongAdapter(
- activity: AppCompatActivity,
+ activity: FragmentActivity,
dataSet: MutableList,
- @LayoutRes itemLayoutRes: Int,
- cabHolder: CabHolder?
-) : SongAdapter(activity, dataSet, itemLayoutRes, cabHolder) {
+ @LayoutRes itemLayoutRes: Int
+) : SongAdapter(activity, dataSet, itemLayoutRes) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder {
if (viewType == OFFSET_ITEM) {
@@ -76,4 +88,4 @@ abstract class AbsOffsetSongAdapter(
const val OFFSET_ITEM = 0
const val SONG = 1
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt
index 74a2f7ebd..bf85fe28b 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt
@@ -1,82 +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.adapter.song
import android.view.MenuItem
import android.view.View
-import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.isVisible
+import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.R.menu
-import code.name.monkey.retromusic.dialogs.RemoveFromPlaylistDialog
-import code.name.monkey.retromusic.interfaces.CabHolder
-import code.name.monkey.retromusic.model.PlaylistSong
+import code.name.monkey.retromusic.db.PlaylistEntity
+import code.name.monkey.retromusic.db.toSongEntity
+import code.name.monkey.retromusic.db.toSongsEntity
+import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog
+import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.ViewUtil
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
-import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
-import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import org.koin.androidx.viewmodel.ext.android.viewModel
class OrderablePlaylistSongAdapter(
- activity: AppCompatActivity,
- dataSet: ArrayList,
+ private val playlistId: Long,
+ activity: FragmentActivity,
+ dataSet: MutableList,
itemLayoutRes: Int,
- cabHolder: CabHolder?,
- private val onMoveItemListener: OnMoveItemListener?
-) : PlaylistSongAdapter(
- activity, dataSet, itemLayoutRes, cabHolder
-), DraggableItemAdapter {
+) : SongAdapter(activity, dataSet, itemLayoutRes),
+ DraggableItemAdapter {
+
+ val libraryViewModel: LibraryViewModel by activity.viewModel()
init {
- setMultiSelectMenuRes(menu.menu_playlists_songs_selection)
+ this.setHasStableIds(true)
+ this.setMultiSelectMenuRes(R.menu.menu_playlists_songs_selection)
+ }
+
+ override fun getItemId(position: Int): Long {
+ // requires static value, it means need to keep the same value
+ // even if the item position has been changed.
+ return dataSet[position].id
}
override fun createViewHolder(view: View): SongAdapter.ViewHolder {
return ViewHolder(view)
}
- override fun getItemId(position: Int): Long {
- var positionFinal = position
- positionFinal--
+ override fun onMultipleItemAction(menuItem: MenuItem, selection: List) {
+ when (menuItem.itemId) {
+ R.id.action_remove_from_playlist -> RemoveSongFromPlaylistDialog.create(
+ selection.toSongsEntity(
+ playlistId
+ )
+ )
+ .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
- var long: Long = 0
- if (positionFinal < 0) {
- long = -2
- } else {
- if (dataSet[positionFinal] is PlaylistSong) {
- long = (dataSet[positionFinal] as PlaylistSong).idInPlayList.toLong()
- }
+ else -> super.onMultipleItemAction(menuItem, selection)
}
- return long
}
- override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList) {
- when (menuItem.itemId) {
- R.id.action_remove_from_playlist -> {
- RemoveFromPlaylistDialog.create(selection as ArrayList)
- .show(activity.supportFragmentManager, "ADD_PLAYLIST")
- return
+ inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) {
+
+ override var songMenuRes: Int
+ get() = R.menu.menu_item_playlist_song
+ set(value) {
+ super.songMenuRes = value
}
+
+ override fun onSongMenuItemClick(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.action_remove_from_playlist -> {
+ RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlistId))
+ .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
+ return true
+ }
+ }
+ return super.onSongMenuItemClick(item)
+ }
+
+ init {
+ dragView?.isVisible = true
}
- super.onMultipleItemAction(menuItem, selection)
}
override fun onCheckCanStartDrag(holder: ViewHolder, position: Int, x: Int, y: Int): Boolean {
- return onMoveItemListener != null && position > 0 && (ViewUtil.hitTest(
- holder.dragView!!, x, y
- ) || ViewUtil.hitTest(holder.image!!, x, y))
- }
-
- override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange {
- return ItemDraggableRange(1, dataSet.size)
+ if (isInQuickSelectMode) {
+ return false
+ }
+ return ViewUtil.hitTest(holder.imageText!!, x, y) || ViewUtil.hitTest(
+ holder.dragView!!,
+ x,
+ y
+ )
}
override fun onMoveItem(fromPosition: Int, toPosition: Int) {
- if (onMoveItemListener != null && fromPosition != toPosition) {
- onMoveItemListener.onMoveItem(fromPosition - 1, toPosition - 1)
- }
+ dataSet.add(toPosition, dataSet.removeAt(fromPosition))
+ }
+
+ override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange? {
+ return null
}
override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean {
- return dropPosition > 0
+ return true
}
override fun onItemDragStarted(position: Int) {
@@ -87,53 +126,9 @@ class OrderablePlaylistSongAdapter(
notifyDataSetChanged()
}
- interface OnMoveItemListener {
- fun onMoveItem(fromPosition: Int, toPosition: Int)
- }
-
- inner class ViewHolder(itemView: View) : PlaylistSongAdapter.ViewHolder(itemView),
- DraggableItemViewHolder {
- @DraggableItemStateFlags
- private var mDragStateFlags: Int = 0
-
- override var songMenuRes: Int
- get() = R.menu.menu_item_playlist_song
- set(value) {
- super.songMenuRes = value
- }
-
- init {
- if (dragView != null) {
- if (onMoveItemListener != null) {
- dragView?.visibility = View.VISIBLE
- } else {
- dragView?.visibility = View.GONE
- }
- }
+ fun saveSongs(playlistEntity: PlaylistEntity) {
+ activity.lifecycleScope.launch(Dispatchers.IO) {
+ libraryViewModel.insertSongs(dataSet.toSongsEntity(playlistEntity))
}
-
- override fun onSongMenuItemClick(item: MenuItem): Boolean {
- when (item.itemId) {
- R.id.action_remove_from_playlist -> {
- RemoveFromPlaylistDialog.create(song as PlaylistSong)
- .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
- return true
- }
- }
- return super.onSongMenuItemClick(item)
- }
-
- @DraggableItemStateFlags
- override fun getDragStateFlags(): Int {
- return mDragStateFlags
- }
-
- override fun setDragStateFlags(@DraggableItemStateFlags flags: Int) {
- mDragStateFlags = flags
- }
- }
-
- companion object {
- val TAG: String = OrderablePlaylistSongAdapter::class.java.simpleName
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt
index deba43f35..2d387be44 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt
@@ -1,11 +1,26 @@
+/*
+ * Copyright (c) 2020 Hemanth Savarla.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
package code.name.monkey.retromusic.adapter.song
-import android.graphics.PorterDuff.Mode
import android.view.MenuItem
import android.view.View
-import android.widget.ImageView
-import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.isVisible
+import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R
+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.MusicPlayerRemote.isPlaying
import code.name.monkey.retromusic.helper.MusicPlayerRemote.playNextSong
@@ -13,6 +28,7 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.ViewUtil
+import com.bumptech.glide.Glide
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
@@ -21,22 +37,18 @@ import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstant
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAction
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionDefault
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem
-import com.h6ah4i.android.widget.advrecyclerview.swipeable.annotation.SwipeableItemResults
import me.zhanghai.android.fastscroll.PopupTextProvider
-import java.util.*
class PlayingQueueAdapter(
- activity: AppCompatActivity,
- dataSet: ArrayList,
+ activity: FragmentActivity,
+ dataSet: MutableList,
private var current: Int,
- itemLayoutRes: Int
-) : SongAdapter(
- activity, dataSet, itemLayoutRes, null
-), DraggableItemAdapter,
+ itemLayoutRes: Int,
+) : SongAdapter(activity, dataSet, itemLayoutRes),
+ DraggableItemAdapter,
SwipeableItemAdapter,
PopupTextProvider {
- private var color = -1
private var songToRemove: Song? = null
override fun createViewHolder(view: View): SongAdapter.ViewHolder {
@@ -45,30 +57,13 @@ class PlayingQueueAdapter(
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
super.onBindViewHolder(holder, position)
- holder.imageText?.text = (position - current).toString()
- holder.time?.text = MusicUtil.getReadableDurationString(dataSet[position].duration)
+ val song = dataSet[position]
+ holder.time?.text = MusicUtil.getReadableDurationString(song.duration)
if (holder.itemViewType == HISTORY || holder.itemViewType == CURRENT) {
setAlpha(holder, 0.5f)
}
}
- private fun setColor(holder: SongAdapter.ViewHolder, white: Int) {
-
- if (holder.title != null) {
- holder.title!!.setTextColor(white)
- if (color != -1) {
- holder.title!!.setTextColor(color)
- }
- }
-
- holder.text?.setTextColor(white)
- holder.time?.setTextColor(white)
- holder.imageText?.setTextColor(white)
- if (holder.menu != null) {
- (holder.menu as ImageView).setColorFilter(white, Mode.SRC_IN)
- }
- }
-
override fun getItemViewType(position: Int): Int {
if (position < current) {
return HISTORY
@@ -79,11 +74,17 @@ class PlayingQueueAdapter(
}
override fun loadAlbumCover(song: Song, holder: SongAdapter.ViewHolder) {
- // We don't want to load it in this adapter
+ if (holder.image == null) {
+ return
+ }
+ Glide.with(activity)
+ .load(RetroGlideExtension.getSongModel(song))
+ .songCoverOptions(song)
+ .into(holder.image!!)
}
- fun swapDataSet(dataSet: ArrayList, position: Int) {
- this.dataSet = dataSet
+ fun swapDataSet(dataSet: List, position: Int) {
+ this.dataSet = dataSet.toMutableList()
current = position
notifyDataSetChanged()
}
@@ -97,7 +98,6 @@ class PlayingQueueAdapter(
holder.image?.alpha = alpha
holder.title?.alpha = alpha
holder.text?.alpha = alpha
- holder.imageText?.alpha = alpha
holder.paletteColorContainer?.alpha = alpha
holder.dragView?.alpha = alpha
holder.menu?.alpha = alpha
@@ -140,7 +140,6 @@ class PlayingQueueAdapter(
}
inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) {
-
@DraggableItemStateFlags
private var mDragStateFlags: Int = 0
@@ -151,8 +150,15 @@ class PlayingQueueAdapter(
}
init {
- imageText?.visibility = View.VISIBLE
- dragView?.visibility = View.VISIBLE
+ dragView?.isVisible = true
+ }
+
+ override fun onClick(v: View?) {
+ if (isInQuickSelectMode) {
+ toggleChecked(layoutPosition)
+ } else {
+ MusicPlayerRemote.playSongAt(layoutPosition)
+ }
}
override fun onSongMenuItemClick(item: MenuItem): Boolean {
@@ -174,8 +180,8 @@ class PlayingQueueAdapter(
mDragStateFlags = flags
}
- override fun getSwipeableContainerView(): View? {
- return dummyContainer
+ override fun getSwipeableContainerView(): View {
+ return dummyContainer!!
}
}
@@ -186,52 +192,46 @@ class PlayingQueueAdapter(
private const val UP_NEXT = 2
}
- override fun onSwipeItem(
- holder: ViewHolder?,
- position: Int, @SwipeableItemResults result: Int
- ): SwipeResultAction {
- return if (result === SwipeableItemConstants.RESULT_CANCELED) {
+ override fun onSwipeItem(holder: ViewHolder, position: Int, result: Int): SwipeResultAction {
+ return if (result == SwipeableItemConstants.RESULT_CANCELED) {
SwipeResultActionDefault()
} else {
- SwipedResultActionRemoveItem(this, position, activity)
+ SwipedResultActionRemoveItem(this, position)
}
}
- override fun onGetSwipeReactionType(holder: ViewHolder?, position: Int, x: Int, y: Int): Int {
- return if (onCheckCanStartDrag(holder!!, position, x, y)) {
+ override fun onGetSwipeReactionType(holder: ViewHolder, position: Int, x: Int, y: Int): Int {
+ return if (onCheckCanStartDrag(holder, position, x, y)) {
SwipeableItemConstants.REACTION_CAN_NOT_SWIPE_BOTH_H
} else {
SwipeableItemConstants.REACTION_CAN_SWIPE_BOTH_H
}
}
- override fun onSwipeItemStarted(p0: ViewHolder?, p1: Int) {
+ override fun onSwipeItemStarted(holder: ViewHolder, p1: Int) {
}
- override fun onSetSwipeBackground(holder: ViewHolder?, position: Int, result: Int) {
+ override fun onSetSwipeBackground(holder: ViewHolder, position: Int, result: Int) {
}
internal class SwipedResultActionRemoveItem(
private val adapter: PlayingQueueAdapter,
private val position: Int,
- private val activity: AppCompatActivity
) : SwipeResultActionRemoveItem() {
private var songToRemove: Song? = null
- private val isPlaying: Boolean = MusicPlayerRemote.isPlaying
- private val songProgressMillis = 0
override fun onPerformAction() {
- //currentlyShownSnackbar = null
+ // currentlyShownSnackbar = null
}
override fun onSlideAnimationEnd() {
- //initializeSnackBar(adapter, position, activity, isPlaying)
+ // initializeSnackBar(adapter, position, activity, isPlaying)
songToRemove = adapter.dataSet[position]
- //If song removed was the playing song, then play the next song
+ // If song removed was the playing song, then play the next song
if (isPlaying(songToRemove!!)) {
playNextSong()
}
- //Swipe animation is much smoother when we do the heavy lifting after it's completed
+ // Swipe animation is much smoother when we do the heavy lifting after it's completed
adapter.setSongToRemove(songToRemove!!)
removeFromQueue(songToRemove!!)
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlaylistSongAdapter.kt
deleted file mode 100644
index 6ffc8942f..000000000
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlaylistSongAdapter.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-package code.name.monkey.retromusic.adapter.song
-
-import android.app.ActivityOptions
-import android.view.MenuItem
-import android.view.View
-import androidx.appcompat.app.AppCompatActivity
-import code.name.monkey.retromusic.R
-import code.name.monkey.retromusic.helper.MusicPlayerRemote
-import code.name.monkey.retromusic.interfaces.CabHolder
-import code.name.monkey.retromusic.model.Song
-import code.name.monkey.retromusic.util.NavigationUtil
-import com.google.android.material.button.MaterialButton
-
-open class PlaylistSongAdapter(
- activity: AppCompatActivity,
- dataSet: MutableList,
- itemLayoutRes: Int,
- cabHolder: CabHolder?
-) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) {
-
- init {
- this.setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection)
- }
-
- override fun createViewHolder(view: View): SongAdapter.ViewHolder {
- return ViewHolder(view)
- }
-
- override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
- if (holder.itemViewType == OFFSET_ITEM) {
- val viewHolder = holder as ViewHolder
- viewHolder.playAction?.let {
- it.setOnClickListener {
- MusicPlayerRemote.openQueue(dataSet, 0, true)
- }
- }
- viewHolder.shuffleAction?.let {
- it.setOnClickListener {
- MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
- }
- }
- } else {
- super.onBindViewHolder(holder, position - 1)
- }
- }
-
- open inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) {
-
- val playAction: MaterialButton? = itemView.findViewById(R.id.playAction)
- val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction)
-
- override var songMenuRes: Int
- get() = R.menu.menu_item_cannot_delete_single_songs_playlist_song
- set(value) {
- super.songMenuRes = value
- }
-
- override fun onSongMenuItemClick(item: MenuItem): Boolean {
- if (item.itemId == R.id.action_go_to_album) {
- val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
- activity,
- imageContainerCard ?: image,
- "${activity.getString(R.string.transition_album_art)}_${song.albumId}"
- )
- NavigationUtil.goToAlbumOptions(activity, song.albumId, activityOptions)
- return true
- }
- return super.onSongMenuItemClick(item)
- }
- }
-
- companion object {
- val TAG: String = PlaylistSongAdapter::class.java.simpleName
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt
index 2714447be..82ba1a7f7 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt
@@ -1,35 +1,67 @@
+/*
+ * Copyright (c) 2020 Hemanth Savarla.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
package code.name.monkey.retromusic.adapter.song
import android.view.View
-import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.isVisible
+import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.extensions.accentColor
+import code.name.monkey.retromusic.extensions.accentOutlineColor
import code.name.monkey.retromusic.helper.MusicPlayerRemote
-import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song
+import code.name.monkey.retromusic.util.PreferenceUtil
+import code.name.monkey.retromusic.util.RetroUtil
import com.google.android.material.button.MaterialButton
class ShuffleButtonSongAdapter(
- activity: AppCompatActivity,
+ activity: FragmentActivity,
dataSet: MutableList,
- itemLayoutRes: Int,
- cabHolder: CabHolder?
-) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) {
+ itemLayoutRes: Int
+) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes) {
+
override fun createViewHolder(view: View): SongAdapter.ViewHolder {
return ViewHolder(view)
}
+ override fun getItemViewType(position: Int): Int {
+ return if (position == 0) OFFSET_ITEM else SONG
+ }
+
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
if (holder.itemViewType == OFFSET_ITEM) {
val viewHolder = holder as ViewHolder
- viewHolder.playAction?.setOnClickListener {
- MusicPlayerRemote.openQueue(dataSet, 0, true)
+ viewHolder.playAction?.let {
+ it.setOnClickListener {
+ MusicPlayerRemote.openQueue(dataSet, 0, true)
+ }
+ it.accentOutlineColor()
}
- viewHolder.shuffleAction?.setOnClickListener {
- MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
+ viewHolder.shuffleAction?.let {
+ it.setOnClickListener {
+ MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
+ }
+ it.accentColor()
}
} else {
super.onBindViewHolder(holder, position - 1)
+ val landscape = RetroUtil.isLandscape
+ if ((PreferenceUtil.songGridSize > 2 && !landscape) || (PreferenceUtil.songGridSizeLand > 5 && landscape)) {
+ holder.menu?.isVisible = false
+ }
}
}
@@ -45,4 +77,5 @@ class ShuffleButtonSongAdapter(
super.onClick(v)
}
}
-}
\ No newline at end of file
+
+}
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SimpleSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SimpleSongAdapter.kt
index 53a952426..f1f50e627 100755
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SimpleSongAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SimpleSongAdapter.kt
@@ -1,19 +1,30 @@
+/*
+ * Copyright (c) 2020 Hemanth Savarla.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
package code.name.monkey.retromusic.adapter.song
import android.view.LayoutInflater
import android.view.ViewGroup
-import androidx.appcompat.app.AppCompatActivity
-import code.name.monkey.retromusic.interfaces.CabHolder
+import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
-import java.util.*
class SimpleSongAdapter(
- context: AppCompatActivity,
+ context: FragmentActivity,
songs: ArrayList,
- layoutRes: Int,
- cabHolder: CabHolder?
-) : SongAdapter(context, songs, layoutRes, cabHolder) {
+ layoutRes: Int
+) : SongAdapter(context, songs, layoutRes) {
override fun swapDataSet(dataSet: List) {
this.dataSet = dataSet.toMutableList()
@@ -27,9 +38,11 @@ class SimpleSongAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
super.onBindViewHolder(holder, position)
val fixedTrackNumber = MusicUtil.getFixedTrackNumber(dataSet[position].trackNumber)
+ val trackAndTime = (if (fixedTrackNumber > 0) "$fixedTrackNumber | " else "") +
+ MusicUtil.getReadableDurationString(dataSet[position].duration)
- holder.imageText?.text = if (fixedTrackNumber > 0) fixedTrackNumber.toString() else "-"
- holder.time?.text = MusicUtil.getReadableDurationString(dataSet[position].duration)
+ holder.time?.text = trackAndTime
+ holder.text2?.text = dataSet[position].artistName
}
override fun getItemCount(): Int {
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt
index 17b06be8e..7b7b7bf99 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt
@@ -1,48 +1,63 @@
+/*
+ * Copyright (c) 2020 Hemanth Savarla.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
package code.name.monkey.retromusic.adapter.song
-import android.app.ActivityOptions
-import android.graphics.drawable.Drawable
+import android.content.res.ColorStateList
+import android.content.res.Resources
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
-import androidx.appcompat.app.AppCompatActivity
+import androidx.core.os.bundleOf
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
+import androidx.fragment.app.FragmentActivity
+import androidx.navigation.findNavController
+import code.name.monkey.retromusic.EXTRA_ALBUM_ID
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.hide
-import code.name.monkey.retromusic.extensions.show
+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.helper.SortOrder
import code.name.monkey.retromusic.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
-import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
-import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
-import com.afollestad.materialcab.MaterialCab
+import code.name.monkey.retromusic.util.RetroUtil
+import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import me.zhanghai.android.fastscroll.PopupTextProvider
-import java.util.*
/**
* Created by hemanths on 13/08/17.
*/
open class SongAdapter(
- protected val activity: AppCompatActivity,
+ override val activity: FragmentActivity,
var dataSet: MutableList,
protected var itemLayoutRes: Int,
- cabHolder: CabHolder?,
showSectionName: Boolean = true
) : AbsMultiSelectAdapter(
activity,
- cabHolder,
R.menu.menu_media_selection
-), MaterialCab.Callback, PopupTextProvider {
+), PopupTextProvider {
private var showSectionName = true
@@ -52,16 +67,21 @@ open class SongAdapter(
}
open fun swapDataSet(dataSet: List) {
- this.dataSet = dataSet.toMutableList()
+ this.dataSet = ArrayList(dataSet)
notifyDataSetChanged()
}
override fun getItemId(position: Int): Long {
- return dataSet[position].id.toLong()
+ return dataSet[position].id
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
+ val view =
+ try {
+ LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
+ } catch (e: Resources.NotFoundException) {
+ LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false)
+ }
return createViewHolder(view)
}
@@ -73,49 +93,54 @@ open class SongAdapter(
val song = dataSet[position]
val isChecked = isChecked(song)
holder.itemView.isActivated = isChecked
- if (isChecked) {
- holder.menu?.hide()
- } else {
- holder.menu?.show()
- }
+ holder.menu?.isGone = isChecked
holder.title?.text = getSongTitle(song)
holder.text?.text = getSongText(song)
+ holder.text2?.text = getSongText(song)
loadAlbumCover(song, holder)
+ val landscape = RetroUtil.isLandscape
+ if ((PreferenceUtil.songGridSize > 2 && !landscape) || (PreferenceUtil.songGridSizeLand > 5 && landscape)) {
+ holder.menu?.isVisible = false
+ }
}
- private fun setColors(color: Int, holder: ViewHolder) {
+ private fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) {
if (holder.paletteColorContainer != null) {
- holder.paletteColorContainer?.setBackgroundColor(color)
+ holder.title?.setTextColor(color.primaryTextColor)
+ holder.text?.setTextColor(color.secondaryTextColor)
+ holder.paletteColorContainer?.setBackgroundColor(color.backgroundColor)
+ holder.menu?.imageTintList = ColorStateList.valueOf(color.primaryTextColor)
}
+ holder.mask?.backgroundTintList = ColorStateList.valueOf(color.primaryTextColor)
}
protected open fun loadAlbumCover(song: Song, holder: ViewHolder) {
if (holder.image == null) {
return
}
- SongGlideRequest.Builder.from(Glide.with(activity), song)
- .checkIgnoreMediaStore(activity)
- .generatePalette(activity).build()
+ Glide.with(activity)
+ .asBitmapPalette()
+ .songCoverOptions(song)
+ .load(RetroGlideExtension.getSongModel(song))
.into(object : RetroMusicColoredTarget(holder.image!!) {
- override fun onLoadCleared(placeholder: Drawable?) {
- super.onLoadCleared(placeholder)
- setColors(defaultFooterColor, holder)
- }
-
- override fun onColorReady(color: Int) {
- setColors(color, holder)
+ override fun onColorReady(colors: MediaNotificationProcessor) {
+ setColors(colors, holder)
}
})
}
- private fun getSongTitle(song: Song): String? {
+ private fun getSongTitle(song: Song): String {
return song.title
}
- private fun getSongText(song: Song): String? {
+ private fun getSongText(song: Song): String {
return song.artistName
}
+ private fun getSongText2(song: Song): String {
+ return song.albumName
+ }
+
override fun getItemCount(): Int {
return dataSet.size
}
@@ -124,26 +149,31 @@ open class SongAdapter(
return dataSet[position]
}
- override fun getName(song: Song): String {
- return song.title
+ override fun getName(model: Song): String {
+ return model.title
}
- override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList) {
+ override fun onMultipleItemAction(menuItem: MenuItem, selection: List) {
SongsMenuHelper.handleMenuClick(activity, selection, menuItem.itemId)
}
override fun getPopupText(position: Int): String {
- val sectionName: String? = when (PreferenceUtil.getInstance(activity).songSortOrder) {
+ val sectionName: String? = when (PreferenceUtil.songSortOrder) {
+ SortOrder.SongSortOrder.SONG_DEFAULT -> return MusicUtil.getSectionName(
+ dataSet[position].title,
+ true
+ )
+
SortOrder.SongSortOrder.SONG_A_Z, SortOrder.SongSortOrder.SONG_Z_A -> dataSet[position].title
SortOrder.SongSortOrder.SONG_ALBUM -> dataSet[position].albumName
SortOrder.SongSortOrder.SONG_ARTIST -> dataSet[position].artistName
SortOrder.SongSortOrder.SONG_YEAR -> return MusicUtil.getYearString(dataSet[position].year)
SortOrder.SongSortOrder.COMPOSER -> dataSet[position].composer
+ SortOrder.SongSortOrder.SONG_ALBUM_ARTIST -> dataSet[position].albumArtist
else -> {
return ""
}
}
-
return MusicUtil.getSectionName(sectionName)
}
@@ -153,7 +183,6 @@ open class SongAdapter(
get() = dataSet[layoutPosition]
init {
- setImageTransitionName(activity.getString(R.string.transition_album_art))
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
override val song: Song
get() = this@ViewHolder.song
@@ -168,15 +197,14 @@ open class SongAdapter(
}
protected open fun onSongMenuItemClick(item: MenuItem): Boolean {
- if (image != null && image!!.visibility == View.VISIBLE) {
+ if (image != null && image!!.isVisible) {
when (item.itemId) {
R.id.action_go_to_album -> {
- val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
- activity,
- imageContainerCard ?: image,
- "${activity.getString(R.string.transition_album_art)}_${song.albumId}"
- )
- NavigationUtil.goToAlbumOptions(activity, song.albumId, activityOptions)
+ activity.findNavController(R.id.fragment_container)
+ .navigate(
+ R.id.albumDetailsFragment,
+ bundleOf(EXTRA_ALBUM_ID to song.albumId)
+ )
return true
}
}
@@ -193,12 +221,12 @@ open class SongAdapter(
}
override fun onLongClick(v: View?): Boolean {
+ println("Long click")
return toggleChecked(layoutPosition)
}
}
companion object {
-
val TAG: String = SongAdapter::class.java.simpleName
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.kt b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.kt
index 15e1b3020..ad8f964e7 100644
--- a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.kt
@@ -1,37 +1,35 @@
/*
- * 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.appshortcuts
import android.content.Context
-import android.graphics.Bitmap
-import android.graphics.Canvas
-import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.graphics.drawable.LayerDrawable
import android.os.Build
import android.util.TypedValue
import androidx.annotation.RequiresApi
+import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.extensions.getTintedDrawable
import code.name.monkey.retromusic.util.PreferenceUtil
-import code.name.monkey.retromusic.util.RetroUtil
@RequiresApi(Build.VERSION_CODES.N_MR1)
object AppShortcutIconGenerator {
fun generateThemedIcon(context: Context, iconId: Int): Icon {
- return if (PreferenceUtil.getInstance(context).coloredAppShortcuts()) {
+ return if (PreferenceUtil.isColoredAppShortcuts) {
generateUserThemedIcon(context, iconId)
} else {
generateDefaultThemedIcon(context, iconId)
@@ -60,28 +58,20 @@ object AppShortcutIconGenerator {
}
private fun generateThemedIcon(
- context: Context, iconId: Int, foregroundColor: Int, backgroundColor: Int
+ context: Context,
+ iconId: Int,
+ foregroundColor: Int,
+ backgroundColor: Int,
): Icon {
// Get and tint foreground and background drawables
- val vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor)
- val backgroundDrawable = RetroUtil.getTintedVectorDrawable(
- context, R.drawable.ic_app_shortcut_background, backgroundColor
- )
+ val vectorDrawable = context.getTintedDrawable(iconId, foregroundColor)
+ val backgroundDrawable =
+ context.getTintedDrawable(R.drawable.ic_app_shortcut_background, backgroundColor)
// Squash the two drawables together
val layerDrawable = LayerDrawable(arrayOf(backgroundDrawable, vectorDrawable))
// Return as an Icon
- return Icon.createWithBitmap(drawableToBitmap(layerDrawable))
- }
-
- private fun drawableToBitmap(drawable: Drawable): Bitmap {
- val bitmap = Bitmap.createBitmap(
- drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888
- )
- val canvas = Canvas(bitmap)
- drawable.setBounds(0, 0, canvas.width, canvas.height)
- drawable.draw(canvas)
- return bitmap
+ return Icon.createWithBitmap(layerDrawable.toBitmap())
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.kt b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.kt
index 1bf1e90c0..9f10d795b 100644
--- a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.kt
@@ -1,70 +1,61 @@
/*
- * 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.appshortcuts
import android.app.Activity
import android.content.Intent
import android.os.Bundle
-import code.name.monkey.retromusic.activities.SearchActivity
+import androidx.core.os.bundleOf
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType
-import code.name.monkey.retromusic.appshortcuts.shortcuttype.SearchShortCutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType
+import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist
-import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist
import code.name.monkey.retromusic.model.smartplaylist.ShuffleAllPlaylist
+import code.name.monkey.retromusic.model.smartplaylist.TopTracksPlaylist
import code.name.monkey.retromusic.service.MusicService
-import code.name.monkey.retromusic.service.MusicService.*
+import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_PLAY_PLAYLIST
+import code.name.monkey.retromusic.service.MusicService.Companion.INTENT_EXTRA_PLAYLIST
+import code.name.monkey.retromusic.service.MusicService.Companion.INTENT_EXTRA_SHUFFLE_MODE
+import code.name.monkey.retromusic.service.MusicService.Companion.SHUFFLE_MODE_NONE
+import code.name.monkey.retromusic.service.MusicService.Companion.SHUFFLE_MODE_SHUFFLE
class AppShortcutLauncherActivity : Activity() {
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
-
- var shortcutType = SHORTCUT_TYPE_NONE
-
- // Set shortcutType from the intent extras
- val extras = intent.extras
- if (extras != null) {
- shortcutType = extras.getInt(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE)
- }
-
- when (shortcutType) {
+ when (extraNotNull(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE).value) {
SHORTCUT_TYPE_SHUFFLE_ALL -> {
startServiceWithPlaylist(
- MusicService.SHUFFLE_MODE_SHUFFLE, ShuffleAllPlaylist(applicationContext)
+ SHUFFLE_MODE_SHUFFLE, ShuffleAllPlaylist()
)
DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.id)
}
SHORTCUT_TYPE_TOP_TRACKS -> {
startServiceWithPlaylist(
- MusicService.SHUFFLE_MODE_NONE, MyTopTracksPlaylist(applicationContext)
+ SHUFFLE_MODE_NONE, TopTracksPlaylist()
)
DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.id)
}
SHORTCUT_TYPE_LAST_ADDED -> {
startServiceWithPlaylist(
- MusicService.SHUFFLE_MODE_NONE, LastAddedPlaylist(applicationContext)
+ SHUFFLE_MODE_NONE, LastAddedPlaylist()
)
DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.id)
}
- SHORTCUT_TYPE_SEARCH -> {
- startActivity(Intent(this, SearchActivity::class.java))
- DynamicShortcutManager.reportShortcutUsed(this, SearchShortCutType.id)
- }
}
finish()
}
@@ -73,9 +64,10 @@ class AppShortcutLauncherActivity : Activity() {
val intent = Intent(this, MusicService::class.java)
intent.action = ACTION_PLAY_PLAYLIST
- val bundle = Bundle()
- bundle.putParcelable(INTENT_EXTRA_PLAYLIST, playlist)
- bundle.putInt(INTENT_EXTRA_SHUFFLE_MODE, shuffleMode)
+ val bundle = bundleOf(
+ INTENT_EXTRA_PLAYLIST to playlist,
+ INTENT_EXTRA_SHUFFLE_MODE to shuffleMode
+ )
intent.putExtras(bundle)
@@ -83,11 +75,10 @@ class AppShortcutLauncherActivity : Activity() {
}
companion object {
- const val KEY_SHORTCUT_TYPE = "code.name.monkey.retromusic.appshortcuts.ShortcutType"
- const val SHORTCUT_TYPE_SHUFFLE_ALL = 0
- const val SHORTCUT_TYPE_TOP_TRACKS = 1
- const val SHORTCUT_TYPE_LAST_ADDED = 2
- const val SHORTCUT_TYPE_SEARCH = 3
- const val SHORTCUT_TYPE_NONE = 4
+ const val KEY_SHORTCUT_TYPE = "io.github.muntashirakon.Music.appshortcuts.ShortcutType"
+ const val SHORTCUT_TYPE_SHUFFLE_ALL = 0L
+ const val SHORTCUT_TYPE_TOP_TRACKS = 1L
+ const val SHORTCUT_TYPE_LAST_ADDED = 2L
+ const val SHORTCUT_TYPE_NONE = 4L
}
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.kt b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.kt
index c77df6b54..a943ed0c8 100644
--- a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.kt
@@ -1,17 +1,17 @@
/*
- * Copyright (c) 2019 Hemanth Savarala.
+ * Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
- * This is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by
- * the Free Software Foundation either version 3 of the License, or (at your option) any later version.
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
+ *
*/
-
package code.name.monkey.retromusic.appshortcuts
import android.annotation.TargetApi
@@ -21,34 +21,31 @@ import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon
import android.os.Build
+import androidx.core.content.getSystemService
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType
-import code.name.monkey.retromusic.appshortcuts.shortcuttype.SearchShortCutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType
-import java.util.*
@TargetApi(Build.VERSION_CODES.N_MR1)
class DynamicShortcutManager(private val context: Context) {
- private val shortcutManager: ShortcutManager =
- this.context.getSystemService(ShortcutManager::class.java)
+ private val shortcutManager: ShortcutManager? =
+ this.context.getSystemService()
private val defaultShortcuts: List
- get() = Arrays.asList(
- SearchShortCutType(context).shortcutInfo,
+ get() = listOf(
ShuffleAllShortcutType(context).shortcutInfo,
TopTracksShortcutType(context).shortcutInfo,
LastAddedShortcutType(context).shortcutInfo
-
)
fun initDynamicShortcuts() {
- //if (shortcutManager.dynamicShortcuts.size == 0) {
- shortcutManager.dynamicShortcuts = defaultShortcuts
- //}
+ // if (shortcutManager.dynamicShortcuts.size == 0) {
+ shortcutManager?.dynamicShortcuts = defaultShortcuts
+ // }
}
fun updateDynamicShortcuts() {
- shortcutManager.updateShortcuts(defaultShortcuts)
+ shortcutManager?.updateShortcuts(defaultShortcuts)
}
companion object {
@@ -61,12 +58,16 @@ class DynamicShortcutManager(private val context: Context) {
icon: Icon,
intent: Intent
): ShortcutInfo {
- return ShortcutInfo.Builder(context, id).setShortLabel(shortLabel)
- .setLongLabel(longLabel).setIcon(icon).setIntent(intent).build()
+ return ShortcutInfo.Builder(context, id)
+ .setShortLabel(shortLabel)
+ .setLongLabel(longLabel)
+ .setIcon(icon)
+ .setIntent(intent)
+ .build()
}
fun reportShortcutUsed(context: Context, shortcutId: String) {
- context.getSystemService(ShortcutManager::class.java).reportShortcutUsed(shortcutId)
+ context.getSystemService