Merge RetroMusicPlayer/dev into dev

Signed-off-by: Muntashir Al-Islam <muntashirakon@riseup.net>
This commit is contained in:
Muntashir Al-Islam 2023-03-15 11:22:32 +06:00
commit 46ad05a832
539 changed files with 10446 additions and 8947 deletions

4
.gitattributes vendored Normal file
View file

@ -0,0 +1,4 @@
* text=auto eol=lf
*.bat text eol=crlf
*.jar binary

View file

@ -7,28 +7,28 @@ on:
branches: [ dev ] branches: [ dev ]
jobs: jobs:
build: check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 10
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: set up JDK 11 - uses: gradle/wrapper-validation-action@v1
uses: actions/setup-java@v2 - uses: actions/setup-java@v3
with: with:
java-version: '11' distribution: 'zulu'
distribution: 'temurin' java-version: 17
cache: gradle - uses: gradle/gradle-build-action@v2
- name: Lint Android
run: ./gradlew lint
- name: Generate temporary keystore build:
run: keytool -genkey -v -storetype pkcs12 -keystore store.p12 -storepass android -alias android -keyalg RSA -keysize 2048 -validity 10000 -dname CN=CI runs-on: ubuntu-latest
- name: Write retro.properties steps:
run: | - uses: actions/checkout@v3
cat >retro.properties <<EOF - uses: actions/setup-java@v3
storeFile=$PWD/store.p12 with:
keyAlias=android java-version: '17'
storePassword=android distribution: 'zulu'
keyPassword=android - uses: gradle/gradle-build-action@v2
EOF - name: Build
- name: Build with Gradle run: ./gradlew app:assemble
run: ./gradlew build

View file

@ -11,17 +11,18 @@ Material Design music player for Android music lovers
## Differences between Metro and [RetroMusicPlayer](https://github.com/h4h13/RetroMusicPlayer) ## Differences between Metro and [RetroMusicPlayer](https://github.com/h4h13/RetroMusicPlayer)
- Google Play libraries removed (fully libre) - Google Play libraries removed (fully libre)
- Pro features available for free - Pro features available for free
- Fully offline (INTERNET permission removed)
- Bug fixes - Bug fixes
- Minor differences in UI - Minor differences in UI
## 📱 Screenshots ## 📱 Screenshots
### App Themes ### App Themes
| <img src="screenshots/home_light.jpg" width="200"/> | <img src="screenshots/home_dark.jpg" width="200"/> | <img src="screenshots/home_black.jpg" width="200"/> | | <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg" width="200"/> | <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg" width="200"/> | <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/4.jpg" width="200"/> |
|:---:|:---:|:---:| |:---:|:---:|:---:|
|Clearly white| Kinda dark | Just black| |Clearly white| Kinda dark | Just black|
### Player screen ### Player screen
| <img src="screenshots/home_light.jpg" width="200"/>| <img src="screenshots/songs.jpg" width="200"/>| <img src="screenshots/albums.jpg" width="200"/>| <img src="screenshots/artists.jpg" width="200"/>| <img src="screenshots/settings.jpg" width="200"/>| | <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg" width="200"/>| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/5.jpg" width="200"/>| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/6.jpg" width="200"/>| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/7.jpg" width="200"/>| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/8.jpg" width="200"/>|
|:---:|:---:|:---:|:---:|:---:| |:---:|:---:|:---:|:---:|:---:|
| Home | Songs | Albums | Artists | Settings | | Home | Songs | Albums | Artists | Settings |
@ -36,7 +37,7 @@ Material Design music player for Android music lovers
| Synced Replace Cover light | Synced Replace Cover dark | Synced Replace Cover black | | Synced Replace Cover light | Synced Replace Cover dark | Synced Replace Cover black |
### 10+ Now playing themes ### 10+ Now playing themes
| <img src="screenshots/normal.jpg" width="200"/> |<img src="screenshots/fit.jpg" width="200"/>| <img src="screenshots/flat.jpg" width="200"/> | <img src="screenshots/color.jpg" width="200"/> | <img src="screenshots/material.jpg" width="200"/> | | <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg" width="200"/> |<img src="screenshots/fit.jpg" width="200"/>| <img src="screenshots/flat.jpg" width="200"/> | <img src="screenshots/color.jpg" width="200"/> | <img src="screenshots/material.jpg" width="200"/> |
|:-----: |:-----: |:-----: |:-----: |:-----: | |:-----: |:-----: |:-----: |:-----: |:-----: |
| Normal | Fit | Flat | Color | Material | | Normal | Fit | Flat | Color | Material |

View file

@ -1,23 +1,22 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: "androidx.navigation.safeargs.kotlin" apply plugin: "androidx.navigation.safeargs.kotlin"
apply plugin: 'kotlin-parcelize' apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
android { android {
compileSdk 32 compileSdk 33
buildToolsVersion = '30.0.3' namespace "code.name.monkey.retromusic"
defaultConfig { defaultConfig {
namespace 'code.name.monkey.retromusic'
minSdk 21 minSdk 21
targetSdk 32 targetSdk 32
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
applicationId 'io.github.muntashirakon.Music' applicationId 'io.github.muntashirakon.Music'
versionCode 10580 versionCode 10600
versionName '5.8.5' versionName '6.0.4'
multiDexEnabled true multiDexEnabled true
} }
@ -32,7 +31,7 @@ android {
} }
} }
buildFeatures{ buildFeatures {
viewBinding true viewBinding true
} }
packagingOptions { packagingOptions {
@ -41,8 +40,8 @@ android {
} }
} }
lint { lint {
abortOnError false abortOnError true
disable 'MissingTranslation', 'InvalidPackage' warning 'ImpliedQuantity', 'Instantiatable', 'MissingQuantity', 'MissingTranslation'
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
@ -51,8 +50,11 @@ android {
kotlinOptions { kotlinOptions {
jvmTarget = "1.8" jvmTarget = "1.8"
} }
dependenciesInfo {
configurations.all { includeInApk = false
includeInBundle = false
}
configurations.configureEach {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9' resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
} }
} }
@ -61,13 +63,13 @@ android {
dependencies { dependencies {
implementation project(':appthemehelper') implementation project(':appthemehelper')
implementation "androidx.gridlayout:gridlayout:1.0.0" implementation "androidx.gridlayout:gridlayout:1.0.0"
implementation "androidx.cardview:cardview:1.0.0"
implementation "androidx.appcompat:appcompat:$appcompat_version" implementation "androidx.appcompat:appcompat:$appcompat_version"
implementation 'androidx.annotation:annotation:1.3.0' implementation 'androidx.annotation:annotation:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation "androidx.preference:preference-ktx:$preference_version" implementation "androidx.preference:preference-ktx:$preference_version"
implementation 'androidx.core:core-ktx:1.7.0' implementation "androidx.core:core-ktx:$core_version"
implementation 'androidx.palette:palette-ktx:1.0.0' implementation 'androidx.palette:palette-ktx:1.0.0'
implementation "androidx.media:media:1.6.0" implementation "androidx.media:media:1.6.0"
@ -76,20 +78,22 @@ dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version" implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version" implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
def room_version = '2.4.2' def room_version = '2.5.0'
implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-ktx:$room_version" implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version" ksp "androidx.room:room-compiler:$room_version"
def lifecycle_version = "2.5.0-rc01"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
implementation "androidx.core:core-splashscreen:1.0.0-beta02" implementation "androidx.core:core-splashscreen:1.0.0"
implementation "com.google.android.material:material:$mdc_version" implementation "com.google.android.material:material:$mdc_version"
implementation 'com.google.code.gson:gson:2.9.0'
def retrofit_version = '2.9.0'
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
def material_dialog_version = "3.3.0" def material_dialog_version = "3.3.0"
implementation "com.afollestad.material-dialogs:core:$material_dialog_version" implementation "com.afollestad.material-dialogs:core:$material_dialog_version"
@ -98,19 +102,15 @@ dependencies {
implementation 'com.afollestad:material-cab:2.0.1' implementation 'com.afollestad:material-cab:2.0.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
def kotlin_coroutines_version = '1.6.1' def koin_version = '3.3.3'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
def koin_version = '3.2.0'
implementation "io.insert-koin:koin-core:$koin_version" implementation "io.insert-koin:koin-core:$koin_version"
implementation "io.insert-koin:koin-android:$koin_version" implementation "io.insert-koin:koin-android:$koin_version"
def glide_version = '4.13.2' def glide_version = '4.15.0'
implementation "com.github.bumptech.glide:glide:$glide_version" implementation "com.github.bumptech.glide:glide:$glide_version"
kapt "com.github.bumptech.glide:compiler:$glide_version" ksp "com.github.bumptech.glide:ksp:$glide_version"
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0' implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
@ -125,8 +125,7 @@ dependencies {
implementation 'com.r0adkll:slidableactivity:2.1.0' implementation 'com.r0adkll:slidableactivity:2.1.0'
implementation 'com.heinrichreimersoftware:material-intro:2.0.0' implementation 'com.heinrichreimersoftware:material-intro:2.0.0'
implementation 'com.github.dhaval2404:imagepicker:2.1' implementation 'com.github.dhaval2404:imagepicker:2.1'
implementation 'me.zhanghai.android.fastscroll:library:1.1.8' implementation 'me.zhanghai.android.fastscroll:library:1.2.0'
implementation 'cat.ereza:customactivityoncrash:2.3.0' implementation 'cat.ereza:customactivityoncrash:2.4.0'
implementation 'me.tankery.lib:circularSeekBar:1.3.2' implementation 'me.tankery.lib:circularSeekBar:1.4.1'
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
} }

View file

@ -0,0 +1,12 @@
package code.name.monkey.retromusic.billing
import android.content.Context
@Suppress("UNUSED_PARAMETER")
class BillingManager(context: Context) {
fun release() {}
val isProVersion: Boolean
get() = true
}

View file

@ -0,0 +1,6 @@
package code.name.monkey.retromusic.cast
import android.content.Context
@Suppress("UNUSED_PARAMETER")
class RetroWebServer(context: Context)

View file

@ -0,0 +1,17 @@
@file:Suppress("UNUSED_PARAMETER", "unused")
package code.name.monkey.retromusic.extensions
import android.content.Context
import android.view.Menu
import androidx.fragment.app.FragmentActivity
fun Context.setUpMediaRouteButton(menu: Menu) {}
fun FragmentActivity.installLanguageAndRecreate(code: String) {
recreate()
}
fun Context.goToProVersion() {}
fun Context.installSplitCompat() {}

View file

@ -0,0 +1,47 @@
package code.name.monkey.retromusic.service
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.playback.Playback
// Empty CastPlayer implementation
class CastPlayer : Playback {
override val isInitialized: Boolean
get() = true
override val isPlaying: Boolean
get() = true
override val audioSessionId: Int
get() = 0
override fun setDataSource(
song: Song,
force: Boolean,
completion: (success: Boolean) -> Unit,
) {
}
override fun setNextDataSource(path: String?) {}
override var callbacks: Playback.PlaybackCallbacks? = null
override fun start() = true
override fun stop() {}
override fun release() {}
override fun pause(): Boolean = true
override fun duration() = 0
override fun position() = 0
override fun seek(whereto: Int) = whereto
override fun setVolume(vol: Float) = true
override fun setAudioSessionId(sessionId: Int) = true
override fun setCrossFadeDuration(duration: Int) {}
override fun setPlaybackSpeedPitch(speed: Float, pitch: Float) {}
}

View file

@ -0,0 +1,8 @@
package code.name.monkey.retromusic.util
import android.content.Context
@Suppress("UNUSED_PARAMETER")
object AppRater {
fun appLaunched(context: Context) {}
}

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="download_policy">never</string>
</resources>

View file

@ -14,33 +14,37 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" /> android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" /> <uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission <uses-permission
android:name="android.permission.WRITE_SETTINGS" android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" /> tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission
android:name="android.permission.BLUETOOTH_CONNECT"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<application <application
android:name="code.name.monkey.retromusic.App" android:name=".App"
android:allowBackup="@bool/allowBackup" android:allowBackup="@bool/allowBackup"
android:configChanges="locale|layoutDirection" android:configChanges="locale|layoutDirection"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:restoreAnyVersion="true" android:restoreAnyVersion="true"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.RetroMusic.FollowSystem" android:theme="@style/Theme.RetroMusic.FollowSystem"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
tools:ignore="AllowBackup,GoogleAppIndexingWarning" tools:targetApi="m">
tools:targetApi="q">
<activity <activity
android:name="code.name.monkey.retromusic.activities.MainActivity" android:name=".activities.MainActivity"
android:exported="true" android:exported="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/SplashTheme"> android:theme="@style/Theme.RetroMusic.SplashScreen">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.MUSIC_PLAYER" /> <action android:name="android.intent.action.MUSIC_PLAYER" />
@ -51,7 +55,6 @@
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" /> <action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
@ -111,18 +114,20 @@
<data android:mimeType="vnd.android.cursor.dir/audio" /> <data android:mimeType="vnd.android.cursor.dir/audio" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="code.name.monkey.retromusic.activities.SettingsActivity" /> <activity android:name=".activities.tageditor.AlbumTagEditorActivity" />
<activity android:name="code.name.monkey.retromusic.activities.tageditor.AlbumTagEditorActivity" /> <activity android:name=".activities.tageditor.SongTagEditorActivity" />
<activity android:name="code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity" /> <activity android:name=".activities.LicenseActivity" />
<activity android:name="code.name.monkey.retromusic.activities.LicenseActivity" /> <activity android:name=".activities.bugreport.BugReportActivity" />
<activity android:name="code.name.monkey.retromusic.activities.bugreport.BugReportActivity" /> <activity android:name=".activities.ShareInstagramStory" />
<activity android:name="code.name.monkey.retromusic.activities.ShareInstagramStory" /> <activity android:name=".activities.DriveModeActivity" />
<activity android:name="code.name.monkey.retromusic.activities.DriveModeActivity" /> <activity android:name=".activities.PermissionActivity" />
<activity android:name="code.name.monkey.retromusic.activities.PermissionActivity" />
<activity android:name="code.name.monkey.retromusic.activities.LockScreenActivity" />
<activity android:name="code.name.monkey.retromusic.activities.saf.SAFRequestActivity" />
<activity <activity
android:name="code.name.monkey.retromusic.fragments.backup.RestoreActivity" android:name=".activities.LockScreenActivity"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:showOnLockScreen="true" />
<activity
android:name=".fragments.backup.RestoreActivity"
android:excludeFromRecents="false" android:excludeFromRecents="false"
android:exported="true" android:exported="true"
android:label="@string/restore" android:label="@string/restore"
@ -159,32 +164,22 @@
</activity> </activity>
<activity <activity
android:name="code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity" android:name=".appshortcuts.AppShortcutLauncherActivity"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:theme="@android:style/Theme.Translucent.NoTitleBar" /> android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity <activity
android:name="code.name.monkey.retromusic.activities.saf.SAFGuideActivity" android:name=".activities.saf.SAFGuideActivity"
android:theme="@style/Theme.Intro" /> android:theme="@style/Theme.Intro" />
<activity <activity
android:name="code.name.monkey.retromusic.activities.ErrorActivity" android:name=".activities.ErrorActivity"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="cat.ereza.customactivityoncrash.RESTART" /> <action android:name="cat.ereza.customactivityoncrash.RESTART" />
</intent-filter> </intent-filter>
</activity> </activity>
<provider
android:name="code.name.monkey.retromusic.misc.GenericFileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}" android:authorities="${applicationId}"
@ -196,7 +191,7 @@
</provider> </provider>
<receiver <receiver
android:name="androidx.media.session.MediaButtonReceiver" android:name=".service.MediaButtonIntentReceiver"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" /> <action android:name="android.intent.action.MEDIA_BUTTON" />
@ -204,7 +199,7 @@
</receiver> </receiver>
<receiver <receiver
android:name="code.name.monkey.retromusic.appwidgets.BootReceiver" android:name=".appwidgets.BootReceiver"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
@ -213,7 +208,7 @@
</receiver> </receiver>
<receiver <receiver
android:name="code.name.monkey.retromusic.appwidgets.AppWidgetBig" android:name=".appwidgets.AppWidgetBig"
android:exported="true" android:exported="true"
android:label="@string/app_widget_big_name"> android:label="@string/app_widget_big_name">
<intent-filter> <intent-filter>
@ -226,7 +221,7 @@
</receiver> </receiver>
<receiver <receiver
android:name="code.name.monkey.retromusic.appwidgets.AppWidgetClassic" android:name=".appwidgets.AppWidgetClassic"
android:exported="true" android:exported="true"
android:label="@string/app_widget_classic_name"> android:label="@string/app_widget_classic_name">
<intent-filter> <intent-filter>
@ -238,7 +233,7 @@
android:resource="@xml/app_widget_classic_info" /> android:resource="@xml/app_widget_classic_info" />
</receiver> </receiver>
<receiver <receiver
android:name="code.name.monkey.retromusic.appwidgets.AppWidgetSmall" android:name=".appwidgets.AppWidgetSmall"
android:exported="true" android:exported="true"
android:label="@string/app_widget_small_name"> android:label="@string/app_widget_small_name">
<intent-filter> <intent-filter>
@ -250,7 +245,7 @@
android:resource="@xml/app_widget_small_info" /> android:resource="@xml/app_widget_small_info" />
</receiver> </receiver>
<receiver <receiver
android:name="code.name.monkey.retromusic.appwidgets.AppWidgetText" android:name=".appwidgets.AppWidgetText"
android:exported="true" android:exported="true"
android:label="@string/app_widget_text_name"> android:label="@string/app_widget_text_name">
<intent-filter> <intent-filter>
@ -262,7 +257,7 @@
android:resource="@xml/app_widget_text" /> android:resource="@xml/app_widget_text" />
</receiver> </receiver>
<receiver <receiver
android:name="code.name.monkey.retromusic.appwidgets.AppWidgetCard" android:name=".appwidgets.AppWidgetCard"
android:exported="true" android:exported="true"
android:label="@string/app_widget_card_name"> android:label="@string/app_widget_card_name">
<intent-filter> <intent-filter>
@ -274,7 +269,7 @@
android:resource="@xml/app_widget_card_info" /> android:resource="@xml/app_widget_card_info" />
</receiver> </receiver>
<receiver <receiver
android:name="code.name.monkey.retromusic.appwidgets.AppWidgetMD3" android:name=".appwidgets.AppWidgetMD3"
android:exported="true" android:exported="true"
android:label="@string/app_widget_md3_name"> android:label="@string/app_widget_md3_name">
<intent-filter> <intent-filter>
@ -286,7 +281,7 @@
android:resource="@xml/app_widget_md3_info" /> android:resource="@xml/app_widget_md3_info" />
</receiver> </receiver>
<receiver <receiver
android:name="code.name.monkey.retromusic.appwidgets.AppWidgetCircle" android:name=".appwidgets.AppWidgetCircle"
android:exported="true" android:exported="true"
android:label="@string/app_widget_circle_name"> android:label="@string/app_widget_circle_name">
<intent-filter> <intent-filter>
@ -299,7 +294,7 @@
</receiver> </receiver>
<service <service
android:name="code.name.monkey.retromusic.service.MusicService" android:name=".service.MusicService"
android:enabled="true" android:enabled="true"
android:exported="true" android:exported="true"
android:foregroundServiceType="mediaPlayback" android:foregroundServiceType="mediaPlayback"
@ -307,9 +302,6 @@
<intent-filter> <intent-filter>
<action android:name="android.media.browse.MediaBrowserService" /> <action android:name="android.media.browse.MediaBrowserService" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</service> </service>
<meta-data <meta-data

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -62,6 +62,68 @@
</head> </head>
<body> <body>
<div>
<h5>March 13, 2023</h5>
<h2>v6.0.4</h2>
<h3>What's New</h3>
<ul>
<li>Minor redesign in Playlist details screen</li>
<li>Updated translations</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fixed file popup menu actions in Folders tab</li>
<li>Fixed playlist image loading</li>
<li>Fixed blurry album art in Android 13</li>
<li>Minor bug fixes and improvements</li>
</ul>
</div>
<div>
<h5>July 10, 2022</h5>
<h2>v6.0.3<span class="tag"><i>Beta</i></span></h2>
<h3>Fixed</h3>
<ul>
<li>Migrated icons to Material symbols</li>
</ul>
</div>
<div>
<h5>June 21, 2022</h5>
<h2>v6.0.2<span class="tag"><i>Beta</i></span></h2>
<h3>Fixed</h3>
<ul>
<li>Minor bug fixes and improvements</li>
</ul>
</div>
<div>
<h5>June 13, 2022</h5>
<h2>v6.0.1<span class="tag"><i>Beta</i></span></h2>
<h3>Fixed</h3>
<ul>
<li>Fixed ChromeCast crash</li>
<li>Fixed Slider crashes</li>
<li>Fixed storage related crashes on Android 10</li>
<li>Fixed CrossFade not working Fade Audio is not working</li>
</ul>
</div>
<div>
<h5>June 7, 2022</h5>
<h2>v6.0.0<span class="tag"><i>Beta</i></span></h2>
<h3>What's New</h3>
<ul>
<li>Better Cast</li>
<li>Mini player in settings screen</li>
<li>Changed Seekbar with Sliders</li>
<li>Added NavigationRailView for Landscape</li>
<li>Show remaining time in Sleep timer dialog</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fixed Top/Recent Artists/Albums not updating (Wrong sort order)</li>
<li>Fixed all Blacklist related crashes</li>
<li>Fix restart button not working in crash activity</li>
</ul>
</div>
<div> <div>
<h5>May 25, 2022</h5> <h5>May 25, 2022</h5>
<h2>v5.8.5</h2> <h2>v5.8.5</h2>

View file

@ -10,14 +10,17 @@
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * 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. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
*/ */
package code.name.monkey.retromusic package code.name.monkey.retromusic
import android.app.Application import android.app.Application
import androidx.preference.PreferenceManager
import cat.ereza.customactivityoncrash.config.CaocConfig import cat.ereza.customactivityoncrash.config.CaocConfig
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.activities.ErrorActivity 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.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.helper.WallpaperAccentManager import code.name.monkey.retromusic.helper.WallpaperAccentManager
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
@ -38,7 +41,7 @@ class App : Application() {
// default theme // default theme
if (!ThemeStore.isConfigured(this, 3)) { if (!ThemeStore.isConfigured(this, 3)) {
ThemeStore.editTheme(this) ThemeStore.editTheme(this)
.accentColorRes(R.color.md_deep_purple_A200) .accentColorRes(code.name.monkey.appthemehelper.R.color.md_deep_purple_A200)
.coloredNavigationBar(true) .coloredNavigationBar(true)
.commit() .commit()
} }
@ -48,7 +51,12 @@ class App : Application() {
DynamicShortcutManager(this).initDynamicShortcuts() DynamicShortcutManager(this).initDynamicShortcuts()
// setting Error activity // setting Error activity
CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java).apply() CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java)
.restartActivity(MainActivity::class.java).apply()
// Set Default values for now playing preferences
// This will reduce startup time for now playing settings fragment as Preference listener of AbsSlidingMusicPanelActivity won't be called
PreferenceManager.setDefaultValues(this, R.xml.pref_now_playing_screen, false)
} }
override fun onTerminate() { override fun onTerminate() {

View file

@ -79,12 +79,7 @@ const val CIRCULAR_ALBUM_ART = "circular_album_art"
const val USER_NAME = "user_name" const val USER_NAME = "user_name"
const val TOGGLE_FULL_SCREEN = "toggle_full_screen" const val TOGGLE_FULL_SCREEN = "toggle_full_screen"
const val TOGGLE_VOLUME = "toggle_volume" const val TOGGLE_VOLUME = "toggle_volume"
const val ROUND_CORNERS = "corner_window"
const val TOGGLE_GENRE = "toggle_genre"
const val PROFILE_IMAGE_PATH = "profile_image_path"
const val BANNER_IMAGE_PATH = "banner_image_path"
const val ADAPTIVE_COLOR_APP = "adaptive_color_app" const val ADAPTIVE_COLOR_APP = "adaptive_color_app"
const val TOGGLE_SEPARATE_LINE = "toggle_separate_line"
const val HOME_ARTIST_GRID_STYLE = "home_artist_grid_style" const val HOME_ARTIST_GRID_STYLE = "home_artist_grid_style"
const val HOME_ALBUM_GRID_STYLE = "home_album_grid_style" const val HOME_ALBUM_GRID_STYLE = "home_album_grid_style"
const val TOGGLE_ADD_CONTROLS = "toggle_add_controls" const val TOGGLE_ADD_CONTROLS = "toggle_add_controls"
@ -99,7 +94,6 @@ const val SAF_SDCARD_URI = "saf_sdcard_uri"
const val SONG_SORT_ORDER = "song_sort_order" const val SONG_SORT_ORDER = "song_sort_order"
const val SONG_GRID_SIZE = "song_grid_size" const val SONG_GRID_SIZE = "song_grid_size"
const val GENRE_SORT_ORDER = "genre_sort_order" const val GENRE_SORT_ORDER = "genre_sort_order"
const val LAST_PAGE = "last_start_page"
const val BLUETOOTH_PLAYBACK = "bluetooth_playback" const val BLUETOOTH_PLAYBACK = "bluetooth_playback"
const val INITIALIZED_BLACKLIST = "initialized_blacklist" const val INITIALIZED_BLACKLIST = "initialized_blacklist"
const val ARTIST_SORT_ORDER = "artist_sort_order" const val ARTIST_SORT_ORDER = "artist_sort_order"
@ -132,7 +126,6 @@ const val ARTIST_DETAIL_SONG_SORT_ORDER = "artist_detail_song_sort_order"
const val LYRICS_OPTIONS = "lyrics_tab_position" const val LYRICS_OPTIONS = "lyrics_tab_position"
const val CHOOSE_EQUALIZER = "choose_equalizer" const val CHOOSE_EQUALIZER = "choose_equalizer"
const val EQUALIZER = "equalizer" const val EQUALIZER = "equalizer"
const val TOGGLE_SHUFFLE = "toggle_shuffle"
const val SONG_GRID_STYLE = "song_grid_style" const val SONG_GRID_STYLE = "song_grid_style"
const val PAUSE_ON_ZERO_VOLUME = "pause_on_zero_volume" const val PAUSE_ON_ZERO_VOLUME = "pause_on_zero_volume"
const val FILTER_SONG = "filter_song" const val FILTER_SONG = "filter_song"

View file

@ -3,7 +3,7 @@ package code.name.monkey.retromusic
import android.content.Context import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
import android.os.LocaleList import android.os.LocaleList
import code.name.monkey.appthemehelper.util.VersionUtils.hasNougatMR import code.name.monkey.appthemehelper.util.VersionUtils.hasNougat
import java.util.* import java.util.*
class LanguageContextWrapper(base: Context?) : ContextWrapper(base) { class LanguageContextWrapper(base: Context?) : ContextWrapper(base) {
@ -11,7 +11,7 @@ class LanguageContextWrapper(base: Context?) : ContextWrapper(base) {
fun wrap(context: Context?, newLocale: Locale?): LanguageContextWrapper { fun wrap(context: Context?, newLocale: Locale?): LanguageContextWrapper {
if (context == null) return LanguageContextWrapper(context) if (context == null) return LanguageContextWrapper(context)
val configuration = context.resources.configuration val configuration = context.resources.configuration
if (hasNougatMR()) { if (hasNougat()) {
configuration.setLocale(newLocale) configuration.setLocale(newLocale)
val localeList = LocaleList(newLocale) val localeList = LocaleList(newLocale)
LocaleList.setDefault(localeList) LocaleList.setDefault(localeList)

View file

@ -1,11 +1,8 @@
package code.name.monkey.retromusic package code.name.monkey.retromusic
import androidx.room.Room import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import code.name.monkey.retromusic.auto.AutoMusicProvider import code.name.monkey.retromusic.auto.AutoMusicProvider
import code.name.monkey.retromusic.db.BlackListStoreDao import code.name.monkey.retromusic.db.MIGRATION_23_24
import code.name.monkey.retromusic.db.BlackListStoreEntity
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.RetroDatabase import code.name.monkey.retromusic.db.RetroDatabase
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
@ -15,10 +12,6 @@ import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel
import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel
import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.repository.* import code.name.monkey.retromusic.repository.*
import code.name.monkey.retromusic.util.FilePathUtil
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.bind import org.koin.dsl.bind
@ -28,32 +21,14 @@ private val roomModule = module {
single { single {
Room.databaseBuilder(androidContext(), RetroDatabase::class.java, "playlist.db") Room.databaseBuilder(androidContext(), RetroDatabase::class.java, "playlist.db")
.allowMainThreadQueries() .addMigrations(MIGRATION_23_24)
.addCallback(object : RoomDatabase.Callback() {
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
GlobalScope.launch(IO) {
FilePathUtil.blacklistFilePaths().map {
get<BlackListStoreDao>().insertBlacklistPath(BlackListStoreEntity(it))
}
}
}
})
.fallbackToDestructiveMigration()
.build() .build()
} }
factory {
get<RetroDatabase>().lyricsDao()
}
factory { factory {
get<RetroDatabase>().playlistDao() get<RetroDatabase>().playlistDao()
} }
factory {
get<RetroDatabase>().blackListStore()
}
factory { factory {
get<RetroDatabase>().playCountDao() get<RetroDatabase>().playCountDao()
} }
@ -63,7 +38,7 @@ private val roomModule = module {
} }
single { single {
RealRoomRepository(get(), get(), get(), get(), get()) RealRoomRepository(get(), get(), get())
} bind RoomRepository::class } bind RoomRepository::class
} }
private val autoModule = module { private val autoModule = module {
@ -164,10 +139,10 @@ private val viewModules = module {
) )
} }
viewModel { (playlist: PlaylistWithSongs) -> viewModel { (playlistId: Long) ->
PlaylistDetailsViewModel( PlaylistDetailsViewModel(
get(), get(),
playlist playlistId
) )
} }

View file

@ -14,13 +14,10 @@
*/ */
package code.name.monkey.retromusic.activities package code.name.monkey.retromusic.activities
import android.animation.ObjectAnimator
import android.content.Intent import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.os.Bundle import android.os.Bundle
import android.view.animation.LinearInterpolator
import android.widget.SeekBar
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
@ -28,19 +25,19 @@ import code.name.monkey.retromusic.databinding.ActivityDriveModeBinding
import code.name.monkey.retromusic.db.toSongEntity import code.name.monkey.retromusic.db.toSongEntity
import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.drawAboveSystemBars import code.name.monkey.retromusic.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.glide.BlurTransformation import code.name.monkey.retromusic.glide.BlurTransformation
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler 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.model.Song
import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import com.bumptech.glide.Glide
import com.google.android.material.slider.Slider
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -68,7 +65,7 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
lastPlaybackControlsColor = accentColor() lastPlaybackControlsColor = accentColor()
binding.close.setOnClickListener { binding.close.setOnClickListener {
onBackPressed() onBackPressedDispatcher.onBackPressed()
} }
binding.repeatButton.drawAboveSystemBars() binding.repeatButton.drawAboveSystemBars()
} }
@ -113,17 +110,15 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
} }
private fun setUpProgressSlider() { private fun setUpProgressSlider() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() { binding.progressSlider.addOnChangeListener { _: Slider, progress: Float, fromUser: Boolean ->
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { if (fromUser) {
if (fromUser) { MusicPlayerRemote.seekTo(progress.toInt())
MusicPlayerRemote.seekTo(progress) onUpdateProgressViews(
onUpdateProgressViews( MusicPlayerRemote.songProgressMillis,
MusicPlayerRemote.songProgressMillis, MusicPlayerRemote.songDurationMillis
MusicPlayerRemote.songDurationMillis )
)
}
} }
}) }
} }
override fun onPause() { override fun onPause() {
@ -191,6 +186,7 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
lastPlaybackControlsColor, lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN PorterDuff.Mode.SRC_IN
) )
else -> binding.shuffleButton.setColorFilter( else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor, lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN PorterDuff.Mode.SRC_IN
@ -207,6 +203,7 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
PorterDuff.Mode.SRC_IN PorterDuff.Mode.SRC_IN
) )
} }
MusicService.REPEAT_MODE_ALL -> { MusicService.REPEAT_MODE_ALL -> {
binding.repeatButton.setImageResource(R.drawable.ic_repeat) binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter( binding.repeatButton.setColorFilter(
@ -214,6 +211,7 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
PorterDuff.Mode.SRC_IN PorterDuff.Mode.SRC_IN
) )
} }
MusicService.REPEAT_MODE_THIS -> { MusicService.REPEAT_MODE_THIS -> {
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one) binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter( binding.repeatButton.setColorFilter(
@ -241,7 +239,7 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
binding.songTitle.text = song.title binding.songTitle.text = song.title
binding.songText.text = song.artistName binding.songText.text = song.artistName
GlideApp.with(this) Glide.with(this)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.songCoverOptions(song) .songCoverOptions(song)
.transform(BlurTransformation.Builder(this).build()) .transform(BlurTransformation.Builder(this).build())
@ -249,12 +247,10 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
} }
override fun onUpdateProgressViews(progress: Int, total: Int) { override fun onUpdateProgressViews(progress: Int, total: Int) {
binding.progressSlider.max = total binding.progressSlider.run {
valueTo = total.toFloat()
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress) value = progress.toFloat().coerceIn(valueFrom, valueTo)
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME }
animator.interpolator = LinearInterpolator()
animator.start()
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong()) binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong()) binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())

View file

@ -3,32 +3,32 @@ package code.name.monkey.retromusic.activities
import android.os.Bundle import android.os.Bundle
import android.widget.Button import android.widget.Button
import android.widget.ImageView import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import cat.ereza.customactivityoncrash.CustomActivityOnCrash import cat.ereza.customactivityoncrash.CustomActivityOnCrash
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.FileUtils.createFile import code.name.monkey.retromusic.util.FileUtils.createFile
import code.name.monkey.retromusic.util.Share.shareFile import code.name.monkey.retromusic.util.Share.shareFile
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.text.DateFormat import java.text.DateFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
class ErrorActivity : AppCompatActivity() { class ErrorActivity : AppCompatActivity() {
private val dayFormat: DateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) private val dayFormat: DateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
private val ReportPrefix = "bug_report-" private val reportPrefix = "bug_report-"
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.customactivityoncrash_default_error_activity) setContentView(cat.ereza.customactivityoncrash.R.layout.customactivityoncrash_default_error_activity)
val restartButton = val restartButton =
findViewById<Button>(R.id.customactivityoncrash_error_activity_restart_button) findViewById<Button>(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_restart_button)
val config = CustomActivityOnCrash.getConfigFromIntent(intent) val config = CustomActivityOnCrash.getConfigFromIntent(intent)
if (config == null) { if (config == null) {
finish() finish()
return return
} }
restartButton.setText(R.string.customactivityoncrash_error_activity_restart_app) restartButton.setText(cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_restart_app)
restartButton.setOnClickListener { restartButton.setOnClickListener {
CustomActivityOnCrash.restartApplication( CustomActivityOnCrash.restartApplication(
this@ErrorActivity, this@ErrorActivity,
@ -36,11 +36,11 @@ class ErrorActivity : AppCompatActivity() {
) )
} }
val moreInfoButton = val moreInfoButton =
findViewById<Button>(R.id.customactivityoncrash_error_activity_more_info_button) findViewById<Button>(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_more_info_button)
moreInfoButton.setOnClickListener { //We retrieve all the error data and show it moreInfoButton.setOnClickListener { //We retrieve all the error data and show it
AlertDialog.Builder(this@ErrorActivity) MaterialAlertDialogBuilder(this@ErrorActivity)
.setTitle(R.string.customactivityoncrash_error_activity_error_details_title) .setTitle(cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_error_details_title)
.setMessage( .setMessage(
CustomActivityOnCrash.getAllErrorDetailsFromIntent( CustomActivityOnCrash.getAllErrorDetailsFromIntent(
this@ErrorActivity, this@ErrorActivity,
@ -48,7 +48,7 @@ class ErrorActivity : AppCompatActivity() {
) )
) )
.setPositiveButton( .setPositiveButton(
R.string.customactivityoncrash_error_activity_error_details_close, cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_error_details_close,
null null
) )
.setNeutralButton( .setNeutralButton(
@ -58,19 +58,19 @@ class ErrorActivity : AppCompatActivity() {
val bugReport = createFile( val bugReport = createFile(
context = this, context = this,
"Bug Report", "Bug Report",
"$ReportPrefix${dayFormat.format(Date())}", "$reportPrefix${dayFormat.format(Date())}",
CustomActivityOnCrash.getAllErrorDetailsFromIntent( CustomActivityOnCrash.getAllErrorDetailsFromIntent(
this@ErrorActivity, this@ErrorActivity,
intent intent
), ".txt" ), ".txt"
) )
shareFile(this, bugReport) shareFile(this, bugReport, "text/*")
} }
.show() .show()
} }
val errorActivityDrawableId = config.errorDrawable val errorActivityDrawableId = config.errorDrawable
val errorImageView = val errorImageView =
findViewById<ImageView>(R.id.customactivityoncrash_error_activity_image) findViewById<ImageView>(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_image)
if (errorActivityDrawableId != null) { if (errorActivityDrawableId != null) {
errorImageView.setImageResource( errorImageView.setImageResource(
errorActivityDrawableId errorActivityDrawableId

View file

@ -77,7 +77,7 @@ class LicenseActivity : AbsThemeActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) { if (item.itemId == android.R.id.home) {
onBackPressed() onBackPressedDispatcher.onBackPressed()
return true return true
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)

View file

@ -26,11 +26,13 @@ import code.name.monkey.retromusic.extensions.hideStatusBar
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.extensions.whichFragment import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.fragments.player.lockscreen.LockScreenControlsFragment import code.name.monkey.retromusic.fragments.player.lockscreen.LockScreenControlsFragment
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import com.r0adkll.slidr.Slidr import com.r0adkll.slidr.Slidr
import com.r0adkll.slidr.model.SlidrConfig import com.r0adkll.slidr.model.SlidrConfig
import com.r0adkll.slidr.model.SlidrListener import com.r0adkll.slidr.model.SlidrListener
@ -84,12 +86,11 @@ class LockScreenActivity : AbsMusicServiceActivity() {
private fun lockScreenInit() { private fun lockScreenInit() {
if (VersionUtils.hasOreoMR1()) { if (VersionUtils.hasOreoMR1()) {
setShowWhenLocked(true) setShowWhenLocked(true)
val keyguardManager = getSystemService<KeyguardManager>() //setTurnScreenOn(true)
keyguardManager?.requestDismissKeyguard(this, null)
} else { } else {
this.window.addFlags( window.addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED // or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
) )
} }
} }
@ -106,7 +107,7 @@ class LockScreenActivity : AbsMusicServiceActivity() {
private fun updateSongs() { private fun updateSongs() {
val song = MusicPlayerRemote.currentSong val song = MusicPlayerRemote.currentSong
GlideApp.with(this) Glide.with(this)
.asBitmapPalette() .asBitmapPalette()
.songCoverOptions(song) .songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))

View file

@ -15,18 +15,15 @@
package code.name.monkey.retromusic.activities package code.name.monkey.retromusic.activities
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.MediaStore import android.provider.MediaStore
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.contains import androidx.navigation.contains
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import code.name.monkey.retromusic.* import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs
import code.name.monkey.retromusic.interfaces.IScrollHelper import code.name.monkey.retromusic.interfaces.IScrollHelper
@ -35,20 +32,17 @@ import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.repository.PlaylistSongsLoader import code.name.monkey.retromusic.repository.PlaylistSongsLoader
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.logE
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener { class MainActivity : AbsSlidingMusicPanelActivity() {
companion object { companion object {
const val TAG = "MainActivity" const val TAG = "MainActivity"
const val EXPAND_PANEL = "expand_panel" const val EXPAND_PANEL = "expand_panel"
} }
override fun createContentView(): SlidingMusicPanelLayoutBinding {
return wrapSlidingMusicPanel()
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
@ -56,9 +50,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
updateTabs() updateTabs()
setupNavigationController() setupNavigationController()
if (!hasPermissions()) {
findNavController(R.id.fragment_container).navigate(R.id.permissionFragment)
}
WhatsNewFragment.showChangeLog(this) WhatsNewFragment.showChangeLog(this)
} }
@ -84,9 +76,9 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
) )
} }
navController.graph = navGraph navController.graph = navGraph
bottomNavigationView.setupWithNavController(navController) navigationView.setupWithNavController(navController)
// Scroll Fragment to top // Scroll Fragment to top
bottomNavigationView.setOnItemReselectedListener { navigationView.setOnItemReselectedListener {
currentFragment(R.id.fragment_container).apply { currentFragment(R.id.fragment_container).apply {
if (this is IScrollHelper) { if (this is IScrollHelper) {
scrollToTop() scrollToTop()
@ -118,7 +110,9 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
} }
private fun saveTab(id: Int) { private fun saveTab(id: Int) {
PreferenceUtil.lastTab = id if (PreferenceUtil.libraryCategory.firstOrNull { it.category.id == id }?.visible == true) {
PreferenceUtil.lastTab = id
}
} }
override fun onSupportNavigateUp(): Boolean = override fun onSupportNavigateUp(): Boolean =
@ -135,22 +129,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
} }
} }
override fun onResume() {
super.onResume()
PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
}
override fun onDestroy() {
super.onDestroy()
PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key == GENERAL_THEME || key == MATERIAL_YOU || key == WALLPAPER_ACCENT || key == BLACK_THEME || key == ADAPTIVE_COLOR_APP || key == USER_NAME || key == TOGGLE_FULL_SCREEN || key == TOGGLE_VOLUME || key == ROUND_CORNERS || key == CAROUSEL_EFFECT || key == NOW_PLAYING_SCREEN_ID || key == TOGGLE_GENRE || key == BANNER_IMAGE_PATH || key == PROFILE_IMAGE_PATH || key == CIRCULAR_ALBUM_ART || key == KEEP_SCREEN_ON || key == TOGGLE_SEPARATE_LINE || key == TOGGLE_HOME_BANNER || key == TOGGLE_ADD_CONTROLS || key == ALBUM_COVER_STYLE || key == HOME_ARTIST_GRID_STYLE || key == ALBUM_COVER_TRANSFORM || key == DESATURATED_COLOR || key == EXTRA_SONG_INFO || key == TAB_TEXT_MODE || key == LANGUAGE_NAME || key == LIBRARY_CATEGORIES || key == CUSTOM_FONT || key == APPBAR_MODE || key == CIRCLE_PLAY_BUTTON || key == SWIPE_DOWN_DISMISS) {
postRecreate()
}
}
override fun onServiceConnected() { override fun onServiceConnected() {
super.onServiceConnected() super.onServiceConnected()
intent ?: return intent ?: return
@ -218,7 +196,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
private fun parseLongFromIntent( private fun parseLongFromIntent(
intent: Intent, intent: Intent,
longKey: String, longKey: String,
stringKey: String stringKey: String,
): Long { ): Long {
var id = intent.getLongExtra(longKey, -1) var id = intent.getLongExtra(longKey, -1)
if (id < 0) { if (id < 0) {
@ -227,7 +205,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
try { try {
id = idString.toLong() id = idString.toLong()
} catch (e: NumberFormatException) { } catch (e: NumberFormatException) {
println(e.message) logE(e)
} }
} }
} }

View file

@ -22,6 +22,7 @@ import android.content.res.ColorStateList
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import androidx.activity.OnBackPressedCallback
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.net.toUri import androidx.core.net.toUri
@ -30,8 +31,8 @@ import androidx.core.view.isVisible
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.databinding.ActivityPermissionBinding import code.name.monkey.retromusic.databinding.ActivityPermissionBinding
import code.name.monkey.retromusic.extensions.*
class PermissionActivity : AbsMusicServiceActivity() { class PermissionActivity : AbsMusicServiceActivity() {
private lateinit var binding: ActivityPermissionBinding private lateinit var binding: ActivityPermissionBinding
@ -61,10 +62,14 @@ class PermissionActivity : AbsMusicServiceActivity() {
if (VersionUtils.hasS()) { if (VersionUtils.hasS()) {
binding.bluetoothPermission.show() binding.bluetoothPermission.show()
binding.bluetoothPermission.setButtonClick { binding.bluetoothPermission.setButtonClick {
ActivityCompat.requestPermissions(this, ActivityCompat.requestPermissions(
this,
arrayOf(BLUETOOTH_CONNECT), arrayOf(BLUETOOTH_CONNECT),
PERMISSION_REQUEST) BLUETOOTH_PERMISSION_REQUEST
)
} }
} else {
binding.audioPermission.setNumber("2")
} }
binding.finish.accentBackgroundColor() binding.finish.accentBackgroundColor()
@ -79,12 +84,20 @@ class PermissionActivity : AbsMusicServiceActivity() {
finish() finish()
} }
} }
onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
finishAffinity()
remove()
}
})
} }
private fun setupTitle() { private fun setupTitle() {
val appName = val appName =
getString(R.string.message_welcome, getString(
"<b>Metro</b>") R.string.message_welcome,
"<b>Metro</b>"
)
.parseAsHtml() .parseAsHtml()
binding.appNameText.text = appName binding.appNameText.text = appName
} }
@ -114,23 +127,22 @@ class PermissionActivity : AbsMusicServiceActivity() {
} }
private fun hasStoragePermission(): Boolean { private fun hasStoragePermission(): Boolean {
return ActivityCompat.checkSelfPermission(this, return ActivityCompat.checkSelfPermission(
Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED this,
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
} }
@RequiresApi(Build.VERSION_CODES.S) @RequiresApi(Build.VERSION_CODES.S)
private fun hasBluetoothPermission(): Boolean { private fun hasBluetoothPermission(): Boolean {
return ActivityCompat.checkSelfPermission(this, return ActivityCompat.checkSelfPermission(
BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED this,
BLUETOOTH_CONNECT
) == PackageManager.PERMISSION_GRANTED
} }
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
private fun hasAudioPermission(): Boolean { private fun hasAudioPermission(): Boolean {
return Settings.System.canWrite(this) return Settings.System.canWrite(this)
} }
override fun onBackPressed() {
super.onBackPressed()
finishAffinity()
}
} }

View file

@ -22,26 +22,28 @@ import android.os.Bundle
import android.provider.MediaStore.Images.Media import android.provider.MediaStore.Images.Media
import android.view.MenuItem import android.view.MenuItem
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.core.os.BundleCompat
import androidx.core.view.drawToBitmap import androidx.core.view.drawToBitmap
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.MaterialValueHelper
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.databinding.ActivityShareInstagramBinding
import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.setLightStatusBar
import code.name.monkey.retromusic.extensions.setStatusBarColor import code.name.monkey.retromusic.extensions.setStatusBarColor
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.RetroMusicColoredTarget
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.Share import code.name.monkey.retromusic.util.Share
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
/** /**
* Created by hemanths on 2020-02-02. * Created by hemanths on 2020-02-02.
*/ */
class ShareInstagramStory : AbsBaseActivity() { class ShareInstagramStory : AbsThemeActivity() {
private lateinit var binding: ActivityShareInstagramBinding private lateinit var binding: ActivityShareInstagramBinding
@ -51,7 +53,7 @@ class ShareInstagramStory : AbsBaseActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) { if (item.itemId == android.R.id.home) {
onBackPressed() onBackPressedDispatcher.onBackPressed()
return true return true
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
@ -66,16 +68,15 @@ class ShareInstagramStory : AbsBaseActivity() {
binding.toolbar.setBackgroundColor(Color.TRANSPARENT) binding.toolbar.setBackgroundColor(Color.TRANSPARENT)
setSupportActionBar(binding.toolbar) setSupportActionBar(binding.toolbar)
val song = intent.extras?.getParcelable<Song>(EXTRA_SONG) val song = intent.extras?.let { BundleCompat.getParcelable(it, EXTRA_SONG, Song::class.java) }
song?.let { songFinal -> song?.let { songFinal ->
GlideApp.with(this) Glide.with(this)
.asBitmapPalette() .asBitmapPalette()
.songCoverOptions(songFinal) .songCoverOptions(songFinal)
.load(RetroGlideExtension.getSongModel(songFinal)) .load(RetroGlideExtension.getSongModel(songFinal))
.into(object : RetroMusicColoredTarget(binding.image) { .into(object : RetroMusicColoredTarget(binding.image) {
override fun onColorReady(colors: MediaNotificationProcessor) { override fun onColorReady(colors: MediaNotificationProcessor) {
val isColorLight = ColorUtil.isColorLight(colors.backgroundColor) setColors(colors.backgroundColor)
setColors(isColorLight, colors.backgroundColor)
} }
}) })
@ -103,22 +104,7 @@ class ShareInstagramStory : AbsBaseActivity() {
ColorStateList.valueOf(accentColor()) ColorStateList.valueOf(accentColor())
} }
private fun setColors(colorLight: Boolean, color: Int) { private fun setColors(color: Int) {
setLightStatusBar(colorLight)
binding.toolbar.setTitleTextColor(
MaterialValueHelper.getPrimaryTextColor(
this@ShareInstagramStory,
colorLight
)
)
binding.toolbar.navigationIcon?.setTintList(
ColorStateList.valueOf(
MaterialValueHelper.getPrimaryTextColor(
this@ShareInstagramStory,
colorLight
)
)
)
binding.mainContent.background = binding.mainContent.background =
GradientDrawable( GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM, GradientDrawable.Orientation.TOP_BOTTOM,

View file

@ -1,12 +1,17 @@
package code.name.monkey.retromusic.activities package code.name.monkey.retromusic.activities
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.core.content.PackageManagerCompat
import androidx.core.content.pm.PackageInfoCompat import androidx.core.content.pm.PackageInfoCompat
import androidx.core.widget.NestedScrollView import androidx.core.widget.NestedScrollView
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
@ -22,7 +27,7 @@ import code.name.monkey.retromusic.extensions.openUrl
import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.util.* import java.util.Locale
class WhatsNewFragment : BottomSheetDialogFragment() { class WhatsNewFragment : BottomSheetDialogFragment() {
private var _binding: FragmentWhatsNewBinding? = null private var _binding: FragmentWhatsNewBinding? = null
@ -41,7 +46,7 @@ class WhatsNewFragment : BottomSheetDialogFragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
try { try {
val buf = StringBuilder() val buf = StringBuilder()
val stream= requireContext().assets.open("retro-changelog.html") val stream = requireContext().assets.open("retro-changelog.html")
stream.reader(StandardCharsets.UTF_8).buffered().use { br -> stream.reader(StandardCharsets.UTF_8).buffered().use { br ->
var str: String? var str: String?
while (br.readLine().also { str = it } != null) { while (br.readLine().also { str = it } != null) {
@ -76,6 +81,17 @@ class WhatsNewFragment : BottomSheetDialogFragment() {
) )
) )
binding.webView.loadData(changeLog, "text/html", "UTF-8") 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) { } catch (e: Throwable) {
binding.webView.loadData( binding.webView.loadData(
"<h1>Unable to load</h1><p>" + e.localizedMessage + "</p>", "text/html", "UTF-8" "<h1>Unable to load</h1><p>" + e.localizedMessage + "</p>", "text/html", "UTF-8"

View file

@ -32,6 +32,8 @@ import androidx.core.content.getSystemService
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.accentColor 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 import com.google.android.material.snackbar.Snackbar
abstract class AbsBaseActivity : AbsThemeActivity() { abstract class AbsBaseActivity : AbsThemeActivity() {
@ -52,7 +54,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
} }
private val snackBarContainer: View private val snackBarContainer: View
get() = window.decorView get() = rootView
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -75,7 +77,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
protected open fun onHasPermissionsChanged(hasPermissions: Boolean) { protected open fun onHasPermissionsChanged(hasPermissions: Boolean) {
// implemented by sub classes // implemented by sub classes
println(hasPermissions) logD(hasPermissions)
} }
override fun dispatchKeyEvent(event: KeyEvent): Boolean { override fun dispatchKeyEvent(event: KeyEvent): Boolean {
@ -114,33 +116,19 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
for (grantResult in grantResults) { for (grantResult in grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) { if (grantResult != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale( 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( Snackbar.make(
snackBarContainer, snackBarContainer,
permissionDeniedMessage!!, permissionDeniedMessage!!,
Snackbar.LENGTH_INDEFINITE Snackbar.LENGTH_SHORT
) )
.setAction(R.string.action_grant) { requestPermissions() } .setAction(R.string.action_grant) { requestPermissions() }
.setActionTextColor(accentColor()).show() .setActionTextColor(accentColor()).show()
} else 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_INDEFINITE
)
.setAction(R.string.action_grant) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.BLUETOOTH_CONNECT),
PERMISSION_REQUEST)
}
.setActionTextColor(accentColor()).show()
} else { } else {
// User has deny permission and checked never show permission dialog so you can redirect to Application settings page // User has deny permission and checked never show permission dialog so you can redirect to Application settings page
Snackbar.make( Snackbar.make(
@ -165,11 +153,34 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
} }
hadPermissions = true hadPermissions = true
onHasPermissionsChanged(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 { companion object {
const val PERMISSION_REQUEST = 100 const val PERMISSION_REQUEST = 100
const val BLUETOOTH_PERMISSION_REQUEST = 101
} }
// this lets keyboard close when clicked in background // this lets keyboard close when clicked in background

View file

@ -33,6 +33,7 @@ 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.REPEAT_MODE_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.SHUFFLE_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.PreferenceUtil
import code.name.monkey.retromusic.util.logD
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -185,12 +186,12 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventLi
true true
) // just in case we need to know this at some point ) // just in case we need to know this at some point
sendBroadcast(intent) sendBroadcast(intent)
println("sendBroadcast $hasPermissions") logD("sendBroadcast $hasPermissions")
} }
override fun getPermissionsToRequest(): Array<String> { override fun getPermissionsToRequest(): Array<String> {
return mutableListOf(Manifest.permission.READ_EXTERNAL_STORAGE).apply { return mutableListOf(Manifest.permission.READ_EXTERNAL_STORAGE).apply {
if (!VersionUtils.hasQ()) { if (!VersionUtils.hasR()) {
add(Manifest.permission.WRITE_EXTERNAL_STORAGE) add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
} }
}.toTypedArray() }.toTypedArray()

View file

@ -16,6 +16,8 @@ package code.name.monkey.retromusic.activities.base
import android.animation.ArgbEvaluator import android.animation.ArgbEvaluator
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.content.Intent
import android.content.SharedPreferences
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
@ -24,14 +26,31 @@ import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.view.animation.PathInterpolator import android.view.animation.PathInterpolator
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.activity.OnBackPressedCallback
import androidx.core.animation.doOnEnd import androidx.core.animation.doOnEnd
import androidx.core.view.* import androidx.core.view.*
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit import androidx.fragment.app.commit
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.extensions.* 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.R
import code.name.monkey.retromusic.SCREEN_ON_LYRICS
import code.name.monkey.retromusic.SWIPE_ANYWHERE_NOW_PLAYING
import code.name.monkey.retromusic.SWIPE_DOWN_DISMISS
import code.name.monkey.retromusic.TAB_TEXT_MODE
import code.name.monkey.retromusic.TOGGLE_ADD_CONTROLS
import code.name.monkey.retromusic.TOGGLE_FULL_SCREEN
import code.name.monkey.retromusic.TOGGLE_VOLUME
import code.name.monkey.retromusic.activities.PermissionActivity
import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.LibraryViewModel 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.NowPlayingScreen.* import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
@ -60,12 +79,21 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.CategoryInfo import code.name.monkey.retromusic.model.CategoryInfo
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil import code.name.monkey.retromusic.util.ViewUtil
import code.name.monkey.retromusic.util.logD
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.* import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_DRAGGING
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_SETTLING
import com.google.android.material.bottomsheet.BottomSheetBehavior.from
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
SharedPreferences.OnSharedPreferenceChangeListener {
companion object { companion object {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
} }
@ -74,13 +102,13 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
private var windowInsets: WindowInsetsCompat? = null private var windowInsets: WindowInsetsCompat? = null
protected val libraryViewModel by viewModel<LibraryViewModel>() protected val libraryViewModel by viewModel<LibraryViewModel>()
private lateinit var bottomSheetBehavior: BottomSheetBehavior<FrameLayout> private lateinit var bottomSheetBehavior: BottomSheetBehavior<FrameLayout>
private var playerFragment: AbsPlayerFragment? = null private lateinit var playerFragment: AbsPlayerFragment
private var miniPlayerFragment: MiniPlayerFragment? = null private var miniPlayerFragment: MiniPlayerFragment? = null
private var nowPlayingScreen: NowPlayingScreen? = null private var nowPlayingScreen: NowPlayingScreen? = null
private var taskColor: Int = 0 private var taskColor: Int = 0
private var paletteColor: Int = Color.WHITE private var paletteColor: Int = Color.WHITE
private var navigationBarColor = 0 private var navigationBarColor = 0
protected abstract fun createContentView(): SlidingMusicPanelLayoutBinding
private val panelState: Int private val panelState: Int
get() = bottomSheetBehavior.state get() = bottomSheetBehavior.state
private lateinit var binding: SlidingMusicPanelLayoutBinding private lateinit var binding: SlidingMusicPanelLayoutBinding
@ -89,45 +117,51 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
private var navigationBarColorAnimator: ValueAnimator? = null private var navigationBarColorAnimator: ValueAnimator? = null
private val argbEvaluator: ArgbEvaluator = ArgbEvaluator() private val argbEvaluator: ArgbEvaluator = ArgbEvaluator()
private val bottomSheetCallbackList = object : BottomSheetCallback() { private val bottomSheetCallbackList by lazy {
object : BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) { override fun onSlide(bottomSheet: View, slideOffset: Float) {
setMiniPlayerAlphaProgress(slideOffset) setMiniPlayerAlphaProgress(slideOffset)
navigationBarColorAnimator?.cancel() navigationBarColorAnimator?.cancel()
setNavigationBarColorPreOreo( setNavigationBarColorPreOreo(
argbEvaluator.evaluate( argbEvaluator.evaluate(
slideOffset, slideOffset,
surfaceColor(), surfaceColor(),
navigationBarColor navigationBarColor
) as Int ) as Int
) )
} }
override fun onStateChanged(bottomSheet: View, newState: Int) { override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) { when (newState) {
STATE_EXPANDED -> { STATE_EXPANDED -> {
onPanelExpanded() onPanelExpanded()
if (PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics) { if (PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics) {
keepScreenOn(true) keepScreenOn(true)
}
} }
}
STATE_COLLAPSED -> { STATE_COLLAPSED -> {
onPanelCollapsed() onPanelCollapsed()
if ((PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics) || !PreferenceUtil.isScreenOnEnabled) { if ((PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics) || !PreferenceUtil.isScreenOnEnabled) {
keepScreenOn(false) keepScreenOn(false)
}
} }
}
STATE_SETTLING, STATE_DRAGGING -> { STATE_SETTLING, STATE_DRAGGING -> {
if (fromNotification) { if (fromNotification) {
binding.bottomNavigationView.bringToFront() binding.navigationView.bringToFront()
fromNotification = false fromNotification = false
}
}
STATE_HIDDEN -> {
MusicPlayerRemote.clearQueue()
}
else -> {
logD("Do a flip")
} }
}
STATE_HIDDEN -> {
MusicPlayerRemote.clearQueue()
}
else -> {
println("Do a flip")
} }
} }
} }
@ -137,12 +171,14 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = createContentView() if (!hasPermissions()) {
startActivity(Intent(this, PermissionActivity::class.java))
finish()
}
binding = SlidingMusicPanelLayoutBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener( binding.root.setOnApplyWindowInsetsListener { _, insets ->
binding.root windowInsets = WindowInsetsCompat.toWindowInsetsCompat(insets)
) { _, insets ->
windowInsets = insets
insets insets
} }
chooseFragmentForTheme() chooseFragmentForTheme()
@ -151,7 +187,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
updateColor() updateColor()
if (!PreferenceUtil.materialYou) { if (!PreferenceUtil.materialYou) {
binding.slidingPanel.backgroundTintList = ColorStateList.valueOf(darkAccentColor()) binding.slidingPanel.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
bottomNavigationView.backgroundTintList = ColorStateList.valueOf(darkAccentColor()) navigationView.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
} }
navigationBarColor = surfaceColor() navigationBarColor = surfaceColor()
@ -161,11 +197,13 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
bottomSheetBehavior = from(binding.slidingPanel) bottomSheetBehavior = from(binding.slidingPanel)
bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList) bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
bottomSheetBehavior.isHideable = PreferenceUtil.swipeDownToDismiss bottomSheetBehavior.isHideable = PreferenceUtil.swipeDownToDismiss
bottomSheetBehavior.significantVelocityThreshold = 300
setMiniPlayerAlphaProgress(0F) setMiniPlayerAlphaProgress(0F)
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
if (nowPlayingScreen != PreferenceUtil.nowPlayingScreen) { if (nowPlayingScreen != PreferenceUtil.nowPlayingScreen) {
postRecreate() postRecreate()
} }
@ -177,10 +215,69 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList) bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList)
PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)
} }
protected fun wrapSlidingMusicPanel(): SlidingMusicPanelLayoutBinding { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
return SlidingMusicPanelLayoutBinding.inflate(layoutInflater) when (key) {
SWIPE_DOWN_DISMISS -> {
bottomSheetBehavior.isHideable = PreferenceUtil.swipeDownToDismiss
}
TOGGLE_ADD_CONTROLS -> {
miniPlayerFragment?.setUpButtons()
}
NOW_PLAYING_SCREEN_ID -> {
chooseFragmentForTheme()
binding.slidingPanel.updateLayoutParams<ViewGroup.LayoutParams> {
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()
}
}
} }
fun collapsePanel() { fun collapsePanel() {
@ -196,8 +293,10 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
val alpha = 1 - progress val alpha = 1 - progress
miniPlayerFragment?.view?.alpha = 1 - (progress / 0.2F) miniPlayerFragment?.view?.alpha = 1 - (progress / 0.2F)
miniPlayerFragment?.view?.isGone = alpha == 0f miniPlayerFragment?.view?.isGone = alpha == 0f
binding.bottomNavigationView.translationY = progress * 500 if (!isLandscape) {
binding.bottomNavigationView.alpha = alpha binding.navigationView.translationY = progress * 500
binding.navigationView.alpha = alpha
}
binding.playerFragmentContainer.alpha = (progress - 0.2F) / 0.2F binding.playerFragmentContainer.alpha = (progress - 0.2F) / 0.2F
} }
@ -224,13 +323,13 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
setLightStatusBarAuto() setLightStatusBarAuto()
setLightNavigationBarAuto() setLightNavigationBarAuto()
setTaskDescriptionColor(taskColor) setTaskDescriptionColor(taskColor)
playerFragment?.onHide() //playerFragment?.onHide()
} }
open fun onPanelExpanded() { open fun onPanelExpanded() {
setMiniPlayerAlphaProgress(1F) setMiniPlayerAlphaProgress(1F)
onPaletteColorChanged() onPaletteColorChanged()
playerFragment?.onShow() //playerFragment?.onShow()
} }
private fun setupSlidingUpPanel() { private fun setupSlidingUpPanel() {
@ -254,21 +353,15 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}) })
} }
val bottomNavigationView get() = binding.bottomNavigationView val navigationView get() = binding.navigationView
val slidingPanel get() = binding.slidingPanel val slidingPanel get() = binding.slidingPanel
val isBottomNavVisible get() = navigationView.isVisible && navigationView is BottomNavigationView
override fun onServiceConnected() { override fun onServiceConnected() {
super.onServiceConnected() super.onServiceConnected()
if (MusicPlayerRemote.playingQueue.isNotEmpty()) { hideBottomSheet(false)
binding.slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
binding.slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
hideBottomSheet(false)
}
})
} // don't call hideBottomSheet(true) here as it causes a bug with the SlidingUpPanelLayout
} }
override fun onQueueChanged() { override fun onQueueChanged() {
@ -280,12 +373,8 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
} }
} }
override fun onBackPressed() {
if (!handleBackPress()) super.onBackPressed()
}
private fun handleBackPress(): Boolean { private fun handleBackPress(): Boolean {
if (bottomSheetBehavior.peekHeight != 0 && playerFragment!!.onBackPressed()) return true if (bottomSheetBehavior.peekHeight != 0 && playerFragment.onBackPressed()) return true
if (panelState == STATE_EXPANDED) { if (panelState == STATE_EXPANDED) {
collapsePanel() collapsePanel()
return true return true
@ -332,18 +421,20 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
} }
fun updateTabs() { fun updateTabs() {
binding.bottomNavigationView.menu.clear() binding.navigationView.menu.clear()
val currentTabs: List<CategoryInfo> = PreferenceUtil.libraryCategory val currentTabs: List<CategoryInfo> = PreferenceUtil.libraryCategory
for (tab in currentTabs) { for (tab in currentTabs) {
if (tab.visible) { if (tab.visible) {
val menu = tab.category val menu = tab.category
binding.bottomNavigationView.menu.add(0, menu.id, 0, menu.stringRes) binding.navigationView.menu.add(0, menu.id, 0, menu.stringRes)
.setIcon(menu.icon) .setIcon(menu.icon)
} }
} }
if (binding.bottomNavigationView.menu.size() == 1) { if (binding.navigationView.menu.size() == 1) {
isInOneTabMode = true isInOneTabMode = true
binding.bottomNavigationView.hide() binding.navigationView.isVisible = false
} else {
isInOneTabMode = false
} }
} }
@ -359,7 +450,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
animate: Boolean = false, animate: Boolean = false,
hideBottomSheet: Boolean = MusicPlayerRemote.playingQueue.isEmpty(), hideBottomSheet: Boolean = MusicPlayerRemote.playingQueue.isEmpty(),
) { ) {
if (!ViewCompat.isLaidOut(bottomNavigationView)) { if (!ViewCompat.isLaidOut(navigationView)) {
return return
} }
if (isInOneTabMode) { if (isInOneTabMode) {
@ -370,38 +461,38 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
) )
return return
} }
val mAnimate = animate && bottomSheetBehavior.state == STATE_COLLAPSED if (visible xor navigationView.isVisible) {
if (mAnimate) { val mAnimate = animate && bottomSheetBehavior.state == STATE_COLLAPSED
if (visible) { if (mAnimate) {
binding.bottomNavigationView.bringToFront() if (visible) {
binding.bottomNavigationView.show() binding.navigationView.bringToFront()
binding.navigationView.show()
} else {
binding.navigationView.hide()
}
} else { } else {
binding.bottomNavigationView.hide() binding.navigationView.isVisible = visible
} if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
} else { binding.navigationView.bringToFront()
binding.bottomNavigationView.isVisible = false }
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
binding.bottomNavigationView.bringToFront()
} }
} }
hideBottomSheet( hideBottomSheet(
hide = hideBottomSheet, hide = hideBottomSheet,
animate = animate, animate = animate,
isBottomNavVisible = visible isBottomNavVisible = visible && navigationView is BottomNavigationView
) )
} }
fun hideBottomSheet( fun hideBottomSheet(
hide: Boolean, hide: Boolean,
animate: Boolean = false, animate: Boolean = false,
isBottomNavVisible: Boolean = bottomNavigationView.isVisible, isBottomNavVisible: Boolean = navigationView.isVisible && navigationView is BottomNavigationView,
) { ) {
val heightOfBar = val heightOfBar = windowInsets.getBottomInsets() + dip(R.dimen.mini_player_height)
windowInsets.safeGetBottomInsets() +
if (MusicPlayerRemote.isCasting) dip(R.dimen.cast_mini_player_height) else dip(R.dimen.mini_player_height)
val heightOfBarWithTabs = heightOfBar + dip(R.dimen.bottom_nav_height) val heightOfBarWithTabs = heightOfBar + dip(R.dimen.bottom_nav_height)
if (hide) { if (hide) {
bottomSheetBehavior.peekHeight = -windowInsets.safeGetBottomInsets() bottomSheetBehavior.peekHeight = -windowInsets.getBottomInsets()
bottomSheetBehavior.state = STATE_COLLAPSED bottomSheetBehavior.state = STATE_COLLAPSED
libraryViewModel.setFabMargin( libraryViewModel.setFabMargin(
this, this,
@ -410,17 +501,20 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
} else { } else {
if (MusicPlayerRemote.playingQueue.isNotEmpty()) { if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
binding.slidingPanel.elevation = 0F binding.slidingPanel.elevation = 0F
binding.bottomNavigationView.elevation = 5F binding.navigationView.elevation = 5F
if (isBottomNavVisible) { if (isBottomNavVisible) {
println("List") logD("List")
if (animate) { if (animate) {
bottomSheetBehavior.peekHeightAnimate(heightOfBarWithTabs) bottomSheetBehavior.peekHeightAnimate(heightOfBarWithTabs)
} else { } else {
bottomSheetBehavior.peekHeight = heightOfBarWithTabs bottomSheetBehavior.peekHeight = heightOfBarWithTabs
} }
libraryViewModel.setFabMargin(this, dip(R.dimen.mini_player_height_expanded)) libraryViewModel.setFabMargin(
this,
dip(R.dimen.bottom_nav_mini_player_height)
)
} else { } else {
println("Details") logD("Details")
if (animate) { if (animate) {
bottomSheetBehavior.peekHeightAnimate(heightOfBar).doOnEnd { bottomSheetBehavior.peekHeightAnimate(heightOfBar).doOnEnd {
binding.slidingPanel.bringToFront() binding.slidingPanel.bringToFront()
@ -443,7 +537,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
private fun chooseFragmentForTheme() { private fun chooseFragmentForTheme() {
nowPlayingScreen = PreferenceUtil.nowPlayingScreen nowPlayingScreen = PreferenceUtil.nowPlayingScreen
val fragment: Fragment = when (nowPlayingScreen) { val fragment: AbsPlayerFragment = when (nowPlayingScreen) {
Blur -> BlurPlayerFragment() Blur -> BlurPlayerFragment()
Adaptive -> AdaptiveFragment() Adaptive -> AdaptiveFragment()
Normal -> PlayerFragment() Normal -> PlayerFragment()
@ -463,12 +557,12 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
Classic -> ClassicPlayerFragment() Classic -> ClassicPlayerFragment()
MD3 -> MD3PlayerFragment() MD3 -> MD3PlayerFragment()
else -> PlayerFragment() else -> PlayerFragment()
} // must implement AbsPlayerFragment } // must extend AbsPlayerFragment
supportFragmentManager.commit { supportFragmentManager.commit {
replace(R.id.playerFragmentContainer, fragment) replace(R.id.playerFragmentContainer, fragment)
} }
supportFragmentManager.executePendingTransactions() supportFragmentManager.executePendingTransactions()
playerFragment = whichFragment<AbsPlayerFragment>(R.id.playerFragmentContainer) playerFragment = whichFragment(R.id.playerFragmentContainer)
miniPlayerFragment = whichFragment<MiniPlayerFragment>(R.id.miniPlayerFragment) miniPlayerFragment = whichFragment<MiniPlayerFragment>(R.id.miniPlayerFragment)
miniPlayerFragment?.view?.setOnClickListener { expandPanel() } miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
} }

View file

@ -20,15 +20,15 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.view.KeyEvent import android.view.KeyEvent
import android.view.View
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
import code.name.monkey.appthemehelper.common.ATHToolbarActivity import code.name.monkey.appthemehelper.common.ATHToolbarActivity
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.LanguageContextWrapper import code.name.monkey.retromusic.LanguageContextWrapper
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.R 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.PreferenceUtil
import code.name.monkey.retromusic.util.maybeShowAnnoyingToasts
import code.name.monkey.retromusic.util.theme.getNightMode import code.name.monkey.retromusic.util.theme.getNightMode
import code.name.monkey.retromusic.util.theme.getThemeResValue import code.name.monkey.retromusic.util.theme.getThemeResValue
import java.util.* import java.util.*
@ -42,13 +42,13 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
hideStatusBar() hideStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setEdgeToEdgeOrImmersive() setEdgeToEdgeOrImmersive()
registerSystemUiVisibility() maybeSetScreenOn()
toggleScreenOn()
setLightNavigationBarAuto() setLightNavigationBarAuto()
setLightStatusBarAuto(surfaceColor()) setLightStatusBarAuto(surfaceColor())
if (VersionUtils.hasQ()) { if (VersionUtils.hasQ()) {
window.decorView.isForceDarkAllowed = false window.decorView.isForceDarkAllowed = false
} }
maybeShowAnnoyingToasts()
} }
private fun updateTheme() { private fun updateTheme() {
@ -60,9 +60,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
if (PreferenceUtil.isCustomFont) { if (PreferenceUtil.isCustomFont) {
setTheme(R.style.FontThemeOverlay) setTheme(R.style.FontThemeOverlay)
} }
if (PreferenceUtil.circlePlayButton) {
setTheme(R.style.CircleFABOverlay)
}
} }
override fun onWindowFocusChanged(hasFocus: Boolean) { override fun onWindowFocusChanged(hasFocus: Boolean) {
@ -76,20 +73,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
} }
} }
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)
}
override fun run() { override fun run() {
setImmersiveFullscreen() setImmersiveFullscreen()
} }
@ -101,7 +84,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
public override fun onDestroy() { public override fun onDestroy() {
super.onDestroy() super.onDestroy()
unregisterSystemUiVisibility()
exitFullscreen() exitFullscreen()
} }

View file

@ -64,7 +64,6 @@ open class BugReportActivity : AbsThemeActivity() {
private fun reportIssue() { private fun reportIssue() {
copyDeviceInfoToClipBoard() copyDeviceInfoToClipBoard()
val i = Intent(Intent.ACTION_VIEW) val i = Intent(Intent.ACTION_VIEW)
i.data = ISSUE_TRACKER_LINK.toUri() i.data = ISSUE_TRACKER_LINK.toUri()
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
@ -80,17 +79,11 @@ open class BugReportActivity : AbsThemeActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) { if (item.itemId == android.R.id.home) {
onBackPressed() onBackPressedDispatcher.onBackPressed()
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private fun tryToFinishActivity() {
if (!isFinishing) {
finish()
}
}
companion object { companion object {
private const val ISSUE_TRACKER_LINK = private const val ISSUE_TRACKER_LINK =
"https://github.com/MuntashirAkon/Metro/issues/new" "https://github.com/MuntashirAkon/Metro/issues/new"

View file

@ -50,8 +50,8 @@ public class SAFGuideActivity extends IntroActivity {
? R.string.saf_guide_slide1_description_before_o ? R.string.saf_guide_slide1_description_before_o
: R.string.saf_guide_slide1_description) : R.string.saf_guide_slide1_description)
.image(R.drawable.saf_guide_1) .image(R.drawable.saf_guide_1)
.background(R.color.md_deep_purple_300) .background(code.name.monkey.appthemehelper.R.color.md_deep_purple_300)
.backgroundDark(R.color.md_deep_purple_400) .backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_400)
.layout(R.layout.fragment_simple_slide_large_image) .layout(R.layout.fragment_simple_slide_large_image)
.build()); .build());
addSlide( addSlide(
@ -59,8 +59,8 @@ public class SAFGuideActivity extends IntroActivity {
.title(R.string.saf_guide_slide2_title) .title(R.string.saf_guide_slide2_title)
.description(R.string.saf_guide_slide2_description) .description(R.string.saf_guide_slide2_description)
.image(R.drawable.saf_guide_2) .image(R.drawable.saf_guide_2)
.background(R.color.md_deep_purple_500) .background(code.name.monkey.appthemehelper.R.color.md_deep_purple_500)
.backgroundDark(R.color.md_deep_purple_600) .backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_600)
.layout(R.layout.fragment_simple_slide_large_image) .layout(R.layout.fragment_simple_slide_large_image)
.build()); .build());
addSlide( addSlide(
@ -68,8 +68,8 @@ public class SAFGuideActivity extends IntroActivity {
.title(R.string.saf_guide_slide3_title) .title(R.string.saf_guide_slide3_title)
.description(R.string.saf_guide_slide3_description) .description(R.string.saf_guide_slide3_description)
.image(R.drawable.saf_guide_3) .image(R.drawable.saf_guide_3)
.background(R.color.md_deep_purple_700) .background(code.name.monkey.appthemehelper.R.color.md_deep_purple_700)
.backgroundDark(R.color.md_deep_purple_800) .backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_800)
.layout(R.layout.fragment_simple_slide_large_image) .layout(R.layout.fragment_simple_slide_large_image)
.build()); .build());
} }

View file

@ -33,11 +33,10 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity
import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.hideSoftKeyboard import code.name.monkey.retromusic.extensions.hideSoftKeyboard
@ -46,6 +45,7 @@ import code.name.monkey.retromusic.model.ArtworkInfo
import code.name.monkey.retromusic.model.AudioTagInfo import code.name.monkey.retromusic.model.AudioTagInfo
import code.name.monkey.retromusic.repository.Repository import code.name.monkey.retromusic.repository.Repository
import code.name.monkey.retromusic.util.SAFUtil import code.name.monkey.retromusic.util.SAFUtil
import code.name.monkey.retromusic.util.logD
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
@ -55,7 +55,7 @@ import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.tag.FieldKey import org.jaudiotagger.tag.FieldKey
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import java.io.File import java.io.File
import java.util.* import java.util.Collections
abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() { abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
abstract val editorImage: ImageView abstract val editorImage: ImageView
@ -221,7 +221,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
getIntentExtras() getIntentExtras()
songPaths = getSongPaths() songPaths = getSongPaths()
println(songPaths?.size) logD(songPaths?.size)
if (songPaths!!.isEmpty()) { if (songPaths!!.isEmpty()) {
finish() finish()
} }
@ -274,7 +274,6 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
scaleY = 0f scaleY = 0f
isEnabled = false isEnabled = false
setOnClickListener { save() } setOnClickListener { save() }
TintHelper.setTintAuto(this, ThemeStore.accentColor(this@AbsTagEditorActivity), true)
} }
} }
@ -307,7 +306,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
android.R.id.home -> { android.R.id.home -> {
super.onBackPressed() onBackPressedDispatcher.onBackPressed()
return true return true
} }
} }
@ -350,7 +349,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
hideSoftKeyboard() hideSoftKeyboard()
hideFab() hideFab()
println(fieldKeyValueMap) logD(fieldKeyValueMap)
GlobalScope.launch { GlobalScope.launch {
if (VersionUtils.hasR()) { if (VersionUtils.hasR()) {
cacheFiles = TagWriter.writeTagsToFilesR( cacheFiles = TagWriter.writeTagsToFilesR(
@ -409,15 +408,18 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
loadImageFromFile(it) loadImageFromFile(it)
} }
} }
code.name.monkey.retromusic.activities.saf.SAFGuideActivity.REQUEST_CODE_SAF_GUIDE -> {
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE -> {
SAFUtil.openTreePicker(this) SAFUtil.openTreePicker(this)
} }
SAFUtil.REQUEST_SAF_PICK_TREE -> { SAFUtil.REQUEST_SAF_PICK_TREE -> {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
SAFUtil.saveTreeUri(this, intent) SAFUtil.saveTreeUri(this, intent)
writeTags(savedSongPaths) writeTags(savedSongPaths)
} }
} }
SAFUtil.REQUEST_SAF_PICK_FILE -> { SAFUtil.REQUEST_SAF_PICK_FILE -> {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
writeTags(Collections.singletonList(currentSongPath + SAFUtil.SEPARATOR + intent!!.dataString)) writeTags(Collections.singletonList(currentSongPath + SAFUtil.SEPARATOR + intent!!.dataString))

View file

@ -30,8 +30,12 @@ import androidx.core.widget.doAfterTextChanged
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding
import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.extensions.defaultFooterColor
import code.name.monkey.retromusic.extensions.isColorLight
import code.name.monkey.retromusic.extensions.setTint
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.ArtworkInfo import code.name.monkey.retromusic.model.ArtworkInfo
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
@ -39,12 +43,14 @@ import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
import code.name.monkey.retromusic.util.RetroColorUtil.getColor 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.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.target.ImageViewTarget import com.bumptech.glide.request.target.ImageViewTarget
import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.request.transition.Transition
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import org.jaudiotagger.tag.FieldKey import org.jaudiotagger.tag.FieldKey
import java.util.* import java.util.EnumMap
class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBinding>() { class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBinding>() {
@ -98,7 +104,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
binding.albumArtistText.setText(albumArtistName) binding.albumArtistText.setText(albumArtistName)
binding.genreTitle.setText(genreName) binding.genreTitle.setText(genreName)
binding.yearTitle.setText(songYear) binding.yearTitle.setText(songYear)
println(albumTitle + albumArtistName) logD(albumTitle + albumArtistName)
} }
override fun loadCurrentImage() { override fun loadCurrentImage() {
@ -131,7 +137,9 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
} }
override fun loadImageFromFile(selectedFile: Uri?) { override fun loadImageFromFile(selectedFile: Uri?) {
GlideApp.with(this@AlbumTagEditorActivity).asBitmapPalette().load(selectedFile) Glide.with(this@AlbumTagEditorActivity)
.asBitmapPalette()
.load(selectedFile)
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
.into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) { .into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) {
override fun onResourceReady( override fun onResourceReady(

View file

@ -31,13 +31,15 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.ActivitySongTagEditorBinding import code.name.monkey.retromusic.databinding.ActivitySongTagEditorBinding
import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.ArtworkInfo import code.name.monkey.retromusic.model.ArtworkInfo
import code.name.monkey.retromusic.repository.SongRepository import code.name.monkey.retromusic.repository.SongRepository
import code.name.monkey.retromusic.util.ImageUtil import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.RetroColorUtil 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.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.target.ImageViewTarget import com.bumptech.glide.request.target.ImageViewTarget
import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.request.transition.Transition
@ -102,7 +104,7 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
binding.discNumberText.setText(discNumber) binding.discNumberText.setText(discNumber)
binding.lyricsText.setText(lyrics) binding.lyricsText.setText(lyrics)
binding.songComposerText.setText(composer) binding.songComposerText.setText(composer)
println(songTitle + songYear) logD(songTitle + songYear)
} }
override fun loadCurrentImage() { override fun loadCurrentImage() {
@ -170,8 +172,11 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
override fun getSongUris(): List<Uri> = listOf(MusicUtil.getSongFileUri(id)) override fun getSongUris(): List<Uri> = listOf(MusicUtil.getSongFileUri(id))
override fun loadImageFromFile(selectedFile: Uri?) { override fun loadImageFromFile(selectedFile: Uri?) {
GlideApp.with(this@SongTagEditorActivity).asBitmapPalette().load(selectedFile) Glide.with(this@SongTagEditorActivity)
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true) .asBitmapPalette()
.load(selectedFile)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) { .into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) {
override fun onResourceReady( override fun onResourceReady(
resource: BitmapPaletteWrapper, resource: BitmapPaletteWrapper,

View file

@ -23,13 +23,15 @@ import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.ItemGenreBinding import code.name.monkey.retromusic.databinding.ItemGenreBinding
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.RetroMusicColoredTarget
import code.name.monkey.retromusic.interfaces.IGenreClickListener import code.name.monkey.retromusic.interfaces.IGenreClickListener
import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import java.util.* import java.util.*
/** /**
@ -68,10 +70,10 @@ class GenreAdapter(
private fun loadGenreImage(genre: Genre, holder: GenreAdapter.ViewHolder) { private fun loadGenreImage(genre: Genre, holder: GenreAdapter.ViewHolder) {
val genreSong = MusicUtil.songByGenre(genre.id) val genreSong = MusicUtil.songByGenre(genre.id)
GlideApp.with(activity) Glide.with(activity)
.asBitmapPalette() .asBitmapPalette()
.load(RetroGlideExtension.getSongModel(genreSong))
.songCoverOptions(genreSong) .songCoverOptions(genreSong)
.load(RetroGlideExtension.getSongModel(genreSong))
.into(object : RetroMusicColoredTarget(holder.binding.image) { .into(object : RetroMusicColoredTarget(holder.binding.image) {
override fun onColorReady(colors: MediaNotificationProcessor) { override fun onColorReady(colors: MediaNotificationProcessor) {
setColors(holder, colors) setColors(holder, colors)

View file

@ -18,7 +18,6 @@ import android.annotation.SuppressLint
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.AppCompatTextView
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
@ -35,14 +34,14 @@ import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.fragments.home.HomeFragment import code.name.monkey.retromusic.fragments.home.HomeFragment
import code.name.monkey.retromusic.interfaces.IAlbumClickListener import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.IArtistClickListener import code.name.monkey.retromusic.interfaces.IArtistClickListener
import code.name.monkey.retromusic.interfaces.IGenreClickListener import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Home
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
class HomeAdapter( class HomeAdapter(private val activity: AppCompatActivity) :
private val activity: AppCompatActivity RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener {
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener,
IGenreClickListener {
private var list = listOf<Home>() private var list = listOf<Home>()
@ -134,6 +133,7 @@ class HomeAdapter(
notifyDataSetChanged() notifyDataSetChanged()
} }
@Suppress("UNCHECKED_CAST")
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) { private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
fun bindView(home: Home) { fun bindView(home: Home) {
title.setText(home.titleRes) title.setText(home.titleRes)
@ -144,6 +144,7 @@ class HomeAdapter(
} }
} }
@Suppress("UNCHECKED_CAST")
private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) { private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
fun bindView(home: Home) { fun bindView(home: Home) {
title.setText(home.titleRes) title.setText(home.titleRes)
@ -154,6 +155,7 @@ class HomeAdapter(
} }
} }
@Suppress("UNCHECKED_CAST")
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) { private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
fun bindView(home: Home) { fun bindView(home: Home) {
title.setText(home.titleRes) title.setText(home.titleRes)
@ -161,7 +163,7 @@ class HomeAdapter(
val songAdapter = SongAdapter( val songAdapter = SongAdapter(
activity, activity,
home.arrayList as MutableList<Song>, home.arrayList as MutableList<Song>,
R.layout.item_favourite_card, null R.layout.item_favourite_card
) )
layoutManager = linearLayoutManager() layoutManager = linearLayoutManager()
adapter = songAdapter adapter = songAdapter
@ -172,15 +174,14 @@ class HomeAdapter(
open class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) { open class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView) val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView)
val title: AppCompatTextView = itemView.findViewById(R.id.title) val title: AppCompatTextView = itemView.findViewById(R.id.title)
val arrow: ImageView = itemView.findViewById(R.id.arrow)
val clickableArea: ViewGroup = itemView.findViewById(R.id.clickable_area) val clickableArea: ViewGroup = itemView.findViewById(R.id.clickable_area)
} }
private fun artistsAdapter(artists: List<Artist>) = private fun artistsAdapter(artists: List<Artist>) =
ArtistAdapter(activity, artists, PreferenceUtil.homeArtistGridStyle, null, this) ArtistAdapter(activity, artists, PreferenceUtil.homeArtistGridStyle, this)
private fun albumAdapter(albums: List<Album>) = private fun albumAdapter(albums: List<Album>) =
AlbumAdapter(activity, albums, PreferenceUtil.homeAlbumGridStyle, null, this) AlbumAdapter(activity, albums, PreferenceUtil.homeAlbumGridStyle, this)
private fun gridLayoutManager() = private fun gridLayoutManager() =
GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false) GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
@ -209,16 +210,4 @@ class HomeAdapter(
) )
) )
} }
}
override fun onClickGenre(genre: Genre, view: View) {
activity.findNavController(R.id.fragment_container).navigate(
R.id.genreDetailsFragment,
bundleOf(EXTRA_GENRE to genre),
null,
FragmentNavigatorExtras(
view to "genre"
)
)
}
}

View file

@ -27,9 +27,12 @@ import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.* import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.MusicPlayerRemote
import code.name.monkey.retromusic.helper.menu.SongMenuHelper import code.name.monkey.retromusic.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
@ -37,6 +40,7 @@ import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import com.bumptech.glide.Glide
import java.util.* import java.util.*
class SearchAdapter( class SearchAdapter(
@ -59,26 +63,28 @@ class SearchAdapter(
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return if (viewType == HEADER) ViewHolder( return when (viewType) {
LayoutInflater.from(activity).inflate( HEADER -> ViewHolder(
R.layout.sub_header, LayoutInflater.from(activity).inflate(
parent, R.layout.sub_header,
false parent,
), viewType false
) ), viewType
else if (viewType == ALBUM || viewType == ARTIST || viewType== ALBUM_ARTIST) )
ViewHolder(
ALBUM, ARTIST, ALBUM_ARTIST -> ViewHolder(
LayoutInflater.from(activity).inflate( LayoutInflater.from(activity).inflate(
R.layout.item_list_big, R.layout.item_list_big,
parent, parent,
false false
), viewType ), viewType
) )
else
ViewHolder( else -> ViewHolder(
LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false), LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false),
viewType viewType
) )
}
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@ -88,25 +94,30 @@ class SearchAdapter(
val album = dataSet[position] as Album val album = dataSet[position] as Album
holder.title?.text = album.title holder.title?.text = album.title
holder.text?.text = album.artistName holder.text?.text = album.artistName
GlideApp.with(activity).asDrawable().albumCoverOptions(album.safeGetFirstSong()).load( Glide.with(activity).asDrawable().albumCoverOptions(album.safeGetFirstSong())
RetroGlideExtension.getSongModel(album.safeGetFirstSong())) .load(RetroGlideExtension.getSongModel(album.safeGetFirstSong()))
.into(holder.image!!) .into(holder.image!!)
} }
ARTIST -> { ARTIST -> {
holder.imageTextContainer?.isVisible = true holder.imageTextContainer?.isVisible = true
val artist = dataSet[position] as Artist val artist = dataSet[position] as Artist
holder.title?.text = artist.name holder.title?.text = artist.name
holder.text?.text = MusicUtil.getArtistInfoString(activity, artist) holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
GlideApp.with(activity).asDrawable().artistImageOptions(artist).load( Glide.with(activity).asDrawable().artistImageOptions(artist).load(
RetroGlideExtension.getArtistModel(artist)).into(holder.image!!) RetroGlideExtension.getArtistModel(artist)
).into(holder.image!!)
} }
SONG -> { SONG -> {
holder.imageTextContainer?.isVisible = true holder.imageTextContainer?.isVisible = true
val song = dataSet[position] as Song val song = dataSet[position] as Song
holder.title?.text = song.title holder.title?.text = song.title
holder.text?.text = song.albumName holder.text?.text = song.albumName
GlideApp.with(activity).asDrawable().songCoverOptions(song).load(RetroGlideExtension.getSongModel(song)).into(holder.image!!) Glide.with(activity).asDrawable().songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song)).into(holder.image!!)
} }
GENRE -> { GENRE -> {
val genre = dataSet[position] as Genre val genre = dataSet[position] as Genre
holder.title?.text = genre.name holder.title?.text = genre.name
@ -119,19 +130,23 @@ class SearchAdapter(
) )
) )
} }
PLAYLIST -> { PLAYLIST -> {
val playlist = dataSet[position] as PlaylistWithSongs val playlist = dataSet[position] as PlaylistWithSongs
holder.title?.text = playlist.playlistEntity.playlistName holder.title?.text = playlist.playlistEntity.playlistName
//holder.text?.text = MusicUtil.playlistInfoString(activity, playlist.songs) //holder.text?.text = MusicUtil.playlistInfoString(activity, playlist.songs)
} }
ALBUM_ARTIST -> { ALBUM_ARTIST -> {
holder.imageTextContainer?.isVisible = true holder.imageTextContainer?.isVisible = true
val artist = dataSet[position] as Artist val artist = dataSet[position] as Artist
holder.title?.text = artist.name holder.title?.text = artist.name
holder.text?.text = MusicUtil.getArtistInfoString(activity, artist) holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
GlideApp.with(activity).asDrawable().artistImageOptions(artist).load( Glide.with(activity).asDrawable().artistImageOptions(artist).load(
RetroGlideExtension.getArtistModel(artist)).into(holder.image!!) RetroGlideExtension.getArtistModel(artist)
).into(holder.image!!)
} }
else -> { else -> {
holder.title?.text = dataSet[position].toString() holder.title?.text = dataSet[position].toString()
holder.title?.setTextColor(ThemeStore.accentColor(activity)) holder.title?.setTextColor(ThemeStore.accentColor(activity))
@ -143,7 +158,7 @@ class SearchAdapter(
return dataSet.size return dataSet.size
} }
inner class ViewHolder(itemView: View, itemViewType: Int) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View, itemViewType: Int) : MediaEntryViewHolder(itemView) {
init { init {
itemView.setOnLongClickListener(null) itemView.setOnLongClickListener(null)
imageTextContainer?.isInvisible = true imageTextContainer?.isInvisible = true
@ -177,30 +192,35 @@ class SearchAdapter(
bundleOf(EXTRA_ALBUM_ID to (item as Album).id) bundleOf(EXTRA_ALBUM_ID to (item as Album).id)
) )
} }
ARTIST -> { ARTIST -> {
activity.findNavController(R.id.fragment_container).navigate( activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment, R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to (item as Artist).id) bundleOf(EXTRA_ARTIST_ID to (item as Artist).id)
) )
} }
ALBUM_ARTIST ->{
ALBUM_ARTIST -> {
activity.findNavController(R.id.fragment_container).navigate( activity.findNavController(R.id.fragment_container).navigate(
R.id.albumArtistDetailsFragment, R.id.albumArtistDetailsFragment,
bundleOf(EXTRA_ARTIST_NAME to (item as Artist).name) bundleOf(EXTRA_ARTIST_NAME to (item as Artist).name)
) )
} }
GENRE -> { GENRE -> {
activity.findNavController(R.id.fragment_container).navigate( activity.findNavController(R.id.fragment_container).navigate(
R.id.genreDetailsFragment, R.id.genreDetailsFragment,
bundleOf(EXTRA_GENRE to (item as Genre)) bundleOf(EXTRA_GENRE to (item as Genre))
) )
} }
PLAYLIST -> { PLAYLIST -> {
activity.findNavController(R.id.fragment_container).navigate( activity.findNavController(R.id.fragment_container).navigate(
R.id.playlistDetailsFragment, R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to (item as PlaylistWithSongs)) bundleOf(EXTRA_PLAYLIST_ID to (item as PlaylistWithSongs).playlistEntity.playListId)
) )
} }
SONG -> { SONG -> {
MusicPlayerRemote.playNext(item as Song) MusicPlayerRemote.playNext(item as Song)
MusicPlayerRemote.playNextSong() MusicPlayerRemote.playNextSong()

View file

@ -25,12 +25,11 @@ import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.extensions.getTintedDrawable import code.name.monkey.retromusic.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.audiocover.AudioFileCover import code.name.monkey.retromusic.glide.audiocover.AudioFileCover
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.interfaces.ICallbacks import code.name.monkey.retromusic.interfaces.ICallbacks
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.MediaStoreSignature import com.bumptech.glide.signature.MediaStoreSignature
import me.zhanghai.android.fastscroll.PopupTextProvider import me.zhanghai.android.fastscroll.PopupTextProvider
@ -43,10 +42,9 @@ class SongFileAdapter(
override val activity: AppCompatActivity, override val activity: AppCompatActivity,
private var dataSet: List<File>, private var dataSet: List<File>,
private val itemLayoutRes: Int, private val itemLayoutRes: Int,
private val iCallbacks: ICallbacks?, private val iCallbacks: ICallbacks?
iCabHolder: ICabHolder?,
) : AbsMultiSelectAdapter<SongFileAdapter.ViewHolder, File>( ) : AbsMultiSelectAdapter<SongFileAdapter.ViewHolder, File>(
activity, iCabHolder, R.menu.menu_media_selection activity, R.menu.menu_media_selection
), PopupTextProvider { ), PopupTextProvider {
init { init {
@ -96,7 +94,7 @@ class SongFileAdapter(
} }
private fun loadFileImage(file: File, holder: ViewHolder) { 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) { if (file.isDirectory) {
holder.image?.let { holder.image?.let {
it.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN) it.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN)
@ -105,12 +103,12 @@ class SongFileAdapter(
holder.imageTextContainer?.setCardBackgroundColor( holder.imageTextContainer?.setCardBackgroundColor(
ATHUtil.resolveColor( ATHUtil.resolveColor(
activity, activity,
R.attr.colorSurface com.google.android.material.R.attr.colorSurface
) )
) )
} else { } else {
val error = activity.getTintedDrawable(R.drawable.ic_file_music, iconColor) val error = activity.getTintedDrawable(R.drawable.ic_audio_file, iconColor)
GlideApp.with(activity) Glide.with(activity)
.load(AudioFileCover(file.path)) .load(AudioFileCover(file.path))
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)
.error(error) .error(error)

View file

@ -23,29 +23,29 @@ import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.RetroGlideExtension import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.albumCoverOptions
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.SortOrder import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.IAlbumClickListener import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import me.zhanghai.android.fastscroll.PopupTextProvider import me.zhanghai.android.fastscroll.PopupTextProvider
open class AlbumAdapter( open class AlbumAdapter(
override val activity: FragmentActivity, override val activity: FragmentActivity,
var dataSet: List<Album>, var dataSet: List<Album>,
var itemLayoutRes: Int, var itemLayoutRes: Int,
iCabHolder: ICabHolder?,
val listener: IAlbumClickListener? val listener: IAlbumClickListener?
) : AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album>( ) : AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album>(
activity, activity,
iCabHolder,
R.menu.menu_media_selection R.menu.menu_media_selection
), PopupTextProvider { ), PopupTextProvider {
@ -112,7 +112,9 @@ open class AlbumAdapter(
return return
} }
val song = album.safeGetFirstSong() val song = album.safeGetFirstSong()
GlideApp.with(activity).asBitmapPalette().albumCoverOptions(song) Glide.with(activity)
.asBitmapPalette()
.albumCoverOptions(song)
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.into(object : RetroMusicColoredTarget(holder.image!!) { .into(object : RetroMusicColoredTarget(holder.image!!) {
@ -162,6 +164,7 @@ open class AlbumAdapter(
when (PreferenceUtil.albumSortOrder) { when (PreferenceUtil.albumSortOrder) {
SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName = SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName =
dataSet[position].title dataSet[position].title
SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].albumArtist SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].albumArtist
SortOrder.AlbumSortOrder.ALBUM_YEAR -> return MusicUtil.getYearString( SortOrder.AlbumSortOrder.ALBUM_YEAR -> return MusicUtil.getYearString(
dataSet[position].year dataSet[position].year
@ -170,7 +173,7 @@ open class AlbumAdapter(
return MusicUtil.getSectionName(sectionName) return MusicUtil.getSectionName(sectionName)
} }
inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init { init {
menu?.isVisible = false menu?.isVisible = false

View file

@ -19,6 +19,7 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import androidx.core.os.BundleCompat
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
@ -26,16 +27,24 @@ import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.fragments.AlbumCoverStyle import code.name.monkey.retromusic.fragments.AlbumCoverStyle
import code.name.monkey.retromusic.fragments.NowPlayingScreen.* import code.name.monkey.retromusic.fragments.NowPlayingScreen.Card
import code.name.monkey.retromusic.fragments.NowPlayingScreen.Classic
import code.name.monkey.retromusic.fragments.NowPlayingScreen.Fit
import code.name.monkey.retromusic.fragments.NowPlayingScreen.Full
import code.name.monkey.retromusic.fragments.NowPlayingScreen.Gradient
import code.name.monkey.retromusic.fragments.NowPlayingScreen.Peek
import code.name.monkey.retromusic.fragments.NowPlayingScreen.Tiny
import code.name.monkey.retromusic.fragments.base.goToLyrics import code.name.monkey.retromusic.fragments.base.goToLyrics
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.RetroMusicColoredTarget
import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -95,7 +104,7 @@ class AlbumCoverPagerAdapter(
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (arguments != null) { if (arguments != null) {
song = requireArguments().getParcelable(SONG_ARG)!! song = BundleCompat.getParcelable(requireArguments(), SONG_ARG, Song::class.java)!!
} }
} }
@ -119,7 +128,7 @@ class AlbumCoverPagerAdapter(
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
MaterialAlertDialogBuilder( MaterialAlertDialogBuilder(
requireContext(), requireContext(),
R.style.ThemeOverlay_MaterialComponents_Dialog_Alert com.google.android.material.R.style.ThemeOverlay_MaterialComponents_Dialog_Alert
).apply { ).apply {
setTitle(song.title) setTitle(song.title)
setMessage(if (data.isNullOrEmpty()) "No lyrics found" else data) setMessage(if (data.isNullOrEmpty()) "No lyrics found" else data)
@ -164,7 +173,9 @@ class AlbumCoverPagerAdapter(
} }
private fun loadAlbumCover(albumCover: ImageView) { private fun loadAlbumCover(albumCover: ImageView) {
GlideApp.with(this).asBitmapPalette().songCoverOptions(song) Glide.with(this)
.asBitmapPalette()
.songCoverOptions(song)
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.dontAnimate() .dontAnimate()

View file

@ -17,23 +17,23 @@ package code.name.monkey.retromusic.adapter.album
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.albumCoverOptions
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.HorizontalAdapterHelper import code.name.monkey.retromusic.helper.HorizontalAdapterHelper
import code.name.monkey.retromusic.interfaces.IAlbumClickListener import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
class HorizontalAlbumAdapter( class HorizontalAlbumAdapter(
activity: FragmentActivity, activity: FragmentActivity,
dataSet: List<Album>, dataSet: List<Album>,
ICabHolder: ICabHolder?,
albumClickListener: IAlbumClickListener albumClickListener: IAlbumClickListener
) : AlbumAdapter( ) : AlbumAdapter(
activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, ICabHolder, albumClickListener activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, albumClickListener
) { ) {
override fun createViewHolder(view: View, viewType: Int): ViewHolder { override fun createViewHolder(view: View, viewType: Int): ViewHolder {
@ -49,7 +49,9 @@ class HorizontalAlbumAdapter(
override fun loadAlbumCover(album: Album, holder: ViewHolder) { override fun loadAlbumCover(album: Album, holder: ViewHolder) {
if (holder.image == null) return if (holder.image == null) return
GlideApp.with(activity).asBitmapPalette().albumCoverOptions(album.safeGetFirstSong()) Glide.with(activity)
.asBitmapPalette()
.albumCoverOptions(album.safeGetFirstSong())
.load(RetroGlideExtension.getSongModel(album.safeGetFirstSong())) .load(RetroGlideExtension.getSongModel(album.safeGetFirstSong()))
.into(object : RetroMusicColoredTarget(holder.image!!) { .into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onColorReady(colors: MediaNotificationProcessor) { override fun onColorReady(colors: MediaNotificationProcessor) {

View file

@ -26,30 +26,29 @@ import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.IAlbumArtistClickListener import code.name.monkey.retromusic.interfaces.IAlbumArtistClickListener
import code.name.monkey.retromusic.interfaces.IArtistClickListener import code.name.monkey.retromusic.interfaces.IArtistClickListener
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import me.zhanghai.android.fastscroll.PopupTextProvider import me.zhanghai.android.fastscroll.PopupTextProvider
class ArtistAdapter( class ArtistAdapter(
override val activity: FragmentActivity, override val activity: FragmentActivity,
var dataSet: List<Artist>, var dataSet: List<Artist>,
var itemLayoutRes: Int, var itemLayoutRes: Int,
val ICabHolder: ICabHolder?,
val IArtistClickListener: IArtistClickListener, val IArtistClickListener: IArtistClickListener,
val IAlbumArtistClickListener: IAlbumArtistClickListener? = null val IAlbumArtistClickListener: IAlbumArtistClickListener? = null
) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>( ) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>(activity, R.menu.menu_media_selection),
activity, ICabHolder, R.menu.menu_media_selection PopupTextProvider {
), PopupTextProvider {
var albumArtistsOnly = false var albumArtistsOnly = false
@ -111,10 +110,10 @@ class ArtistAdapter(
if (holder.image == null) { if (holder.image == null) {
return return
} }
GlideApp.with(activity) Glide.with(activity)
.asBitmapPalette() .asBitmapPalette()
.load(RetroGlideExtension.getArtistModel(artist))
.artistImageOptions(artist) .artistImageOptions(artist)
.load(RetroGlideExtension.getArtistModel(artist))
.transition(RetroGlideExtension.getDefaultTransition()) .transition(RetroGlideExtension.getDefaultTransition())
.into(object : RetroMusicColoredTarget(holder.image!!) { .into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onColorReady(colors: MediaNotificationProcessor) { override fun onColorReady(colors: MediaNotificationProcessor) {

View file

@ -1,56 +1,58 @@
package code.name.monkey.retromusic.adapter.base package code.name.monkey.retromusic.adapter.base
import android.annotation.SuppressLint
import android.graphics.Color import android.graphics.Color
import android.view.ActionMode
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.activity.OnBackPressedCallback
import androidx.annotation.MenuRes import androidx.annotation.MenuRes
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.surfaceColor import code.name.monkey.retromusic.databinding.NumberRollViewBinding
import code.name.monkey.retromusic.interfaces.ICabCallback import code.name.monkey.retromusic.views.NumberRollView
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.util.RetroColorUtil
import com.afollestad.materialcab.attached.AttachedCab
import com.afollestad.materialcab.attached.destroy
import com.afollestad.materialcab.attached.isActive
abstract class AbsMultiSelectAdapter<V : RecyclerView.ViewHolder?, I>( abstract class AbsMultiSelectAdapter<V : RecyclerView.ViewHolder?, I>(
open val activity: FragmentActivity, private val ICabHolder: ICabHolder?, @MenuRes menuRes: Int open val activity: FragmentActivity, @MenuRes menuRes: Int,
) : RecyclerView.Adapter<V>(), ICabCallback { ) : RecyclerView.Adapter<V>(), ActionMode.Callback {
private var cab: AttachedCab? = null var actionMode: ActionMode? = null
private val checked: MutableList<I> private val checked: MutableList<I>
private var menuRes: Int private var menuRes: Int
override fun onCabCreated(cab: AttachedCab, menu: Menu): Boolean {
activity.window.statusBarColor = override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
RetroColorUtil.shiftBackgroundColor(activity.surfaceColor()) val inflater = mode?.menuInflater
inflater?.inflate(menuRes, menu)
return true return true
} }
override fun onCabFinished(cab: AttachedCab): Boolean { override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
clearChecked() return false
activity.window.statusBarColor = when {
VersionUtils.hasMarshmallow() -> Color.TRANSPARENT
else -> Color.BLACK
}
return true
} }
override fun onCabItemClicked(item: MenuItem): Boolean { override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
if (item.itemId == R.id.action_multi_select_adapter_check_all) { if (item?.itemId == R.id.action_multi_select_adapter_check_all) {
checkAll() checkAll()
} else { } else {
onMultipleItemAction(item, ArrayList(checked)) onMultipleItemAction(item!!, ArrayList(checked))
cab?.destroy() actionMode?.finish()
clearChecked() clearChecked()
} }
return true 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() { private fun checkAll() {
if (ICabHolder != null) { if (actionMode != null) {
checked.clear() checked.clear()
for (i in 0 until itemCount) { for (i in 0 until itemCount) {
val identifier = getIdentifier(i) val identifier = getIdentifier(i)
@ -72,7 +74,7 @@ abstract class AbsMultiSelectAdapter<V : RecyclerView.ViewHolder?, I>(
} }
protected val isInQuickSelectMode: Boolean protected val isInQuickSelectMode: Boolean
get() = cab != null && cab!!.isActive() get() = actionMode != null
protected abstract fun onMultipleItemAction(menuItem: MenuItem, selection: List<I>) protected abstract fun onMultipleItemAction(menuItem: MenuItem, selection: List<I>)
protected fun setMultiSelectMenuRes(@MenuRes menuRes: Int) { protected fun setMultiSelectMenuRes(@MenuRes menuRes: Int) {
@ -80,16 +82,13 @@ abstract class AbsMultiSelectAdapter<V : RecyclerView.ViewHolder?, I>(
} }
protected fun toggleChecked(position: Int): Boolean { protected fun toggleChecked(position: Int): Boolean {
if (ICabHolder != null) { val identifier = getIdentifier(position) ?: return false
val identifier = getIdentifier(position) ?: return false if (!checked.remove(identifier)) {
if (!checked.remove(identifier)) { checked.add(identifier)
checked.add(identifier)
}
notifyItemChanged(position)
updateCab()
return true
} }
return false notifyItemChanged(position)
updateCab()
return true
} }
private fun clearChecked() { private fun clearChecked() {
@ -97,23 +96,21 @@ abstract class AbsMultiSelectAdapter<V : RecyclerView.ViewHolder?, I>(
notifyDataSetChanged() notifyDataSetChanged()
} }
@SuppressLint("StringFormatInvalid", "StringFormatMatches")
private fun updateCab() { private fun updateCab() {
if (ICabHolder != null) { if (actionMode == null) {
if (cab == null || !cab!!.isActive()) { actionMode = activity.startActionMode(this)?.apply {
cab = ICabHolder.openCab(menuRes, this) customView = NumberRollViewBinding.inflate(activity.layoutInflater).root
} }
val size = checked.size activity.onBackPressedDispatcher.addCallback(onBackPressedCallback)
when { }
size <= 0 -> { val size = checked.size
cab?.destroy() when {
} size <= 0 -> {
size == 1 -> { actionMode?.finish()
cab?.title(literal = getName(checked[0])) }
} else -> {
else -> { actionMode?.customView?.findViewById<NumberRollView>(R.id.selection_mode_number)
cab?.title(literal = activity.getString(R.string.x_selected, size)) ?.setNumber(size, true)
}
} }
} }
} }
@ -122,4 +119,13 @@ abstract class AbsMultiSelectAdapter<V : RecyclerView.ViewHolder?, I>(
checked = ArrayList() checked = ArrayList()
this.menuRes = menuRes this.menuRes = menuRes
} }
private val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (actionMode != null) {
actionMode?.finish()
remove()
}
}
}
} }

View file

@ -15,6 +15,7 @@
package code.name.monkey.retromusic.adapter.playlist package code.name.monkey.retromusic.adapter.playlist
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.Drawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
@ -23,33 +24,33 @@ import androidx.appcompat.widget.PopupMenu
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.setPadding import androidx.core.view.setPadding
import androidx.fragment.app.FragmentActivity 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.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.toSongs import code.name.monkey.retromusic.db.toSongs
import code.name.monkey.retromusic.extensions.dipToPix import code.name.monkey.retromusic.extensions.dipToPix
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.RetroGlideExtension.playlistOptions
import code.name.monkey.retromusic.glide.playlistPreview.PlaylistPreview import code.name.monkey.retromusic.glide.playlistPreview.PlaylistPreview
import code.name.monkey.retromusic.helper.SortOrder.PlaylistSortOrder import code.name.monkey.retromusic.helper.SortOrder.PlaylistSortOrder
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.interfaces.IPlaylistClickListener import code.name.monkey.retromusic.interfaces.IPlaylistClickListener
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Glide
import me.zhanghai.android.fastscroll.PopupTextProvider import me.zhanghai.android.fastscroll.PopupTextProvider
class PlaylistAdapter( class PlaylistAdapter(
override val activity: FragmentActivity, override val activity: FragmentActivity,
var dataSet: List<PlaylistWithSongs>, var dataSet: List<PlaylistWithSongs>,
private var itemLayoutRes: Int, private var itemLayoutRes: Int,
ICabHolder: ICabHolder?,
private val listener: IPlaylistClickListener private val listener: IPlaylistClickListener
) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, PlaylistWithSongs>( ) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, PlaylistWithSongs>(
activity, activity,
ICabHolder,
R.menu.menu_playlists_selection R.menu.menu_playlists_selection
), PopupTextProvider { ), PopupTextProvider {
@ -71,7 +72,7 @@ class PlaylistAdapter(
return createViewHolder(view) return createViewHolder(view)
} }
fun createViewHolder(view: View): ViewHolder { private fun createViewHolder(view: View): ViewHolder {
return ViewHolder(view) return ViewHolder(view)
} }
@ -100,17 +101,23 @@ class PlaylistAdapter(
holder.title?.text = getPlaylistTitle(playlist.playlistEntity) holder.title?.text = getPlaylistTitle(playlist.playlistEntity)
holder.text?.text = getPlaylistText(playlist) holder.text?.text = getPlaylistText(playlist)
holder.menu?.isGone = isChecked(playlist) holder.menu?.isGone = isChecked(playlist)
GlideApp.with(activity) if (itemLayoutRes == R.layout.item_list) {
.load( holder.image?.setPadding(activity.dipToPix(8F).toInt())
if (itemLayoutRes == R.layout.item_list) { holder.image?.setImageDrawable(getIconRes())
holder.image?.setPadding(activity.dipToPix(8F).toInt()) } else {
R.drawable.ic_playlist_play Glide.with(activity)
} else PlaylistPreview(playlist) .load(PlaylistPreview(playlist))
) .playlistOptions()
.playlistOptions() .into(holder.image!!)
.into(holder.image!!) }
} }
private fun getIconRes(): Drawable = TintHelper.createTintedDrawable(
activity,
R.drawable.ic_playlist_play,
ATHUtil.resolveColor(activity, android.R.attr.colorControlNormal)
)
override fun getItemCount(): Int { override fun getItemCount(): Int {
return dataSet.size return dataSet.size
} }

View file

@ -21,15 +21,13 @@ import androidx.annotation.LayoutRes
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
abstract class AbsOffsetSongAdapter( abstract class AbsOffsetSongAdapter(
activity: FragmentActivity, activity: FragmentActivity,
dataSet: MutableList<Song>, dataSet: MutableList<Song>,
@LayoutRes itemLayoutRes: Int, @LayoutRes itemLayoutRes: Int
ICabHolder: ICabHolder? ) : SongAdapter(activity, dataSet, itemLayoutRes) {
) : SongAdapter(activity, dataSet, itemLayoutRes, ICabHolder) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder {
if (viewType == OFFSET_ITEM) { if (viewType == OFFSET_ITEM) {

View file

@ -24,13 +24,8 @@ import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.toSongEntity import code.name.monkey.retromusic.db.toSongEntity
import code.name.monkey.retromusic.db.toSongsEntity import code.name.monkey.retromusic.db.toSongsEntity
import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.accentOutlineColor
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import com.google.android.material.button.MaterialButton
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -38,12 +33,11 @@ import kotlinx.coroutines.launch
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
class OrderablePlaylistSongAdapter( class OrderablePlaylistSongAdapter(
private val playlist: PlaylistEntity, private val playlistId: Long,
activity: FragmentActivity, activity: FragmentActivity,
dataSet: MutableList<Song>, dataSet: MutableList<Song>,
itemLayoutRes: Int, itemLayoutRes: Int,
ICabHolder: ICabHolder?, ) : SongAdapter(activity, dataSet, itemLayoutRes),
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, ICabHolder),
DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> { DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
val libraryViewModel: LibraryViewModel by activity.viewModel() val libraryViewModel: LibraryViewModel by activity.viewModel()
@ -67,45 +61,20 @@ class OrderablePlaylistSongAdapter(
return ViewHolder(view) 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?.let {
it.setOnClickListener {
MusicPlayerRemote.openQueue(dataSet, 0, true)
}
it.accentOutlineColor()
}
viewHolder.shuffleAction?.let {
it.setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
}
it.accentColor()
}
} else {
super.onBindViewHolder(holder, position - 1)
}
}
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) { override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) {
when (menuItem.itemId) { when (menuItem.itemId) {
R.id.action_remove_from_playlist -> RemoveSongFromPlaylistDialog.create( R.id.action_remove_from_playlist -> RemoveSongFromPlaylistDialog.create(
selection.toSongsEntity( selection.toSongsEntity(
playlist playlistId
) )
) )
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
else -> super.onMultipleItemAction(menuItem, selection) else -> super.onMultipleItemAction(menuItem, selection)
} }
} }
inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) { inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) {
val playAction: MaterialButton? = itemView.findViewById(R.id.playAction)
val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction)
override var songMenuRes: Int override var songMenuRes: Int
get() = R.menu.menu_item_playlist_song get() = R.menu.menu_item_playlist_song
@ -116,7 +85,7 @@ class OrderablePlaylistSongAdapter(
override fun onSongMenuItemClick(item: MenuItem): Boolean { override fun onSongMenuItemClick(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.action_remove_from_playlist -> { R.id.action_remove_from_playlist -> {
RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlist.playListId)) RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlistId))
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
return true return true
} }
@ -149,7 +118,7 @@ class OrderablePlaylistSongAdapter(
} }
override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange { override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange {
return ItemDraggableRange(1, itemCount - 1) return ItemDraggableRange(0, itemCount - 1)
} }
override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean { override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean {

View file

@ -19,8 +19,8 @@ import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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
import code.name.monkey.retromusic.helper.MusicPlayerRemote.isPlaying import code.name.monkey.retromusic.helper.MusicPlayerRemote.isPlaying
import code.name.monkey.retromusic.helper.MusicPlayerRemote.playNextSong import code.name.monkey.retromusic.helper.MusicPlayerRemote.playNextSong
@ -28,6 +28,7 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.ViewUtil 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.DraggableItemAdapter
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
@ -42,10 +43,9 @@ class PlayingQueueAdapter(
activity: FragmentActivity, activity: FragmentActivity,
dataSet: MutableList<Song>, dataSet: MutableList<Song>,
private var current: Int, private var current: Int,
itemLayoutRes: Int itemLayoutRes: Int,
) : SongAdapter( ) : SongAdapter(activity, dataSet, itemLayoutRes),
activity, dataSet, itemLayoutRes, null DraggableItemAdapter<PlayingQueueAdapter.ViewHolder>,
), DraggableItemAdapter<PlayingQueueAdapter.ViewHolder>,
SwipeableItemAdapter<PlayingQueueAdapter.ViewHolder>, SwipeableItemAdapter<PlayingQueueAdapter.ViewHolder>,
PopupTextProvider { PopupTextProvider {
@ -77,7 +77,7 @@ class PlayingQueueAdapter(
if (holder.image == null) { if (holder.image == null) {
return return
} }
GlideApp.with(activity) Glide.with(activity)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.songCoverOptions(song) .songCoverOptions(song)
.into(holder.image!!) .into(holder.image!!)
@ -153,6 +153,14 @@ class PlayingQueueAdapter(
dragView?.isVisible = true dragView?.isVisible = true
} }
override fun onClick(v: View?) {
if (isInQuickSelectMode) {
toggleChecked(layoutPosition)
} else {
MusicPlayerRemote.playSongAt(layoutPosition)
}
}
override fun onSongMenuItemClick(item: MenuItem): Boolean { override fun onSongMenuItemClick(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.action_remove_from_playing_queue -> { R.id.action_remove_from_playing_queue -> {
@ -188,7 +196,7 @@ class PlayingQueueAdapter(
return if (result == SwipeableItemConstants.RESULT_CANCELED) { return if (result == SwipeableItemConstants.RESULT_CANCELED) {
SwipeResultActionDefault() SwipeResultActionDefault()
} else { } else {
SwipedResultActionRemoveItem(this, position, activity) SwipedResultActionRemoveItem(this, position)
} }
} }
@ -209,12 +217,9 @@ class PlayingQueueAdapter(
internal class SwipedResultActionRemoveItem( internal class SwipedResultActionRemoveItem(
private val adapter: PlayingQueueAdapter, private val adapter: PlayingQueueAdapter,
private val position: Int, private val position: Int,
private val activity: FragmentActivity
) : SwipeResultActionRemoveItem() { ) : SwipeResultActionRemoveItem() {
private var songToRemove: Song? = null private var songToRemove: Song? = null
private val isPlaying: Boolean = MusicPlayerRemote.isPlaying
private val songProgressMillis = 0
override fun onPerformAction() { override fun onPerformAction() {
// currentlyShownSnackbar = null // currentlyShownSnackbar = null
} }

View file

@ -21,7 +21,6 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.accentOutlineColor import code.name.monkey.retromusic.extensions.accentOutlineColor
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
@ -30,9 +29,8 @@ import com.google.android.material.button.MaterialButton
class ShuffleButtonSongAdapter( class ShuffleButtonSongAdapter(
activity: FragmentActivity, activity: FragmentActivity,
dataSet: MutableList<Song>, dataSet: MutableList<Song>,
itemLayoutRes: Int, itemLayoutRes: Int
ICabHolder: ICabHolder? ) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes) {
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, ICabHolder) {
override fun createViewHolder(view: View): SongAdapter.ViewHolder { override fun createViewHolder(view: View): SongAdapter.ViewHolder {

View file

@ -17,16 +17,14 @@ package code.name.monkey.retromusic.adapter.song
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
class SimpleSongAdapter( class SimpleSongAdapter(
context: FragmentActivity, context: FragmentActivity,
songs: ArrayList<Song>, songs: ArrayList<Song>,
layoutRes: Int, layoutRes: Int
ICabHolder: ICabHolder? ) : SongAdapter(context, songs, layoutRes) {
) : SongAdapter(context, songs, layoutRes, ICabHolder) {
override fun swapDataSet(dataSet: List<Song>) { override fun swapDataSet(dataSet: List<Song>) {
this.dataSet = dataSet.toMutableList() this.dataSet = dataSet.toMutableList()

View file

@ -28,20 +28,21 @@ import androidx.navigation.findNavController
import code.name.monkey.retromusic.EXTRA_ALBUM_ID import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.helper.menu.SongMenuHelper import code.name.monkey.retromusic.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.ICabCallback
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import me.zhanghai.android.fastscroll.PopupTextProvider import me.zhanghai.android.fastscroll.PopupTextProvider
/** /**
@ -52,13 +53,11 @@ open class SongAdapter(
override val activity: FragmentActivity, override val activity: FragmentActivity,
var dataSet: MutableList<Song>, var dataSet: MutableList<Song>,
protected var itemLayoutRes: Int, protected var itemLayoutRes: Int,
ICabHolder: ICabHolder?,
showSectionName: Boolean = true showSectionName: Boolean = true
) : AbsMultiSelectAdapter<SongAdapter.ViewHolder, Song>( ) : AbsMultiSelectAdapter<SongAdapter.ViewHolder, Song>(
activity, activity,
ICabHolder,
R.menu.menu_media_selection R.menu.menu_media_selection
), ICabCallback, PopupTextProvider { ), PopupTextProvider {
private var showSectionName = true private var showSectionName = true
@ -119,7 +118,9 @@ open class SongAdapter(
if (holder.image == null) { if (holder.image == null) {
return return
} }
GlideApp.with(activity).asBitmapPalette().songCoverOptions(song) Glide.with(activity)
.asBitmapPalette()
.songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.into(object : RetroMusicColoredTarget(holder.image!!) { .into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onColorReady(colors: MediaNotificationProcessor) { override fun onColorReady(colors: MediaNotificationProcessor) {
@ -158,6 +159,11 @@ open class SongAdapter(
override fun getPopupText(position: Int): String { override fun getPopupText(position: Int): String {
val sectionName: String? = when (PreferenceUtil.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_A_Z, SortOrder.SongSortOrder.SONG_Z_A -> dataSet[position].title
SortOrder.SongSortOrder.SONG_ALBUM -> dataSet[position].albumName SortOrder.SongSortOrder.SONG_ALBUM -> dataSet[position].albumName
SortOrder.SongSortOrder.SONG_ARTIST -> dataSet[position].artistName SortOrder.SongSortOrder.SONG_ARTIST -> dataSet[position].artistName
@ -171,7 +177,7 @@ open class SongAdapter(
return MusicUtil.getSectionName(sectionName) return MusicUtil.getSectionName(sectionName)
} }
open inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) { open inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
protected open var songMenuRes = SongMenuHelper.MENU_RES protected open var songMenuRes = SongMenuHelper.MENU_RES
protected open val song: Song protected open val song: Song
get() = dataSet[layoutPosition] get() = dataSet[layoutPosition]
@ -215,6 +221,7 @@ open class SongAdapter(
} }
override fun onLongClick(v: View?): Boolean { override fun onLongClick(v: View?): Boolean {
println("Long click")
return toggleChecked(layoutPosition) return toggleChecked(layoutPosition)
} }
} }

View file

@ -29,7 +29,6 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import code.name.monkey.retromusic.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
@ -152,7 +151,7 @@ class AppWidgetBig : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = GlideApp.with(appContext) target = Glide.with(appContext)
.asBitmap() .asBitmap()
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))

View file

@ -29,8 +29,9 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import code.name.monkey.retromusic.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
@ -143,7 +144,9 @@ class AppWidgetCard : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song) target = Glide.with(service)
.asBitmapPalette()
.songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.centerCrop() .centerCrop()
.into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) { .into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) {

View file

@ -28,8 +28,9 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import code.name.monkey.retromusic.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
@ -89,7 +90,7 @@ class AppWidgetCircle : BaseAppWidget() {
).toBitmap() ).toBitmap()
) )
val isFavorite = runBlocking(Dispatchers.IO) { val isFavorite = runBlocking(Dispatchers.IO) {
return@runBlocking MusicUtil.repository.isSongFavorite(song.id) return@runBlocking MusicUtil.isFavorite(song)
} }
val favoriteRes = val favoriteRes =
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
@ -114,7 +115,9 @@ class AppWidgetCircle : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song) target = Glide.with(service)
.asBitmapPalette()
.songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.apply(RequestOptions.circleCropTransform()) .apply(RequestOptions.circleCropTransform())
.into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) { .into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) {

View file

@ -30,8 +30,9 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import code.name.monkey.retromusic.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
@ -119,7 +120,9 @@ class AppWidgetClassic : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song) target = Glide.with(service)
.asBitmapPalette()
.songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.centerCrop() .centerCrop()

View file

@ -29,8 +29,9 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import code.name.monkey.retromusic.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
@ -144,7 +145,9 @@ class AppWidgetMD3 : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song) target = Glide.with(service)
.asBitmapPalette()
.songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.centerCrop() .centerCrop()
.into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) { .into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) {

View file

@ -29,8 +29,9 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import code.name.monkey.retromusic.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
@ -122,7 +123,9 @@ class AppWidgetSmall : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song) target = Glide.with(service)
.asBitmapPalette()
.songCoverOptions(song)
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.centerCrop() .centerCrop()

View file

@ -40,29 +40,29 @@ class AppWidgetText : BaseAppWidget() {
appWidgetView.setImageViewBitmap( appWidgetView.setImageViewBitmap(
R.id.button_next, R.id.button_next,
context.getTintedDrawable(R.drawable.ic_skip_next, ContextCompat.getColor( context.getTintedDrawable(R.drawable.ic_skip_next, ContextCompat.getColor(
context, R.color.md_white_1000 context, code.name.monkey.appthemehelper.R.color.md_white_1000
)).toBitmap() )).toBitmap()
) )
appWidgetView.setImageViewBitmap( appWidgetView.setImageViewBitmap(
R.id.button_prev, R.id.button_prev,
context.getTintedDrawable(R.drawable.ic_skip_previous, ContextCompat.getColor( context.getTintedDrawable(R.drawable.ic_skip_previous, ContextCompat.getColor(
context, R.color.md_white_1000 context, code.name.monkey.appthemehelper.R.color.md_white_1000
) )
).toBitmap() ).toBitmap()
) )
appWidgetView.setImageViewBitmap( appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, R.id.button_toggle_play_pause,
context.getTintedDrawable(R.drawable.ic_play_arrow_white_32dp, ContextCompat.getColor( context.getTintedDrawable(R.drawable.ic_play_arrow_white_32dp, ContextCompat.getColor(
context, R.color.md_white_1000 context, code.name.monkey.appthemehelper.R.color.md_white_1000
) )
).toBitmap() ).toBitmap()
) )
appWidgetView.setTextColor( appWidgetView.setTextColor(
R.id.title, ContextCompat.getColor(context, R.color.md_white_1000) R.id.title, ContextCompat.getColor(context, code.name.monkey.appthemehelper.R.color.md_white_1000)
) )
appWidgetView.setTextColor( appWidgetView.setTextColor(
R.id.text, ContextCompat.getColor(context, R.color.md_white_1000) R.id.text, ContextCompat.getColor(context, code.name.monkey.appthemehelper.R.color.md_white_1000)
) )
linkButtons(context, appWidgetView) linkButtons(context, appWidgetView)
@ -127,7 +127,7 @@ class AppWidgetText : BaseAppWidget() {
appWidgetView.setImageViewBitmap( appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, R.id.button_toggle_play_pause,
service.getTintedDrawable(playPauseRes, ContextCompat.getColor( service.getTintedDrawable(playPauseRes, ContextCompat.getColor(
service, R.color.md_white_1000) service, code.name.monkey.appthemehelper.R.color.md_white_1000)
).toBitmap() ).toBitmap()
) )
appWidgetView.setImageViewBitmap( appWidgetView.setImageViewBitmap(
@ -136,7 +136,7 @@ class AppWidgetText : BaseAppWidget() {
R.drawable.ic_skip_next, R.drawable.ic_skip_next,
ContextCompat.getColor( ContextCompat.getColor(
service, service,
R.color.md_white_1000 code.name.monkey.appthemehelper.R.color.md_white_1000
) )
).toBitmap() ).toBitmap()
) )
@ -145,7 +145,7 @@ class AppWidgetText : BaseAppWidget() {
service.getTintedDrawable( service.getTintedDrawable(
R.drawable.ic_skip_previous, R.drawable.ic_skip_previous,
ContextCompat.getColor( ContextCompat.getColor(
service, R.color.md_white_1000 service, code.name.monkey.appthemehelper.R.color.md_white_1000
) )
).toBitmap() ).toBitmap()
) )

View file

@ -31,7 +31,7 @@ import java.lang.ref.WeakReference
* Created by Beesham Sarendranauth (Beesham) * Created by Beesham Sarendranauth (Beesham)
*/ */
class AutoMusicProvider( class AutoMusicProvider(
val mContext: Context, private val mContext: Context,
private val songsRepository: SongRepository, private val songsRepository: SongRepository,
private val albumsRepository: AlbumRepository, private val albumsRepository: AlbumRepository,
private val artistsRepository: ArtistRepository, private val artistsRepository: ArtistRepository,
@ -138,7 +138,7 @@ class AutoMusicProvider(
topPlayedRepository.notRecentlyPlayedTracks().take(8) topPlayedRepository.notRecentlyPlayedTracks().take(8)
} }
else -> { else -> {
emptyList() emptyList()
} }
} }
songs.forEach { song -> songs.forEach { song ->

View file

@ -41,6 +41,10 @@ interface PlaylistDao {
@Query("SELECT * FROM PlaylistEntity") @Query("SELECT * FROM PlaylistEntity")
suspend fun playlistsWithSongs(): List<PlaylistWithSongs> suspend fun playlistsWithSongs(): List<PlaylistWithSongs>
@Transaction
@Query("SELECT * FROM PlaylistEntity WHERE playlist_id= :playlistId")
fun getPlaylist(playlistId: Long): LiveData<PlaylistWithSongs>
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>) suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>)
@ -59,8 +63,9 @@ interface PlaylistDao {
@Delete @Delete
suspend fun deletePlaylistSongs(songs: List<SongEntity>) suspend fun deletePlaylistSongs(songs: List<SongEntity>)
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") @RewriteQueriesToDropUnusedColumns
fun favoritesSongsLiveData(playlistId: Long): LiveData<List<SongEntity>> @Query("SELECT * FROM SongEntity ,(SELECT playlist_id FROM PlaylistEntity WHERE playlist_name= :playlistName LIMIT 1) AS playlist WHERE playlist_creator_id= playlist.playlist_id")
fun favoritesSongsLiveData(playlistName: String): LiveData<List<SongEntity>>
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
fun favoritesSongs(playlistId: Long): List<SongEntity> fun favoritesSongs(playlistId: Long): List<SongEntity>

View file

@ -18,14 +18,12 @@ import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
@Database( @Database(
entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class, LyricsEntity::class], entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class],
version = 23, version = 24,
exportSchema = false exportSchema = false
) )
abstract class RetroDatabase : RoomDatabase() { abstract class RetroDatabase : RoomDatabase() {
abstract fun playlistDao(): PlaylistDao abstract fun playlistDao(): PlaylistDao
abstract fun blackListStore(): BlackListStoreDao
abstract fun playCountDao(): PlayCountDao abstract fun playCountDao(): PlayCountDao
abstract fun historyDao(): HistoryDao abstract fun historyDao(): HistoryDao
abstract fun lyricsDao(): LyricsDao
} }

View file

@ -0,0 +1,11 @@
package code.name.monkey.retromusic.db
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
val MIGRATION_23_24 = object : Migration(23, 24) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE LyricsEntity")
database.execSQL("DROP TABLE BlackListStoreEntity")
}
}

View file

@ -145,3 +145,9 @@ fun List<Song>.toSongsEntity(playlistEntity: PlaylistEntity): List<SongEntity> {
it.toSongEntity(playlistEntity.playListId) it.toSongEntity(playlistEntity.playListId)
} }
} }
fun List<Song>.toSongsEntity(playlistId: Long): List<SongEntity> {
return map {
it.toSongEntity(playlistId)
}
}

View file

@ -27,10 +27,10 @@ import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.activityViewModel
class AddToPlaylistDialog : DialogFragment() { class AddToPlaylistDialog : DialogFragment() {
private val libraryViewModel by sharedViewModel<LibraryViewModel>() private val libraryViewModel by activityViewModel<LibraryViewModel>()
companion object { companion object {
fun create(playlistEntities: List<PlaylistEntity>, song: Song): AddToPlaylistDialog { fun create(playlistEntities: List<PlaylistEntity>, song: Song): AddToPlaylistDialog {
@ -58,8 +58,8 @@ class AddToPlaylistDialog : DialogFragment() {
playlistNames.add(entity.playlistName) playlistNames.add(entity.playlistName)
} }
return materialDialog(R.string.add_playlist_title) return materialDialog(R.string.add_playlist_title)
.setItems(playlistNames.toTypedArray()) { dialog, which-> .setItems(playlistNames.toTypedArray()) { dialog, which ->
if (which == 0) { if (which == 0) {
showCreateDialog(songs) showCreateDialog(songs)
} else { } else {
libraryViewModel.addToPlaylist(requireContext(), playlistNames[which], songs) libraryViewModel.addToPlaylist(requireContext(), playlistNames[which], songs)

View file

@ -29,12 +29,12 @@ import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.activityViewModel
class CreatePlaylistDialog : DialogFragment() { class CreatePlaylistDialog : DialogFragment() {
private var _binding: DialogPlaylistBinding? = null private var _binding: DialogPlaylistBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private val libraryViewModel by sharedViewModel<LibraryViewModel>() private val libraryViewModel by activityViewModel<LibraryViewModel>()
companion object { companion object {
fun create(song: Song): CreatePlaylistDialog { fun create(song: Song): CreatePlaylistDialog {

View file

@ -27,11 +27,11 @@ import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.ReloadType
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.activityViewModel
class DeletePlaylistDialog : DialogFragment() { class DeletePlaylistDialog : DialogFragment() {
private val libraryViewModel by sharedViewModel<LibraryViewModel>() private val libraryViewModel by activityViewModel<LibraryViewModel>()
companion object { companion object {
@ -55,10 +55,13 @@ class DeletePlaylistDialog : DialogFragment() {
//noinspection ConstantConditions //noinspection ConstantConditions
if (playlists.size > 1) { if (playlists.size > 1) {
title = R.string.delete_playlists_title title = R.string.delete_playlists_title
message = String.format(getString(R.string.delete_x_playlists), playlists.size).parseAsHtml() message =
String.format(getString(R.string.delete_x_playlists), playlists.size).parseAsHtml()
} else { } else {
title = R.string.delete_playlist_title title = R.string.delete_playlist_title
message = String.format(getString(R.string.delete_playlist_x), playlists[0].playlistName).parseAsHtml() message =
String.format(getString(R.string.delete_playlist_x), playlists[0].playlistName)
.parseAsHtml()
} }
return materialDialog(title) return materialDialog(title)

View file

@ -21,10 +21,10 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.activityViewModel
class ImportPlaylistDialog : DialogFragment() { class ImportPlaylistDialog : DialogFragment() {
private val libraryViewModel by sharedViewModel<LibraryViewModel>() private val libraryViewModel by activityViewModel<LibraryViewModel>()
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return materialDialog(R.string.import_playlist) return materialDialog(R.string.import_playlist)

View file

@ -26,10 +26,10 @@ import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.activityViewModel
class RemoveSongFromPlaylistDialog : DialogFragment() { class RemoveSongFromPlaylistDialog : DialogFragment() {
private val libraryViewModel by sharedViewModel<LibraryViewModel>() private val libraryViewModel by activityViewModel<LibraryViewModel>()
companion object { companion object {
fun create(song: SongEntity): RemoveSongFromPlaylistDialog { fun create(song: SongEntity): RemoveSongFromPlaylistDialog {

View file

@ -29,11 +29,11 @@ import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.ReloadType
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.activityViewModel
class RenamePlaylistDialog : DialogFragment() { class RenamePlaylistDialog : DialogFragment() {
private val libraryViewModel by sharedViewModel<LibraryViewModel>() private val libraryViewModel by activityViewModel<LibraryViewModel>()
companion object { companion object {
fun create(playlistEntity: PlaylistEntity): RenamePlaylistDialog { fun create(playlistEntity: PlaylistEntity): RenamePlaylistDialog {

View file

@ -17,6 +17,7 @@ package code.name.monkey.retromusic.dialogs
import android.app.AlarmManager import android.app.AlarmManager
import android.app.Dialog import android.app.Dialog
import android.app.PendingIntent import android.app.PendingIntent
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.os.CountDownTimer import android.os.CountDownTimer
@ -25,43 +26,45 @@ import android.widget.CheckBox
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.view.isVisible
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.DialogSleepTimerBinding import code.name.monkey.retromusic.databinding.DialogSleepTimerBinding
import code.name.monkey.retromusic.extensions.addAccentColor import code.name.monkey.retromusic.extensions.addAccentColor
import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_PENDING_QUIT import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_PENDING_QUIT
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_QUIT import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_QUIT
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.WhichButton
import com.afollestad.materialdialogs.actions.getActionButton
class SleepTimerDialog : DialogFragment() { class SleepTimerDialog : DialogFragment() {
private var seekArcProgress: Int = 0 private var seekArcProgress: Int = 0
private lateinit var timerUpdater: TimerUpdater private lateinit var timerUpdater: TimerUpdater
private lateinit var dialog: MaterialDialog private lateinit var dialog: AlertDialog
private lateinit var shouldFinishLastSong: CheckBox
private lateinit var timerDisplay: TextView private var _binding: DialogSleepTimerBinding? = null
private val binding get() = _binding!!
private val shouldFinishLastSong: CheckBox get() = binding.shouldFinishLastSong
private val seekBar: SeekBar get() = binding.seekBar
private val timerDisplay: TextView get() = binding.timerDisplay
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
timerUpdater = TimerUpdater() timerUpdater = TimerUpdater()
val binding = DialogSleepTimerBinding.inflate(layoutInflater) _binding = DialogSleepTimerBinding.inflate(layoutInflater)
shouldFinishLastSong = binding.shouldFinishLastSong
timerDisplay = binding.timerDisplay
val finishMusic = PreferenceUtil.isSleepTimerFinishMusic val finishMusic = PreferenceUtil.isSleepTimerFinishMusic
shouldFinishLastSong.apply { shouldFinishLastSong.apply {
addAccentColor() addAccentColor()
isChecked = finishMusic isChecked = finishMusic
} }
binding.seekBar.apply { seekBar.apply {
addAccentColor() addAccentColor()
seekArcProgress = PreferenceUtil.lastSleepTimerValue seekArcProgress = PreferenceUtil.lastSleepTimerValue
updateTimeDisplayTime() updateTimeDisplayTime()
@ -85,47 +88,65 @@ class SleepTimerDialog : DialogFragment() {
PreferenceUtil.lastSleepTimerValue = seekArcProgress PreferenceUtil.lastSleepTimerValue = seekArcProgress
} }
}) })
return materialDialog(R.string.action_sleep_timer)
.setView(binding.root)
.setPositiveButton(R.string.action_set) { _, _ ->
PreferenceUtil.isSleepTimerFinishMusic = shouldFinishLastSong.isChecked
val minutes = seekArcProgress
val pi = makeTimerPendingIntent(PendingIntent.FLAG_CANCEL_CURRENT)
val nextSleepTimerElapsedTime = SystemClock.elapsedRealtime() + minutes * 60 * 1000
PreferenceUtil.nextSleepTimerElapsedRealTime = nextSleepTimerElapsedTime.toInt()
val am = requireContext().getSystemService<AlarmManager>()
am?.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextSleepTimerElapsedTime, pi)
Toast.makeText( materialDialog(R.string.action_sleep_timer).apply {
requireContext(), if (PreferenceUtil.nextSleepTimerElapsedRealTime > System.currentTimeMillis()) {
requireContext().resources.getString(R.string.sleep_timer_set, minutes), seekBar.isVisible = false
Toast.LENGTH_SHORT shouldFinishLastSong.isVisible = false
).show() timerUpdater.start()
} setPositiveButton(android.R.string.ok, null)
.setNegativeButton(android.R.string.cancel) { _, _ -> setNegativeButton(R.string.action_cancel) { _, _ ->
val previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE) timerUpdater.cancel()
if (previous != null) { val previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE)
val am = requireContext().getSystemService<AlarmManager>() if (previous != null) {
am?.cancel(previous) val am = requireContext().getSystemService<AlarmManager>()
previous.cancel() am?.cancel(previous)
Toast.makeText( previous.cancel()
requireContext(),
requireContext().resources.getString(R.string.sleep_timer_canceled),
Toast.LENGTH_SHORT
).show()
val musicService = MusicPlayerRemote.musicService
if (musicService != null && musicService.pendingQuit) {
musicService.pendingQuit = false
Toast.makeText( Toast.makeText(
requireContext(), requireContext(),
requireContext().resources.getString(R.string.sleep_timer_canceled), requireContext().resources.getString(R.string.sleep_timer_canceled),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
val musicService = MusicPlayerRemote.musicService
if (musicService != null && musicService.pendingQuit) {
musicService.pendingQuit = false
Toast.makeText(
requireContext(),
requireContext().resources.getString(R.string.sleep_timer_canceled),
Toast.LENGTH_SHORT
).show()
}
} }
} }
} else {
seekBar.isVisible = true
shouldFinishLastSong.isVisible = true
setPositiveButton(R.string.action_set) { _, _ ->
PreferenceUtil.isSleepTimerFinishMusic = shouldFinishLastSong.isChecked
val minutes = seekArcProgress
val pi = makeTimerPendingIntent(PendingIntent.FLAG_CANCEL_CURRENT)
val nextSleepTimerElapsedTime =
SystemClock.elapsedRealtime() + minutes * 60 * 1000
PreferenceUtil.nextSleepTimerElapsedRealTime = nextSleepTimerElapsedTime.toInt()
val am = requireContext().getSystemService<AlarmManager>()
am?.setExact(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
nextSleepTimerElapsedTime,
pi
)
Toast.makeText(
requireContext(),
requireContext().resources.getString(R.string.sleep_timer_set, minutes),
Toast.LENGTH_SHORT
).show()
}
} }
.create() setView(binding.root)
.colorButtons() dialog = create()
}
return dialog
} }
private fun updateTimeDisplayTime() { private fun updateTimeDisplayTime() {
@ -147,14 +168,10 @@ class SleepTimerDialog : DialogFragment() {
} else intent.setAction(ACTION_QUIT) } else intent.setAction(ACTION_QUIT)
} }
private fun updateCancelButton() { override fun onDismiss(dialog: DialogInterface) {
val musicService = MusicPlayerRemote.musicService super.onDismiss(dialog)
if (musicService != null && musicService.pendingQuit) { timerUpdater.cancel()
dialog.getActionButton(WhichButton.NEUTRAL).text = _binding = null
dialog.context.getString(R.string.cancel_current_timer)
} else {
dialog.getActionButton(WhichButton.NEUTRAL).text = null
}
} }
private inner class TimerUpdater : private inner class TimerUpdater :
@ -164,10 +181,9 @@ class SleepTimerDialog : DialogFragment() {
) { ) {
override fun onTick(millisUntilFinished: Long) { override fun onTick(millisUntilFinished: Long) {
timerDisplay.text = MusicUtil.getReadableDurationString(millisUntilFinished)
} }
override fun onFinish() { override fun onFinish() {}
updateCancelButton()
}
} }
} }

View file

@ -19,6 +19,7 @@ import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.Spanned import android.text.Spanned
import android.util.Log import android.util.Log
import androidx.core.os.BundleCompat
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.text.parseAsHtml import androidx.core.text.parseAsHtml
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
@ -38,7 +39,7 @@ class SongDetailDialog : DialogFragment() {
val context: Context = requireContext() val context: Context = requireContext()
val binding = DialogFileDetailsBinding.inflate(layoutInflater) val binding = DialogFileDetailsBinding.inflate(layoutInflater)
val song = requireArguments().getParcelable<Song>(EXTRA_SONG) val song = BundleCompat.getParcelable(requireArguments(), EXTRA_SONG, Song::class.java)
with(binding) { with(binding) {
fileName.text = makeTextWithTitle(context, R.string.label_file_name, "-") fileName.text = makeTextWithTitle(context, R.string.label_file_name, "-")
filePath.text = makeTextWithTitle(context, R.string.label_file_path, "-") filePath.text = makeTextWithTitle(context, R.string.label_file_path, "-")

View file

@ -17,6 +17,7 @@ package code.name.monkey.retromusic.dialogs
import android.app.Dialog import android.app.Dialog
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.core.os.BundleCompat
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.EXTRA_SONG
@ -29,7 +30,7 @@ import code.name.monkey.retromusic.util.MusicUtil
class SongShareDialog : DialogFragment() { class SongShareDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val song: Song? = requireArguments().getParcelable(EXTRA_SONG) val song: Song? = BundleCompat.getParcelable(requireArguments(), EXTRA_SONG, Song::class.java)
val listening: String = val listening: String =
String.format( String.format(
getString(R.string.currently_listening_to_x_by_x), getString(R.string.currently_listening_to_x_by_x),
@ -60,8 +61,7 @@ class SongShareDialog : DialogFragment() {
0 -> { 0 -> {
startActivity(Intent.createChooser(song?.let { startActivity(Intent.createChooser(song?.let {
MusicUtil.createShareSongFileIntent( MusicUtil.createShareSongFileIntent(
it, requireContext(), it
requireContext()
) )
}, null)) }, null))
} }

View file

@ -20,6 +20,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.DimenRes import androidx.annotation.DimenRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.BundleCompat
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar

View file

@ -16,7 +16,7 @@ import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
fun AppCompatActivity.toggleScreenOn() { fun AppCompatActivity.maybeSetScreenOn() {
if (PreferenceUtil.isScreenOnEnabled) { if (PreferenceUtil.isScreenOnEnabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else { } else {

View file

@ -52,7 +52,7 @@ fun Int.ripAlpha(): Int {
fun Dialog.colorControlNormal() = resolveColor(android.R.attr.colorControlNormal) fun Dialog.colorControlNormal() = resolveColor(android.R.attr.colorControlNormal)
fun Toolbar.backgroundTintList() { fun Toolbar.backgroundTintList() {
val surfaceColor = ATHUtil.resolveColor(context, R.attr.colorSurface, Color.BLACK) val surfaceColor = ATHUtil.resolveColor(context, com.google.android.material.R.attr.colorSurface, Color.BLACK)
val colorStateList = ColorStateList.valueOf(surfaceColor) val colorStateList = ColorStateList.valueOf(surfaceColor)
backgroundTintList = colorStateList backgroundTintList = colorStateList
} }
@ -61,13 +61,13 @@ fun Context.accentColor() = ThemeStore.accentColor(this)
fun Fragment.accentColor() = ThemeStore.accentColor(requireContext()) fun Fragment.accentColor() = ThemeStore.accentColor(requireContext())
fun Context.surfaceColor() = resolveColor(R.attr.colorSurface, Color.WHITE) fun Context.surfaceColor() = resolveColor(com.google.android.material.R.attr.colorSurface, Color.WHITE)
fun Fragment.surfaceColor() = resolveColor(R.attr.colorSurface, Color.WHITE) fun Fragment.surfaceColor() = resolveColor(com.google.android.material.R.attr.colorSurface, Color.WHITE)
fun Context.surfaceColor(fallBackColor: Int) = resolveColor(R.attr.colorSurface, fallBackColor) fun Context.surfaceColor(fallBackColor: Int) = resolveColor(com.google.android.material.R.attr.colorSurface, fallBackColor)
fun Fragment.surfaceColor(fallBackColor: Int) = resolveColor(R.attr.colorSurface, fallBackColor) fun Fragment.surfaceColor(fallBackColor: Int) = resolveColor(com.google.android.material.R.attr.colorSurface, fallBackColor)
fun Context.textColorSecondary() = resolveColor(android.R.attr.textColorSecondary) fun Context.textColorSecondary() = resolveColor(android.R.attr.textColorSecondary)
@ -135,7 +135,9 @@ fun Button.accentTextColor() {
fun MaterialButton.accentBackgroundColor() { fun MaterialButton.accentBackgroundColor() {
if (materialYou) return if (materialYou) return
backgroundTintList = ColorStateList.valueOf(context.accentColor()) backgroundTintList = ColorStateList(
arrayOf(intArrayOf(android.R.attr.state_enabled), intArrayOf()),
intArrayOf(context.accentColor(), context.accentColor().addAlpha(0.12f)))
} }
fun MaterialButton.accentOutlineColor() { fun MaterialButton.accentOutlineColor() {
@ -163,6 +165,15 @@ fun SeekBar.applyColor(@ColorInt color: Int) {
progressBackgroundTintList = ColorStateList.valueOf(color) progressBackgroundTintList = ColorStateList.valueOf(color)
} }
fun Slider.applyColor(@ColorInt color: Int) {
ColorStateList.valueOf(color).run {
thumbTintList = this
trackActiveTintList = this
trackInactiveTintList = ColorStateList.valueOf(color.addAlpha(0.1f))
haloTintList = this
}
}
fun ExtendedFloatingActionButton.accentColor() { fun ExtendedFloatingActionButton.accentColor() {
if (materialYou) return if (materialYou) return
val color = ThemeStore.accentColor(context) val color = ThemeStore.accentColor(context)
@ -301,5 +312,9 @@ inline val @receiver:ColorInt Int.lighterColor
inline val @receiver:ColorInt Int.darkerColor inline val @receiver:ColorInt Int.darkerColor
get() = ColorUtil.darkenColor(this) get() = ColorUtil.darkenColor(this)
inline val Int.colorStateList : ColorStateList inline val Int.colorStateList: ColorStateList
get() = ColorStateList.valueOf(this) get() = ColorStateList.valueOf(this)
fun @receiver:ColorInt Int.addAlpha(alpha: Float): Int {
return ColorUtil.withAlpha(this, alpha)
}

View file

@ -4,7 +4,7 @@ import androidx.core.view.WindowInsetsCompat
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
fun WindowInsetsCompat?.safeGetBottomInsets(): Int { fun WindowInsetsCompat?.getBottomInsets(): Int {
return if (PreferenceUtil.isFullScreenMode) { return if (PreferenceUtil.isFullScreenMode) {
return 0 return 0
} else { } else {

View file

@ -21,6 +21,7 @@ import androidx.navigation.NavController
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.navOptions
fun Fragment.navigate(@IdRes id: Int) = findNavController().navigate(id) fun Fragment.navigate(@IdRes id: Int) = findNavController().navigate(id)
@ -37,3 +38,13 @@ fun AppCompatActivity.findNavController(@IdRes id: Int): NavController {
val fragment = supportFragmentManager.findFragmentById(id) as NavHostFragment val fragment = supportFragmentManager.findFragmentById(id) as NavHostFragment
return fragment.navController return fragment.navController
} }
val fadeNavOptions
get() = navOptions {
anim {
enter = android.R.anim.fade_in
exit = android.R.anim.fade_out
popEnter = android.R.anim.fade_in
popExit = android.R.anim.fade_out
}
}

View file

@ -3,17 +3,20 @@ package code.name.monkey.retromusic.extensions
import android.support.v4.media.MediaDescriptionCompat import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.session.MediaSessionCompat.QueueItem import android.support.v4.media.session.MediaSessionCompat.QueueItem
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
val Song.uri get() = code.name.monkey.retromusic.util.MusicUtil.getSongFileUri(songId = id) val Song.uri get() = MusicUtil.getSongFileUri(songId = id)
val Song.albumArtUri get() = MusicUtil.getMediaStoreAlbumCoverUri(albumId)
fun ArrayList<Song>.toMediaSessionQueue(): List<QueueItem> { fun ArrayList<Song>.toMediaSessionQueue(): List<QueueItem> {
return map { return map { song ->
val mediaDescription = MediaDescriptionCompat.Builder() val mediaDescription = MediaDescriptionCompat.Builder()
.setMediaId(it.id.toString()) .setMediaId(song.id.toString())
.setTitle(it.title) .setTitle(song.title)
.setSubtitle(it.artistName) .setSubtitle(song.artistName)
.setIconUri(song.albumArtUri)
.build() .build()
QueueItem(mediaDescription, it.hashCode().toLong()) QueueItem(mediaDescription, song.hashCode().toLong())
} }
} }

View file

@ -16,6 +16,7 @@ package code.name.monkey.retromusic.extensions
import android.animation.Animator import android.animation.Animator
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.content.res.ColorStateList
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -24,6 +25,7 @@ import android.view.ViewTreeObserver
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.EditText import android.widget.EditText
import androidx.annotation.ColorInt
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.annotation.Px import androidx.annotation.Px
import androidx.core.animation.doOnEnd import androidx.core.animation.doOnEnd
@ -37,8 +39,12 @@ import code.name.monkey.retromusic.util.RetroUtil
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import com.google.android.material.navigation.NavigationBarView
import com.google.android.material.navigationrail.NavigationRailView
import dev.chrisbanes.insetter.applyInsetter import dev.chrisbanes.insetter.applyInsetter
const val ANIM_DURATION = 300L
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T : View> ViewGroup.inflate(@LayoutRes layout: Int): T { fun <T : View> ViewGroup.inflate(@LayoutRes layout: Int): T {
return LayoutInflater.from(context).inflate(layout, this, false) as T return LayoutInflater.from(context).inflate(layout, this, false) as T
@ -62,6 +68,15 @@ fun EditText.appHandleColor(): EditText {
return this return this
} }
fun NavigationBarView.setItemColors(@ColorInt normalColor: Int, @ColorInt selectedColor: Int) {
val csl = ColorStateList(
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)),
intArrayOf(normalColor, selectedColor)
)
itemIconTintList = csl
itemTextColor = csl
}
/** /**
* Potentially animate showing a [BottomNavigationView]. * Potentially animate showing a [BottomNavigationView].
* *
@ -71,7 +86,8 @@ fun EditText.appHandleColor(): EditText {
* Instead, take a snapshot of the view, and animate this in, only changing the visibility (and * Instead, take a snapshot of the view, and animate this in, only changing the visibility (and
* thus layout) when the animation completes. * thus layout) when the animation completes.
*/ */
fun BottomNavigationView.show() { fun NavigationBarView.show() {
if (this is NavigationRailView) return
if (isVisible) return if (isVisible) return
val parent = parent as ViewGroup val parent = parent as ViewGroup
@ -89,10 +105,10 @@ fun BottomNavigationView.show() {
drawable.setBounds(left, parent.height, right, parent.height + height) drawable.setBounds(left, parent.height, right, parent.height + height)
parent.overlay.add(drawable) parent.overlay.add(drawable)
ValueAnimator.ofInt(parent.height, top).apply { ValueAnimator.ofInt(parent.height, top).apply {
duration = 300 duration = ANIM_DURATION
interpolator = AnimationUtils.loadInterpolator( interpolator = AnimationUtils.loadInterpolator(
context, context,
android.R.interpolator.linear_out_slow_in android.R.interpolator.accelerate_decelerate
) )
addUpdateListener { addUpdateListener {
val newTop = it.animatedValue as Int val newTop = it.animatedValue as Int
@ -115,19 +131,25 @@ fun BottomNavigationView.show() {
* Instead, take a snapshot, instantly hide the view (so content lays out to fill), then animate * Instead, take a snapshot, instantly hide the view (so content lays out to fill), then animate
* out the snapshot. * out the snapshot.
*/ */
fun BottomNavigationView.hide() { fun NavigationBarView.hide() {
if (this is NavigationRailView) return
if (isGone) return if (isGone) return
if (!isLaidOut) {
isGone = true
return
}
val drawable = BitmapDrawable(context.resources, drawToBitmap()) val drawable = BitmapDrawable(context.resources, drawToBitmap())
val parent = parent as ViewGroup val parent = parent as ViewGroup
drawable.setBounds(left, top, right, bottom) drawable.setBounds(left, top, right, bottom)
parent.overlay.add(drawable) parent.overlay.add(drawable)
isGone = true isGone = true
ValueAnimator.ofInt(top, parent.height).apply { ValueAnimator.ofInt(top, parent.height).apply {
duration = 300L duration = ANIM_DURATION
interpolator = AnimationUtils.loadInterpolator( interpolator = AnimationUtils.loadInterpolator(
context, context,
android.R.interpolator.fast_out_linear_in android.R.interpolator.accelerate_decelerate
) )
addUpdateListener { addUpdateListener {
val newTop = it.animatedValue as Int val newTop = it.animatedValue as Int
@ -158,7 +180,7 @@ fun View.translateYAnimate(value: Float): Animator {
fun BottomSheetBehavior<*>.peekHeightAnimate(value: Int): Animator { fun BottomSheetBehavior<*>.peekHeightAnimate(value: Int): Animator {
return ObjectAnimator.ofInt(this, "peekHeight", value) return ObjectAnimator.ofInt(this, "peekHeight", value)
.apply { .apply {
duration = 300 duration = ANIM_DURATION
start() start()
} }
} }
@ -254,7 +276,7 @@ fun View.updateMargin(
@Px left: Int = marginLeft, @Px left: Int = marginLeft,
@Px top: Int = marginTop, @Px top: Int = marginTop,
@Px right: Int = marginRight, @Px right: Int = marginRight,
@Px bottom: Int = marginBottom @Px bottom: Int = marginBottom,
) { ) {
(layoutParams as ViewGroup.MarginLayoutParams).updateMargins(left, top, right, bottom) (layoutParams as ViewGroup.MarginLayoutParams).updateMargins(left, top, right, bottom)
} }
@ -295,7 +317,7 @@ fun View.requestApplyInsetsWhenAttached() {
data class InitialPadding( data class InitialPadding(
val left: Int, val top: Int, val left: Int, val top: Int,
val right: Int, val bottom: Int val right: Int, val bottom: Int,
) )
fun recordInitialPaddingForView(view: View) = InitialPadding( fun recordInitialPaddingForView(view: View) = InitialPadding(

View file

@ -16,7 +16,6 @@ package code.name.monkey.retromusic.fragments
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.content.Context import android.content.Context
import android.widget.Toast
import androidx.core.animation.doOnEnd import androidx.core.animation.doOnEnd
import androidx.lifecycle.* import androidx.lifecycle.*
import code.name.monkey.retromusic.RECENT_ALBUMS import code.name.monkey.retromusic.RECENT_ALBUMS
@ -34,6 +33,7 @@ import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.util.DensityUtil import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.logD
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -145,48 +145,47 @@ class LibraryViewModel(
} }
override fun onMediaStoreChanged() { override fun onMediaStoreChanged() {
println("onMediaStoreChanged") logD("onMediaStoreChanged")
loadLibraryContent() loadLibraryContent()
} }
override fun onServiceConnected() { override fun onServiceConnected() {
println("onServiceConnected") logD("onServiceConnected")
} }
override fun onServiceDisconnected() { override fun onServiceDisconnected() {
println("onServiceDisconnected") logD("onServiceDisconnected")
} }
override fun onQueueChanged() { override fun onQueueChanged() {
println("onQueueChanged") logD("onQueueChanged")
} }
override fun onPlayingMetaChanged() { override fun onPlayingMetaChanged() {
println("onPlayingMetaChanged") logD("onPlayingMetaChanged")
} }
override fun onPlayStateChanged() { override fun onPlayStateChanged() {
println("onPlayStateChanged") logD("onPlayStateChanged")
} }
override fun onRepeatModeChanged() { override fun onRepeatModeChanged() {
println("onRepeatModeChanged") logD("onRepeatModeChanged")
} }
override fun onShuffleModeChanged() { override fun onShuffleModeChanged() {
println("onShuffleModeChanged") logD("onShuffleModeChanged")
} }
override fun onFavoriteStateChanged() { override fun onFavoriteStateChanged() {
println("onFavoriteStateChanged") logD("onFavoriteStateChanged")
} }
fun shuffleSongs() = viewModelScope.launch(IO) { fun shuffleSongs() = viewModelScope.launch(IO) {
val songs = repository.allSongs() val songs = repository.allSongs()
MusicPlayerRemote.openAndShuffleQueue( withContext(Main) {
songs, MusicPlayerRemote.openAndShuffleQueue(songs, true)
true }
)
} }
fun renameRoomPlaylist(playListId: Long, name: String) = viewModelScope.launch(IO) { fun renameRoomPlaylist(playListId: Long, name: String) = viewModelScope.launch(IO) {
@ -351,8 +350,7 @@ class LibraryViewModel(
context.getString( context.getString(
R.string.added_song_count_to_playlist, R.string.added_song_count_to_playlist,
songs.size, songs.size,
playlistName), playlistName))
Toast.LENGTH_SHORT)
} }
} }
} }

View file

@ -1,13 +1,14 @@
package code.name.monkey.retromusic.fragments package code.name.monkey.retromusic.fragments
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.view.GestureDetector
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewConfiguration
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlin.math.abs
/** /**
* @param activity, Activity * @param activity, Activity
@ -16,46 +17,63 @@ import kotlinx.coroutines.*
class MusicSeekSkipTouchListener(val activity: FragmentActivity, val next: Boolean) : class MusicSeekSkipTouchListener(val activity: FragmentActivity, val next: Boolean) :
View.OnTouchListener { View.OnTouchListener {
var job: Job? = null private var job: Job? = null
var counter = 0 private var counter = 0
var wasSeeking = false private var wasSeeking = false
private val gestureDetector = GestureDetector(activity, object : private var startX = 0f
GestureDetector.SimpleOnGestureListener() { private var startY = 0f
override fun onDown(e: MotionEvent?): Boolean {
job = activity.lifecycleScope.launch(Dispatchers.Default) { private val scaledTouchSlop = ViewConfiguration.get(activity).scaledTouchSlop
counter = 0
while (isActive) {
delay(500)
wasSeeking = true
var seekingDuration = MusicPlayerRemote.songProgressMillis
if (next) {
seekingDuration += 5000 * (counter.floorDiv(2) + 1)
} else {
seekingDuration -= 5000 * (counter.floorDiv(2) + 1)
}
MusicPlayerRemote.seekTo(seekingDuration)
counter += 1
}
}
return super.onDown(e)
}
})
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View?, event: MotionEvent?): Boolean { override fun onTouch(v: View?, event: MotionEvent?): Boolean {
val action = event?.actionMasked when (event?.actionMasked) {
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { MotionEvent.ACTION_DOWN -> {
job?.cancel() startX = event.x
if (!wasSeeking) { startY = event.y
if (next) { job = activity.lifecycleScope.launch(Dispatchers.Default) {
MusicPlayerRemote.playNextSong() counter = 0
} else { while (isActive) {
MusicPlayerRemote.back() delay(500)
wasSeeking = true
var seekingDuration = MusicPlayerRemote.songProgressMillis
if (next) {
seekingDuration += 5000 * (counter.floorDiv(2) + 1)
} else {
seekingDuration -= 5000 * (counter.floorDiv(2) + 1)
}
withContext(Dispatchers.Main) {
MusicPlayerRemote.seekTo(seekingDuration)
}
counter += 1
}
} }
} }
wasSeeking = false MotionEvent.ACTION_UP -> {
job?.cancel()
val endX = event.x
val endY = event.y
if (!wasSeeking && isAClick(startX, endX, startY, endY)) {
if (next) {
MusicPlayerRemote.playNextSong()
} else {
MusicPlayerRemote.back()
}
}
wasSeeking = false
}
MotionEvent.ACTION_CANCEL -> {
job?.cancel()
}
} }
return gestureDetector.onTouchEvent(event) return false
}
private fun isAClick(startX: Float, endX: Float, startY: Float, endY: Float): Boolean {
val differenceX = abs(startX - endX)
val differenceY = abs(startY - endY)
return !(differenceX > scaledTouchSlop || differenceY > scaledTouchSlop)
} }
} }

View file

@ -25,12 +25,11 @@ import code.name.monkey.retromusic.extensions.openUrl
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.NavigationUtil
import dev.chrisbanes.insetter.applyInsetter import dev.chrisbanes.insetter.applyInsetter
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.activityViewModel
class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener { class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
private var _binding: FragmentAboutBinding? = null private var _binding: FragmentAboutBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -40,7 +39,7 @@ class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
binding.aboutContent.root.applyInsetter { binding.aboutContent.root.applyInsetter {
type(navigationBars = true) { type(navigationBars = true) {
padding() padding(vertical = true)
} }
} }
} }

View file

@ -18,8 +18,11 @@ import android.app.ActivityOptions
import android.content.Intent import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.Menu
import androidx.activity.addCallback import android.view.MenuInflater
import android.view.MenuItem
import android.view.SubMenu
import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.doOnPreDraw import androidx.core.view.doOnPreDraw
@ -43,10 +46,16 @@ import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.databinding.FragmentAlbumDetailsBinding import code.name.monkey.retromusic.databinding.FragmentAlbumDetailsBinding
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.extensions.applyOutlineColor
import code.name.monkey.retromusic.extensions.findActivityNavController
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.asBitmapPalette
import code.name.monkey.retromusic.glide.SingleColorTarget import code.name.monkey.retromusic.glide.SingleColorTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder.Companion.SONG_A_Z import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder.Companion.SONG_A_Z
@ -54,18 +63,15 @@ import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder.Companion
import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder.Companion.SONG_TRACK_LIST import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder.Companion.SONG_TRACK_LIST
import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder.Companion.SONG_Z_A import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder.Companion.SONG_Z_A
import code.name.monkey.retromusic.interfaces.IAlbumClickListener import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.ICabCallback
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil import code.name.monkey.retromusic.util.RetroUtil
import com.afollestad.materialcab.attached.AttachedCab import code.name.monkey.retromusic.util.logD
import com.afollestad.materialcab.attached.destroy import code.name.monkey.retromusic.util.logE
import com.afollestad.materialcab.attached.isActive import com.bumptech.glide.Glide
import com.afollestad.materialcab.createCab
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.transition.MaterialArcMotion import com.google.android.material.transition.MaterialArcMotion
import com.google.android.material.transition.MaterialContainerTransform import com.google.android.material.transition.MaterialContainerTransform
@ -78,7 +84,7 @@ import org.koin.core.parameter.parametersOf
import java.text.Collator import java.text.Collator
class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_details), class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_details),
IAlbumClickListener, ICabHolder { IAlbumClickListener {
private var _binding: FragmentAlbumDetailsBinding? = null private var _binding: FragmentAlbumDetailsBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
@ -114,12 +120,12 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
binding.toolbar.title = " " binding.toolbar.title = " "
binding.albumCoverContainer.transitionName = arguments.extraAlbumId.toString() binding.albumCoverContainer.transitionName = arguments.extraAlbumId.toString()
postponeEnterTransition() postponeEnterTransition()
detailsViewModel.getAlbum().observe(viewLifecycleOwner) { detailsViewModel.getAlbum().observe(viewLifecycleOwner) { album ->
view.doOnPreDraw { view.doOnPreDraw {
startPostponedEnterTransition() startPostponedEnterTransition()
} }
albumArtistExists = !it.albumArtist.isNullOrEmpty() albumArtistExists = !album.albumArtist.isNullOrEmpty()
showAlbum(it) showAlbum(album)
binding.artistImage.transitionName = if (albumArtistExists) { binding.artistImage.transitionName = if (albumArtistExists) {
album.albumArtist album.albumArtist
} else { } else {
@ -158,12 +164,6 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
) )
} }
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
requireActivity().onBackPressed()
}
}
binding.appBarLayout?.statusBarForeground = binding.appBarLayout?.statusBarForeground =
MaterialShapeDrawable.createWithElevationOverlay(requireContext()) MaterialShapeDrawable.createWithElevationOverlay(requireContext())
} }
@ -177,8 +177,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
simpleSongAdapter = SimpleSongAdapter( simpleSongAdapter = SimpleSongAdapter(
requireActivity() as AppCompatActivity, requireActivity() as AppCompatActivity,
ArrayList(), ArrayList(),
R.layout.item_song, R.layout.item_song
this
) )
binding.fragmentAlbumContent.recyclerView.apply { binding.fragmentAlbumContent.recyclerView.apply {
layoutManager = LinearLayoutManager(requireContext()) layoutManager = LinearLayoutManager(requireContext())
@ -237,7 +236,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
String.format(getString(R.string.label_more_from), album.artistName) String.format(getString(R.string.label_more_from), album.artistName)
val albumAdapter = val albumAdapter =
HorizontalAlbumAdapter(requireActivity() as AppCompatActivity, albums, this, this) HorizontalAlbumAdapter(requireActivity() as AppCompatActivity, albums, this)
binding.fragmentAlbumContent.moreRecyclerView.layoutManager = GridLayoutManager( binding.fragmentAlbumContent.moreRecyclerView.layoutManager = GridLayoutManager(
requireContext(), requireContext(),
1, 1,
@ -251,7 +250,8 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
detailsViewModel.getMoreAlbums(artist).observe(viewLifecycleOwner) { detailsViewModel.getMoreAlbums(artist).observe(viewLifecycleOwner) {
moreAlbums(it) moreAlbums(it)
} }
GlideApp.with(requireContext()) Glide.with(requireContext())
//.forceDownload(PreferenceUtil.isAllowedToDownloadMetadata())
.load( .load(
RetroGlideExtension.getArtistModel(artist) RetroGlideExtension.getArtistModel(artist)
) )
@ -262,7 +262,8 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
} }
private fun loadAlbumCover(album: Album) { private fun loadAlbumCover(album: Album) {
GlideApp.with(requireContext()).asBitmapPalette() Glide.with(requireContext())
.asBitmapPalette()
.albumCoverOptions(album.safeGetFirstSong()) .albumCoverOptions(album.safeGetFirstSong())
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(album.safeGetFirstSong())) .load(RetroGlideExtension.getSongModel(album.safeGetFirstSong()))
@ -294,7 +295,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_album_detail, menu) inflater.inflate(R.menu.menu_album_detail, menu)
val sortOrder = menu.findItem(R.id.action_sort_order) val sortOrder = menu.findItem(R.id.action_sort_order)
setUpSortOrderMenu(sortOrder.subMenu) setUpSortOrderMenu(sortOrder.subMenu!!)
ToolbarContentTintHelper.handleOnCreateOptionsMenu( ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(), requireContext(),
binding.toolbar, binding.toolbar,
@ -407,38 +408,6 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
simpleSongAdapter.swapDataSet(album.songs) simpleSongAdapter.swapDataSet(album.songs)
} }
private fun handleBackPress(): Boolean {
cab?.let {
if (it.isActive()) {
it.destroy()
return true
}
}
return false
}
private var cab: AttachedCab? = null
override fun openCab(menuRes: Int, callback: ICabCallback): AttachedCab {
cab?.let {
if (it.isActive()) {
it.destroy()
}
}
cab = createCab(R.id.toolbar_container) {
menu(menuRes)
closeDrawable(R.drawable.ic_close)
backgroundColor(literal = RetroColorUtil.shiftBackgroundColor(surfaceColor()))
slideDown()
onCreate { cab, menu -> callback.onCabCreated(cab, menu) }
onSelection {
callback.onCabItemClicked(it)
}
onDestroy { callback.onCabFinished(it) }
}
return cab as AttachedCab
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null

View file

@ -16,7 +16,6 @@ package code.name.monkey.retromusic.fragments.albums
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.*
import androidx.activity.addCallback
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.navigation.fragment.FragmentNavigatorExtras import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
@ -24,26 +23,18 @@ import androidx.recyclerview.widget.GridLayoutManager
import code.name.monkey.retromusic.EXTRA_ALBUM_ID import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.AlbumAdapter import code.name.monkey.retromusic.adapter.album.AlbumAdapter
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.GridStyle import code.name.monkey.retromusic.fragments.GridStyle
import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder
import code.name.monkey.retromusic.interfaces.IAlbumClickListener import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.ICabCallback
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
import com.afollestad.materialcab.attached.AttachedCab
import com.afollestad.materialcab.attached.destroy
import com.afollestad.materialcab.attached.isActive
import com.afollestad.materialcab.createCab
class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(), class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
IAlbumClickListener, ICabHolder { IAlbumClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -53,12 +44,6 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
else else
adapter?.swapDataSet(listOf()) adapter?.swapDataSet(listOf())
} }
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
requireActivity().onBackPressed()
}
}
} }
override val titleRes: Int override val titleRes: Int
@ -91,7 +76,6 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
requireActivity(), requireActivity(),
dataSet, dataSet,
itemLayoutRes(), itemLayoutRes(),
this,
this this
) )
} }
@ -163,10 +147,10 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
if (RetroUtil.isLandscape) { if (RetroUtil.isLandscape) {
gridSizeItem.setTitle(R.string.action_grid_size_land) gridSizeItem.setTitle(R.string.action_grid_size_land)
} }
setUpGridSizeMenu(gridSizeItem.subMenu) setUpGridSizeMenu(gridSizeItem.subMenu!!)
val layoutItem = menu.findItem(R.id.action_layout_type) val layoutItem = menu.findItem(R.id.action_layout_type)
setupLayoutMenu(layoutItem.subMenu) setupLayoutMenu(layoutItem.subMenu!!)
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu) setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu!!)
} }
private fun setUpSortOrderMenu( private fun setUpSortOrderMenu(
@ -345,41 +329,6 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
if (cab.isActive()) { adapter?.actionMode?.finish()
cab.destroy()
}
}
private fun handleBackPress(): Boolean {
cab?.let {
if (it.isActive()) {
it.destroy()
return true
}
}
return false
}
private var cab: AttachedCab? = null
override fun openCab(menuRes: Int, callback: ICabCallback): AttachedCab {
cab?.let {
println("Cab")
if (it.isActive()) {
it.destroy()
}
}
cab = createCab(R.id.toolbar_container) {
menu(menuRes)
closeDrawable(R.drawable.ic_close)
backgroundColor(literal = RetroColorUtil.shiftBackgroundColor(surfaceColor()))
slideDown()
onCreate { cab, menu -> callback.onCabCreated(cab, menu) }
onSelection {
callback.onCabItemClicked(it)
}
onDestroy { callback.onCabFinished(it) }
}
return cab as AttachedCab
} }
} }

View file

@ -8,7 +8,6 @@ import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
@ -20,46 +19,36 @@ import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.retromusic.EXTRA_ALBUM_ID import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.extensions.applyOutlineColor
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.databinding.FragmentArtistDetailsBinding import code.name.monkey.retromusic.databinding.FragmentArtistDetailsBinding
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension 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.SingleColorTarget import code.name.monkey.retromusic.glide.SingleColorTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.interfaces.IAlbumClickListener import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.ICabCallback
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.util.CustomArtistImageUtil import code.name.monkey.retromusic.util.CustomArtistImageUtil
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil import com.bumptech.glide.Glide
import code.name.monkey.retromusic.util.*
import com.afollestad.materialcab.attached.AttachedCab
import com.afollestad.materialcab.attached.destroy
import com.afollestad.materialcab.attached.isActive
import com.afollestad.materialcab.createCab
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.transition.MaterialContainerTransform import com.google.android.material.transition.MaterialContainerTransform
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
import java.util.* import java.util.Locale
abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_details), abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_details),
IAlbumClickListener, ICabHolder { IAlbumClickListener {
private var _binding: FragmentArtistDetailsBinding? = null private var _binding: FragmentArtistDetailsBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
@ -106,25 +95,19 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) } setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
} }
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
requireActivity().onBackPressed()
}
}
setupSongSortButton() setupSongSortButton()
binding.appBarLayout?.statusBarForeground = binding.appBarLayout?.statusBarForeground =
MaterialShapeDrawable.createWithElevationOverlay(requireContext()) MaterialShapeDrawable.createWithElevationOverlay(requireContext())
} }
private fun setupRecyclerView() { private fun setupRecyclerView() {
albumAdapter = HorizontalAlbumAdapter(requireActivity(), ArrayList(), this, this) albumAdapter = HorizontalAlbumAdapter(requireActivity(), ArrayList(), this)
binding.fragmentArtistContent.albumRecyclerView.apply { binding.fragmentArtistContent.albumRecyclerView.apply {
itemAnimator = DefaultItemAnimator() itemAnimator = DefaultItemAnimator()
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false) layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
adapter = albumAdapter adapter = albumAdapter
} }
songAdapter = SimpleSongAdapter(requireActivity(), ArrayList(), R.layout.item_song, this) songAdapter = SimpleSongAdapter(requireActivity(), ArrayList(), R.layout.item_song)
binding.fragmentArtistContent.recyclerView.apply { binding.fragmentArtistContent.recyclerView.apply {
itemAnimator = DefaultItemAnimator() itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(this.context) layoutManager = LinearLayoutManager(this.context)
@ -162,7 +145,9 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
} }
private fun loadArtistImage(artist: Artist) { private fun loadArtistImage(artist: Artist) {
GlideApp.with(requireContext()).asBitmapPalette().artistImageOptions(artist) Glide.with(requireContext())
.asBitmapPalette()
.artistImageOptions(artist)
.load(RetroGlideExtension.getArtistModel(artist)) .load(RetroGlideExtension.getArtistModel(artist))
.dontAnimate() .dontAnimate()
.into(object : SingleColorTarget(binding.image) { .into(object : SingleColorTarget(binding.image) {
@ -202,10 +187,12 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
MusicPlayerRemote.playNext(songs) MusicPlayerRemote.playNext(songs)
return true return true
} }
R.id.action_add_to_current_playing -> { R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(songs) MusicPlayerRemote.enqueue(songs)
return true return true
} }
R.id.action_add_to_playlist -> { R.id.action_add_to_playlist -> {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val playlists = get<RealRepository>().fetchPlaylists() val playlists = get<RealRepository>().fetchPlaylists()
@ -216,13 +203,19 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
} }
return true return true
} }
R.id.action_set_artist_image -> { R.id.action_set_artist_image -> {
val intent = Intent(Intent.ACTION_GET_CONTENT) val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*" intent.type = "image/*"
selectImageLauncher.launch(Intent.createChooser(intent, selectImageLauncher.launch(
getString(R.string.pick_from_local_storage))) Intent.createChooser(
intent,
getString(R.string.pick_from_local_storage)
)
)
return true return true
} }
R.id.action_reset_artist_image -> { R.id.action_reset_artist_image -> {
showToast(resources.getString(R.string.updating)) showToast(resources.getString(R.string.updating))
lifecycleScope.launch { lifecycleScope.launch {
@ -270,14 +263,19 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
when (savedSongSortOrder) { when (savedSongSortOrder) {
SortOrder.ArtistSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title).isChecked = SortOrder.ArtistSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title).isChecked =
true true
SortOrder.ArtistSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc).isChecked = SortOrder.ArtistSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc).isChecked =
true true
SortOrder.ArtistSongSortOrder.SONG_ALBUM -> SortOrder.ArtistSongSortOrder.SONG_ALBUM ->
sortOrder.findItem(R.id.action_sort_order_album).isChecked = true sortOrder.findItem(R.id.action_sort_order_album).isChecked = true
SortOrder.ArtistSongSortOrder.SONG_YEAR -> SortOrder.ArtistSongSortOrder.SONG_YEAR ->
sortOrder.findItem(R.id.action_sort_order_year).isChecked = true sortOrder.findItem(R.id.action_sort_order_year).isChecked = true
SortOrder.ArtistSongSortOrder.SONG_DURATION -> SortOrder.ArtistSongSortOrder.SONG_DURATION ->
sortOrder.findItem(R.id.action_sort_order_song_duration).isChecked = true sortOrder.findItem(R.id.action_sort_order_song_duration).isChecked = true
else -> { else -> {
throw IllegalArgumentException("invalid $savedSongSortOrder") throw IllegalArgumentException("invalid $savedSongSortOrder")
} }
@ -301,40 +299,6 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
inflater.inflate(R.menu.menu_artist_detail, menu) inflater.inflate(R.menu.menu_artist_detail, menu)
} }
private fun handleBackPress(): Boolean {
cab?.let {
if (it.isActive()) {
it.destroy()
return true
}
}
return false
}
private var cab: AttachedCab? = null
override fun openCab(menuRes: Int, callback: ICabCallback): AttachedCab {
cab?.let {
if (it.isActive()) {
it.destroy()
}
}
cab = createCab(R.id.toolbar_container) {
menu(menuRes)
closeDrawable(R.drawable.ic_close)
backgroundColor(literal = RetroColorUtil.shiftBackgroundColor(surfaceColor()))
slideDown()
onCreate { cab, menu -> callback.onCabCreated(cab, menu) }
onSelection {
callback.onCabItemClicked(it)
}
onDestroy { callback.onCabFinished(it) }
}
return cab as AttachedCab
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null

View file

@ -16,7 +16,6 @@ package code.name.monkey.retromusic.fragments.artists
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.*
import androidx.activity.addCallback
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.navigation.fragment.FragmentNavigatorExtras import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
@ -25,7 +24,6 @@ import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.EXTRA_ARTIST_NAME import code.name.monkey.retromusic.EXTRA_ARTIST_NAME
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.GridStyle import code.name.monkey.retromusic.fragments.GridStyle
import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
@ -33,19 +31,12 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder.ArtistSortOrder import code.name.monkey.retromusic.helper.SortOrder.ArtistSortOrder
import code.name.monkey.retromusic.interfaces.IAlbumArtistClickListener import code.name.monkey.retromusic.interfaces.IAlbumArtistClickListener
import code.name.monkey.retromusic.interfaces.IArtistClickListener import code.name.monkey.retromusic.interfaces.IArtistClickListener
import code.name.monkey.retromusic.interfaces.ICabCallback
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
import com.afollestad.materialcab.attached.AttachedCab
import com.afollestad.materialcab.attached.destroy
import com.afollestad.materialcab.attached.isActive
import com.afollestad.materialcab.createCab
class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(), class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
IArtistClickListener, IAlbumArtistClickListener, ICabHolder { IArtistClickListener, IAlbumArtistClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
libraryViewModel.getArtists().observe(viewLifecycleOwner) { libraryViewModel.getArtists().observe(viewLifecycleOwner) {
@ -54,12 +45,6 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
else else
adapter?.swapDataSet(listOf()) adapter?.swapDataSet(listOf())
} }
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
requireActivity().onBackPressed()
}
}
} }
override val titleRes: Int override val titleRes: Int
@ -97,7 +82,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
dataSet, dataSet,
itemLayoutRes(), itemLayoutRes(),
this, this,
this, this this
) )
} }
@ -173,10 +158,10 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
if (RetroUtil.isLandscape) { if (RetroUtil.isLandscape) {
gridSizeItem.setTitle(R.string.action_grid_size_land) gridSizeItem.setTitle(R.string.action_grid_size_land)
} }
setUpGridSizeMenu(gridSizeItem.subMenu) setUpGridSizeMenu(gridSizeItem.subMenu!!)
val layoutItem = menu.findItem(R.id.action_layout_type) val layoutItem = menu.findItem(R.id.action_layout_type)
setupLayoutMenu(layoutItem.subMenu) setupLayoutMenu(layoutItem.subMenu!!)
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu) setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu!!)
setupAlbumArtistMenu(menu) setupAlbumArtistMenu(menu)
} }
@ -343,47 +328,8 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
return false return false
} }
private fun handleBackPress(): Boolean {
cab?.let {
if (it.isActive()) {
it.destroy()
return true
}
}
return false
}
private var cab: AttachedCab? = null
override fun openCab(menuRes: Int, callback: ICabCallback): AttachedCab {
cab?.let {
if (it.isActive()) {
it.destroy()
}
}
cab = createCab(R.id.toolbar_container) {
menu(menuRes)
closeDrawable(R.drawable.ic_close)
backgroundColor(literal = RetroColorUtil.shiftBackgroundColor(surfaceColor()))
slideDown()
onCreate { cab, menu -> callback.onCabCreated(cab, menu) }
onSelection {
callback.onCabItemClicked(it)
}
onDestroy { callback.onCabFinished(it) }
}
return cab as AttachedCab
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
libraryViewModel.forceReload(ReloadType.Artists) libraryViewModel.forceReload(ReloadType.Artists)
} }
override fun onPause() {
super.onPause()
if (cab.isActive()) {
cab.destroy()
}
}
} }

View file

@ -22,7 +22,7 @@ import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.helper.BackupHelper import code.name.monkey.retromusic.helper.BackupHelper
import code.name.monkey.retromusic.helper.sanitize import code.name.monkey.retromusic.helper.sanitize
import code.name.monkey.retromusic.util.BackupUtil import code.name.monkey.retromusic.util.Share
import com.afollestad.materialdialogs.input.input import com.afollestad.materialdialogs.input.input
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -128,12 +128,7 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
return true return true
} }
R.id.action_share -> { R.id.action_share -> {
activity?.startActivity( Share.shareFile(requireContext(), file, "*/*")
Intent.createChooser(
BackupUtil.createShareFileIntent(file, requireContext()),
null
)
)
return true return true
} }
R.id.action_rename -> { R.id.action_rename -> {
@ -159,4 +154,9 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
} }
return false return false
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
} }

View file

@ -71,7 +71,7 @@ class RestoreActivity : AppCompatActivity() {
DynamicColors.applyToActivityIfAvailable( DynamicColors.applyToActivityIfAvailable(
this, this,
DynamicColorsOptions.Builder() DynamicColorsOptions.Builder()
.setThemeOverlay(R.style.ThemeOverlay_Material3_DynamicColors_DayNight) .setThemeOverlay(com.google.android.material.R.style.ThemeOverlay_Material3_DynamicColors_DayNight)
.build() .build()
) )
} }

View file

@ -22,11 +22,11 @@ import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.activityViewModel
abstract class AbsMainActivityFragment(@LayoutRes layout: Int) : AbsMusicServiceFragment(layout), abstract class AbsMainActivityFragment(@LayoutRes layout: Int) : AbsMusicServiceFragment(layout),
MenuProvider { MenuProvider {
val libraryViewModel: LibraryViewModel by sharedViewModel() val libraryViewModel: LibraryViewModel by activityViewModel()
val mainActivity: MainActivity val mainActivity: MainActivity
get() = activity as MainActivity get() = activity as MainActivity

View file

@ -17,6 +17,7 @@ package code.name.monkey.retromusic.fragments.base
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.annotation.CallSuper
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.navigation.navOptions import androidx.navigation.navOptions
@ -60,11 +61,13 @@ open class AbsMusicServiceFragment(@LayoutRes layout: Int) : Fragment(layout),
serviceActivity = null serviceActivity = null
} }
@CallSuper
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
serviceActivity?.addMusicServiceEventListener(this) serviceActivity?.addMusicServiceEventListener(this)
} }
@CallSuper
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
serviceActivity?.removeMusicServiceEventListener(this) serviceActivity?.removeMusicServiceEventListener(this)

View file

@ -35,11 +35,11 @@ import code.name.monkey.retromusic.fragments.MusicSeekSkipTouchListener
import code.name.monkey.retromusic.fragments.other.VolumeFragment import code.name.monkey.retromusic.fragments.other.VolumeFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
/** /**
* Created by hemanths on 24/09/17. * Created by hemanths on 24/09/17.
@ -58,10 +58,11 @@ abstract class AbsPlayerControlsFragment(@LayoutRes layout: Int) : AbsMusicServi
var lastDisabledPlaybackControlsColor: Int = 0 var lastDisabledPlaybackControlsColor: Int = 0
var isSeeking = false private var isSeeking = false
private set
open val progressSlider: SeekBar? = null open val progressSlider: Slider? = null
open val seekBar: SeekBar? = null
abstract val shuffleButton: ImageButton abstract val shuffleButton: ImageButton
@ -78,45 +79,75 @@ abstract class AbsPlayerControlsFragment(@LayoutRes layout: Int) : AbsMusicServi
private var progressAnimator: ObjectAnimator? = null private var progressAnimator: ObjectAnimator? = null
override fun onUpdateProgressViews(progress: Int, total: Int) { override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider?.max = total if (seekBar == null) {
progressSlider?.valueTo = total.toFloat()
if (isSeeking) { progressSlider?.value =
progressSlider?.progress = progress progress.toFloat().coerceIn(progressSlider?.valueFrom, progressSlider?.valueTo)
} else { } else {
progressAnimator = ObjectAnimator.ofInt(progressSlider, "progress", progress).apply { seekBar?.max = total
duration = SLIDER_ANIMATION_TIME
interpolator = LinearInterpolator()
start()
}
if (isSeeking) {
seekBar?.progress = progress
} else {
progressAnimator =
ObjectAnimator.ofInt(seekBar, "progress", progress).apply {
duration = SLIDER_ANIMATION_TIME
interpolator = LinearInterpolator()
start()
}
}
} }
songTotalTime?.text = MusicUtil.getReadableDurationString(total.toLong()) songTotalTime?.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress?.text = MusicUtil.getReadableDurationString(progress.toLong()) songCurrentProgress?.text = MusicUtil.getReadableDurationString(progress.toLong())
} }
private fun setUpProgressSlider() { private fun setUpProgressSlider() {
progressSlider?.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() { progressSlider?.addOnChangeListener(Slider.OnChangeListener { _, value, fromUser ->
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { onProgressChange(value.toInt(), fromUser)
if (fromUser) { })
onUpdateProgressViews( progressSlider?.addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
progress, override fun onStartTrackingTouch(slider: Slider) {
MusicPlayerRemote.songDurationMillis onStartTrackingTouch()
)
}
} }
override fun onStartTrackingTouch(seekBar: SeekBar) { override fun onStopTrackingTouch(slider: Slider) {
isSeeking = true onStopTrackingTouch(slider.value.toInt())
progressViewUpdateHelper.stop()
progressAnimator?.cancel()
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
isSeeking = false
MusicPlayerRemote.seekTo(seekBar.progress)
progressViewUpdateHelper.start()
} }
}) })
seekBar?.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
onProgressChange(progress, fromUser)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
onStartTrackingTouch()
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
onStopTrackingTouch(seekBar?.progress ?: 0)
}
})
}
private fun onProgressChange(value: Int, fromUser: Boolean) {
if (fromUser) {
onUpdateProgressViews(value, MusicPlayerRemote.songDurationMillis)
}
}
private fun onStartTrackingTouch() {
isSeeking = true
progressViewUpdateHelper.stop()
progressAnimator?.cancel()
}
private fun onStopTrackingTouch(value: Int) {
isSeeking = false
MusicPlayerRemote.seekTo(value)
progressViewUpdateHelper.start()
} }
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
@ -124,6 +155,11 @@ abstract class AbsPlayerControlsFragment(@LayoutRes layout: Int) : AbsMusicServi
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
if (PreferenceUtil.circlePlayButton) {
requireContext().theme.applyStyle(R.style.CircleFABOverlay, true)
} else {
requireContext().theme.applyStyle(R.style.RoundedFABOverlay, true)
}
} }
fun View.showBounceAnimation() { fun View.showBounceAnimation() {

View file

@ -70,13 +70,13 @@ import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.activityViewModel
import kotlin.math.abs import kotlin.math.abs
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragment(layout), abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragment(layout),
Toolbar.OnMenuItemClickListener, IPaletteColorHolder, PlayerAlbumCoverFragment.Callbacks { Toolbar.OnMenuItemClickListener, IPaletteColorHolder, PlayerAlbumCoverFragment.Callbacks {
val libraryViewModel: LibraryViewModel by sharedViewModel() val libraryViewModel: LibraryViewModel by activityViewModel()
val mainActivity: MainActivity val mainActivity: MainActivity
get() = activity as MainActivity get() = activity as MainActivity
@ -92,6 +92,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
PlaybackSpeedDialog.newInstance().show(childFragmentManager, "PLAYBACK_SETTINGS") PlaybackSpeedDialog.newInstance().show(childFragmentManager, "PLAYBACK_SETTINGS")
return true return true
} }
R.id.action_toggle_lyrics -> { R.id.action_toggle_lyrics -> {
PreferenceUtil.showLyrics = !PreferenceUtil.showLyrics PreferenceUtil.showLyrics = !PreferenceUtil.showLyrics
showLyricsIcon(item) showLyricsIcon(item)
@ -102,26 +103,32 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
} }
return true return true
} }
R.id.action_go_to_lyrics -> { R.id.action_go_to_lyrics -> {
goToLyrics(requireActivity()) goToLyrics(requireActivity())
return true return true
} }
R.id.action_toggle_favorite -> { R.id.action_toggle_favorite -> {
toggleFavorite(song) toggleFavorite(song)
return true return true
} }
R.id.action_share -> { R.id.action_share -> {
SongShareDialog.create(song).show(childFragmentManager, "SHARE_SONG") SongShareDialog.create(song).show(childFragmentManager, "SHARE_SONG")
return true return true
} }
R.id.action_go_to_drive_mode -> { R.id.action_go_to_drive_mode -> {
NavigationUtil.gotoDriveMode(requireActivity()) NavigationUtil.gotoDriveMode(requireActivity())
return true return true
} }
R.id.action_delete_from_device -> { R.id.action_delete_from_device -> {
DeleteSongsDialog.create(song).show(childFragmentManager, "DELETE_SONGS") DeleteSongsDialog.create(song).show(childFragmentManager, "DELETE_SONGS")
return true return true
} }
R.id.action_add_to_playlist -> { R.id.action_add_to_playlist -> {
lifecycleScope.launch(IO) { lifecycleScope.launch(IO) {
val playlists = get<RealRepository>().fetchPlaylists() val playlists = get<RealRepository>().fetchPlaylists()
@ -132,25 +139,30 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
} }
return true return true
} }
R.id.action_clear_playing_queue -> { R.id.action_clear_playing_queue -> {
MusicPlayerRemote.clearQueue() MusicPlayerRemote.clearQueue()
return true return true
} }
R.id.action_save_playing_queue -> { R.id.action_save_playing_queue -> {
CreatePlaylistDialog.create(ArrayList(MusicPlayerRemote.playingQueue)) CreatePlaylistDialog.create(ArrayList(MusicPlayerRemote.playingQueue))
.show(childFragmentManager, "ADD_TO_PLAYLIST") .show(childFragmentManager, "ADD_TO_PLAYLIST")
return true return true
} }
R.id.action_tag_editor -> { R.id.action_tag_editor -> {
val intent = Intent(activity, SongTagEditorActivity::class.java) val intent = Intent(activity, SongTagEditorActivity::class.java)
intent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id) intent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id)
startActivity(intent) startActivity(intent)
return true return true
} }
R.id.action_details -> { R.id.action_details -> {
SongDetailDialog.create(song).show(childFragmentManager, "SONG_DETAIL") SongDetailDialog.create(song).show(childFragmentManager, "SONG_DETAIL")
return true return true
} }
R.id.action_go_to_album -> { R.id.action_go_to_album -> {
//Hide Bottom Bar First, else Bottom Sheet doesn't collapse fully //Hide Bottom Bar First, else Bottom Sheet doesn't collapse fully
mainActivity.setBottomNavVisibility(false) mainActivity.setBottomNavVisibility(false)
@ -161,29 +173,37 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
) )
return true return true
} }
R.id.action_go_to_artist -> { R.id.action_go_to_artist -> {
goToArtist(requireActivity()) goToArtist(requireActivity())
return true return true
} }
R.id.now_playing -> { R.id.now_playing -> {
requireActivity().findNavController(R.id.fragment_container).navigate( requireActivity().findNavController(R.id.fragment_container).navigate(
R.id.playing_queue_fragment, R.id.playing_queue_fragment,
null null,
navOptions { launchSingleTop = true }
) )
mainActivity.collapsePanel()
return true return true
} }
R.id.action_show_lyrics -> { R.id.action_show_lyrics -> {
goToLyrics(requireActivity()) goToLyrics(requireActivity())
return true return true
} }
R.id.action_equalizer -> { R.id.action_equalizer -> {
NavigationUtil.openEqualizer(requireActivity()) NavigationUtil.openEqualizer(requireActivity())
return true return true
} }
R.id.action_sleep_timer -> { R.id.action_sleep_timer -> {
SleepTimerDialog().show(parentFragmentManager, "SLEEP_TIMER") SleepTimerDialog().show(parentFragmentManager, "SLEEP_TIMER")
return true return true
} }
R.id.action_set_as_ringtone -> { R.id.action_set_as_ringtone -> {
requireContext().run { requireContext().run {
if (RingtoneManager.requiresDialog(this)) { if (RingtoneManager.requiresDialog(this)) {
@ -195,6 +215,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
return true return true
} }
R.id.action_go_to_genre -> { R.id.action_go_to_genre -> {
val retriever = MediaMetadataRetriever() val retriever = MediaMetadataRetriever()
val trackUri = val trackUri =
@ -294,6 +315,15 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
} }
} }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (PreferenceUtil.circlePlayButton) {
requireContext().theme.applyStyle(R.style.CircleFABOverlay, true)
} else {
requireContext().theme.applyStyle(R.style.RoundedFABOverlay, true)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
if (PreferenceUtil.isFullScreenMode && if (PreferenceUtil.isFullScreenMode &&
@ -321,7 +351,15 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
showLyricsIcon(this) showLyricsIcon(this)
} }
} }
requireView().setOnTouchListener( }
override fun onStart() {
super.onStart()
addSwipeDetector()
}
fun addSwipeDetector() {
view?.setOnTouchListener(
if (PreferenceUtil.swipeAnywhereToChangeSong) { if (PreferenceUtil.swipeAnywhereToChangeSong) {
SwipeDetector( SwipeDetector(
requireContext(), requireContext(),
@ -338,8 +376,8 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
context, context,
object : GestureDetector.SimpleOnGestureListener() { object : GestureDetector.SimpleOnGestureListener() {
override fun onScroll( override fun onScroll(
e1: MotionEvent?, e1: MotionEvent,
e2: MotionEvent?, e2: MotionEvent,
distanceX: Float, distanceX: Float,
distanceY: Float, distanceY: Float,
): Boolean { ): Boolean {
@ -349,6 +387,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
view.parent.requestDisallowInterceptTouchEvent(true) view.parent.requestDisallowInterceptTouchEvent(true)
true true
} }
else -> { else -> {
false false
} }
@ -357,7 +396,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
}) })
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View, event: MotionEvent?): Boolean { override fun onTouch(v: View, event: MotionEvent): Boolean {
viewPager?.dispatchTouchEvent(event) viewPager?.dispatchTouchEvent(event)
return flingPlayBackController.onTouchEvent(event) return flingPlayBackController.onTouchEvent(event)
} }
@ -386,9 +425,7 @@ fun goToArtist(activity: Activity) {
findNavController(R.id.fragment_container).navigate( findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment, R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to song.artistId), bundleOf(EXTRA_ARTIST_ID to song.artistId)
null,
null
) )
} }
} }
@ -407,9 +444,7 @@ fun goToAlbum(activity: Activity) {
findNavController(R.id.fragment_container).navigate( findNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment, R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to song.albumId), bundleOf(EXTRA_ALBUM_ID to song.albumId)
null,
null
) )
} }
} }
@ -426,8 +461,7 @@ fun goToLyrics(activity: Activity) {
findNavController(R.id.fragment_container).navigate( findNavController(R.id.fragment_container).navigate(
R.id.lyrics_fragment, R.id.lyrics_fragment,
null, null,
navOptions { launchSingleTop = true }, navOptions { launchSingleTop = true }
null
) )
} }
} }

View file

@ -19,6 +19,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.transition.TransitionManager import androidx.transition.TransitionManager
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.logD
import com.google.android.material.transition.MaterialFade import com.google.android.material.transition.MaterialFade
abstract class AbsRecyclerViewCustomGridSizeFragment<A : RecyclerView.Adapter<*>, LM : RecyclerView.LayoutManager> : abstract class AbsRecyclerViewCustomGridSizeFragment<A : RecyclerView.Adapter<*>, LM : RecyclerView.LayoutManager> :
@ -73,7 +74,7 @@ abstract class AbsRecyclerViewCustomGridSizeFragment<A : RecyclerView.Adapter<*>
fun setAndSaveSortOrder(sortOrder: String) { fun setAndSaveSortOrder(sortOrder: String) {
this.sortOrder = sortOrder this.sortOrder = sortOrder
println(sortOrder) logD(sortOrder)
saveSortOrder(sortOrder) saveSortOrder(sortOrder)
setSortOrder(sortOrder) setSortOrder(sortOrder)
} }

View file

@ -27,12 +27,12 @@ import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.common.ATHToolbarActivity import code.name.monkey.appthemehelper.common.ATHToolbarActivity
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.databinding.FragmentMainRecyclerBinding import code.name.monkey.retromusic.databinding.FragmentMainRecyclerBinding
import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog
import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog
import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.dip import code.name.monkey.retromusic.extensions.dip
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.IScrollHelper import code.name.monkey.retromusic.interfaces.IScrollHelper
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ThemedFastScroller.create import code.name.monkey.retromusic.util.ThemedFastScroller.create
@ -61,6 +61,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
mainActivity.supportActionBar?.title = null mainActivity.supportActionBar?.title = null
initLayoutManager() initLayoutManager()
initAdapter() initAdapter()
checkForMargins()
setUpRecyclerView() setUpRecyclerView()
setupToolbar() setupToolbar()
binding.shuffleButton.fitsSystemWindows = PreferenceUtil.isFullScreenMode binding.shuffleButton.fitsSystemWindows = PreferenceUtil.isFullScreenMode
@ -118,7 +119,6 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
adapter = this@AbsRecyclerViewFragment.adapter adapter = this@AbsRecyclerViewFragment.adapter
create(this) create(this)
} }
checkForPadding()
} }
protected open fun createFastScroller(recyclerView: RecyclerView): FastScroller { protected open fun createFastScroller(recyclerView: RecyclerView): FastScroller {
@ -131,7 +131,6 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
override fun onChanged() { override fun onChanged() {
super.onChanged() super.onChanged()
checkIsEmpty() checkIsEmpty()
checkForPadding()
} }
}) })
} }
@ -148,16 +147,12 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
binding.empty.isVisible = adapter!!.itemCount == 0 binding.empty.isVisible = adapter!!.itemCount == 0
} }
private fun checkForPadding() { private fun checkForMargins() {
val itemCount: Int = adapter?.itemCount ?: 0 if (mainActivity.isBottomNavVisible) {
binding.recyclerView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
binding.recyclerView.updatePadding( bottomMargin = dip(R.dimen.bottom_nav_height)
bottom = if (itemCount > 0 && MusicPlayerRemote.playingQueue.isNotEmpty()) {
dip(R.dimen.mini_player_height_expanded)
} else {
dip(R.dimen.bottom_nav_height)
} }
) }
} }
private fun initLayoutManager() { private fun initLayoutManager() {
@ -169,16 +164,6 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
@NonNull @NonNull
protected abstract fun createAdapter(): A protected abstract fun createAdapter(): A
override fun onQueueChanged() {
super.onQueueChanged()
checkForPadding()
}
override fun onServiceConnected() {
super.onServiceConnected()
checkForPadding()
}
protected fun invalidateLayoutManager() { protected fun invalidateLayoutManager() {
initLayoutManager() initLayoutManager()
binding.recyclerView.layoutManager = layoutManager binding.recyclerView.layoutManager = layoutManager
@ -216,7 +201,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
override fun onMenuItemSelected(item: MenuItem): Boolean { override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.action_settings -> findNavController().navigate( R.id.action_settings -> findNavController().navigate(
R.id.settingsActivity, R.id.settings_fragment,
null, null,
navOptions navOptions
) )
@ -232,8 +217,18 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
return false return false
} }
override fun onResume() {
super.onResume()
checkForMargins()
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null
} }
override fun onPause() {
super.onPause()
(adapter as? AbsMultiSelectAdapter<*, *>)?.actionMode?.finish()
}
} }

View file

@ -21,11 +21,15 @@ import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.Toolbar
import androidx.core.os.BundleCompat
import androidx.core.text.parseAsHtml import androidx.core.text.parseAsHtml
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.loader.app.LoaderManager import androidx.loader.app.LoaderManager
import androidx.loader.content.Loader import androidx.loader.content.Loader
@ -42,32 +46,29 @@ import code.name.monkey.retromusic.adapter.Storage
import code.name.monkey.retromusic.adapter.StorageAdapter import code.name.monkey.retromusic.adapter.StorageAdapter
import code.name.monkey.retromusic.adapter.StorageClickListener import code.name.monkey.retromusic.adapter.StorageClickListener
import code.name.monkey.retromusic.databinding.FragmentFolderBinding import code.name.monkey.retromusic.databinding.FragmentFolderBinding
import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.extensions.dip
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.extensions.textColorPrimary
import code.name.monkey.retromusic.extensions.textColorSecondary
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote.openQueue import code.name.monkey.retromusic.helper.MusicPlayerRemote.openQueue
import code.name.monkey.retromusic.helper.MusicPlayerRemote.playingQueue import code.name.monkey.retromusic.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.ICabCallback
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.interfaces.ICallbacks import code.name.monkey.retromusic.interfaces.ICallbacks
import code.name.monkey.retromusic.interfaces.IMainActivityFragmentCallbacks import code.name.monkey.retromusic.interfaces.IMainActivityFragmentCallbacks
import code.name.monkey.retromusic.interfaces.IScrollHelper
import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener
import code.name.monkey.retromusic.misc.WrappedAsyncTaskLoader import code.name.monkey.retromusic.misc.WrappedAsyncTaskLoader
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.providers.BlacklistStore import code.name.monkey.retromusic.providers.BlacklistStore
import code.name.monkey.retromusic.util.FileUtil import code.name.monkey.retromusic.util.FileUtil
import code.name.monkey.retromusic.util.PreferenceUtil.startDirectory import code.name.monkey.retromusic.util.PreferenceUtil.startDirectory
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.ThemedFastScroller.create import code.name.monkey.retromusic.util.ThemedFastScroller.create
import code.name.monkey.retromusic.util.getExternalStorageDirectory import code.name.monkey.retromusic.util.getExternalStorageDirectory
import code.name.monkey.retromusic.util.getExternalStoragePublicDirectory import code.name.monkey.retromusic.util.getExternalStoragePublicDirectory
import code.name.monkey.retromusic.views.BreadCrumbLayout
import code.name.monkey.retromusic.views.BreadCrumbLayout.Crumb import code.name.monkey.retromusic.views.BreadCrumbLayout.Crumb
import code.name.monkey.retromusic.views.BreadCrumbLayout.SelectionCallback import code.name.monkey.retromusic.views.BreadCrumbLayout.SelectionCallback
import com.afollestad.materialcab.attached.AttachedCab
import com.afollestad.materialcab.attached.destroy
import com.afollestad.materialcab.attached.isActive
import com.afollestad.materialcab.createCab
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.android.material.transition.MaterialFadeThrough import com.google.android.material.transition.MaterialFadeThrough
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -77,16 +78,19 @@ import java.io.File
import java.io.FileFilter import java.io.FileFilter
import java.io.IOException import java.io.IOException
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.Collections
import java.util.LinkedList
class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder), class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
IMainActivityFragmentCallbacks, ICabHolder, SelectionCallback, ICallbacks, IMainActivityFragmentCallbacks, SelectionCallback, ICallbacks,
LoaderManager.LoaderCallbacks<List<File>>, StorageClickListener { LoaderManager.LoaderCallbacks<List<File>>, StorageClickListener, IScrollHelper {
private var _binding: FragmentFolderBinding? = null private var _binding: FragmentFolderBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
val toolbar: Toolbar get() = binding.appBarLayout.toolbar
private var adapter: SongFileAdapter? = null private var adapter: SongFileAdapter? = null
private var storageAdapter: StorageAdapter? = null private var storageAdapter: StorageAdapter? = null
private var cab: AttachedCab? = null
private val fileComparator = Comparator { lhs: File, rhs: File -> private val fileComparator = Comparator { lhs: File, rhs: File ->
if (lhs.isDirectory && !rhs.isDirectory) { if (lhs.isDirectory && !rhs.isDirectory) {
return@Comparator -1 return@Comparator -1
@ -99,14 +103,16 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
private var storageItems = ArrayList<Storage>() private var storageItems = ArrayList<Storage>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentFolderBinding.bind(view) _binding = FragmentFolderBinding.bind(view)
mainActivity.addMusicServiceEventListener(libraryViewModel) mainActivity.addMusicServiceEventListener(libraryViewModel)
mainActivity.setSupportActionBar(binding.toolbar) mainActivity.setSupportActionBar(toolbar)
mainActivity.supportActionBar?.title = null mainActivity.supportActionBar?.title = null
enterTransition = MaterialFadeThrough() enterTransition = MaterialFadeThrough()
reenterTransition = MaterialFadeThrough() reenterTransition = MaterialFadeThrough()
setUpBreadCrumbs() setUpBreadCrumbs()
checkForMargins()
setUpRecyclerView() setUpRecyclerView()
setUpAdapter() setUpAdapter()
setUpTitle() setUpTitle()
@ -116,24 +122,10 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
if (!handleBackPress()) { if (!handleBackPress()) {
remove() remove()
requireActivity().onBackPressed() requireActivity().onBackPressedDispatcher.onBackPressed()
} }
} }
}) })
binding.toolbarContainer.drawNextToNavbar()
binding.appBarLayout.statusBarForeground =
MaterialShapeDrawable.createWithElevationOverlay(requireContext())
}
private fun setUpTitle() {
binding.toolbar.setNavigationOnClickListener {
findNavController().navigate(R.id.action_search, null, navOptions)
}
binding.appNameText.text = resources.getString(R.string.folders)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState == null) { if (savedInstanceState == null) {
switchToFileAdapter() switchToFileAdapter()
setCrumb( setCrumb(
@ -143,24 +135,38 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
true true
) )
} else { } else {
binding.breadCrumbs.restoreFromStateWrapper(savedInstanceState.getParcelable(CRUMBS)) binding.breadCrumbs.restoreFromStateWrapper(
BundleCompat.getParcelable(
savedInstanceState,
CRUMBS,
BreadCrumbLayout.SavedStateWrapper::class.java
)
)
LoaderManager.getInstance(this).initLoader(LOADER_ID, null, this) LoaderManager.getInstance(this).initLoader(LOADER_ID, null, this)
} }
} }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
if (_binding != null) {
outState.putParcelable(CRUMBS, binding.breadCrumbs.stateWrapper)
}
}
private fun setUpTitle() {
toolbar.setNavigationOnClickListener {
findNavController().navigate(R.id.action_search, null, navOptions)
}
binding.appBarLayout.title = resources.getString(R.string.folders)
}
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
saveScrollPosition() saveScrollPosition()
if (cab.isActive()) { adapter?.actionMode?.finish()
cab.destroy()
}
} }
override fun handleBackPress(): Boolean { override fun handleBackPress(): Boolean {
if (cab != null && cab!!.isActive()) {
cab?.destroy()
return true
}
if (binding.breadCrumbs.popHistory()) { if (binding.breadCrumbs.popHistory()) {
setCrumb(binding.breadCrumbs.lastHistory(), false) setCrumb(binding.breadCrumbs.lastHistory(), false)
return true return true
@ -186,7 +192,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
listSongs( listSongs(
requireContext(), requireContext(),
toList(file), listOf(file),
AUDIO_FILE_FILTER, AUDIO_FILE_FILTER,
fileComparator fileComparator
) { songs -> ) { songs ->
@ -199,10 +205,12 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
} }
return@setOnMenuItemClickListener true return@setOnMenuItemClickListener true
} }
R.id.action_add_to_blacklist -> { R.id.action_add_to_blacklist -> {
BlacklistStore.getInstance(requireContext()).addPath(file) BlacklistStore.getInstance(requireContext()).addPath(file)
return@setOnMenuItemClickListener true return@setOnMenuItemClickListener true
} }
R.id.action_set_as_start_directory -> { R.id.action_set_as_start_directory -> {
startDirectory = file startDirectory = file
showToast( showToast(
@ -210,6 +218,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
) )
return@setOnMenuItemClickListener true return@setOnMenuItemClickListener true
} }
R.id.action_scan -> { R.id.action_scan -> {
lifecycleScope.launch { lifecycleScope.launch {
listPaths(file, AUDIO_FILE_FILTER) { paths -> scanPaths(paths) } listPaths(file, AUDIO_FILE_FILTER) { paths -> scanPaths(paths) }
@ -227,19 +236,21 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
listSongs( listSongs(
requireContext(), requireContext(),
toList(file), listOf(file),
AUDIO_FILE_FILTER, AUDIO_FILE_FILTER,
fileComparator fileComparator
) { songs -> ) { songs ->
if (songs.isNotEmpty()) { if (songs.isNotEmpty()) {
SongsMenuHelper.handleMenuClick( val song = songs.first()
requireActivity(), songs, itemId SongMenuHelper.handleMenuClick(
requireActivity(), song, itemId
) )
} }
} }
} }
return@setOnMenuItemClickListener true return@setOnMenuItemClickListener true
} }
R.id.action_scan -> { R.id.action_scan -> {
lifecycleScope.launch { lifecycleScope.launch {
listPaths(file, AUDIO_FILE_FILTER) { paths -> scanPaths(paths) } listPaths(file, AUDIO_FILE_FILTER) { paths -> scanPaths(paths) }
@ -265,7 +276,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
listSongs( listSongs(
requireContext(), requireContext(),
toList(mFile.parentFile), listOf(mFile.parentFile),
fileFilter, fileFilter,
fileComparator fileComparator
) { songs -> ) { songs ->
@ -333,7 +344,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
} }
override fun onPrepareMenu(menu: Menu) { override fun onPrepareMenu(menu: Menu) {
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), binding.toolbar) ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), toolbar)
} }
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
@ -347,8 +358,8 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
menu.removeItem(R.id.action_layout_type) menu.removeItem(R.id.action_layout_type)
menu.removeItem(R.id.action_sort_order) menu.removeItem(R.id.action_sort_order)
ToolbarContentTintHelper.handleOnCreateOptionsMenu( ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(), binding.toolbar, menu, ATHToolbarActivity.getToolbarBackgroundColor( requireContext(), toolbar, menu, ATHToolbarActivity.getToolbarBackgroundColor(
binding.toolbar toolbar
) )
) )
} }
@ -364,6 +375,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
) )
return true return true
} }
R.id.action_scan -> { R.id.action_scan -> {
val crumb = activeCrumb val crumb = activeCrumb
if (crumb != null) { if (crumb != null) {
@ -373,9 +385,10 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
} }
return true return true
} }
R.id.action_settings -> { R.id.action_settings -> {
findNavController().navigate( findNavController().navigate(
R.id.settingsActivity, R.id.settings_fragment,
null, null,
navOptions navOptions
) )
@ -385,41 +398,16 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
return false return false
} }
override fun onQueueChanged() { override fun onResume() {
super.onQueueChanged() super.onResume()
checkForPadding() checkForMargins()
} }
override fun onServiceConnected() { private fun checkForMargins() {
super.onServiceConnected() if (mainActivity.isBottomNavVisible) {
checkForPadding() binding.recyclerView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
} bottomMargin = dip(R.dimen.bottom_nav_height)
override fun openCab(menuRes: Int, callback: ICabCallback): AttachedCab {
if (cab != null && cab!!.isActive()) {
cab?.destroy()
}
cab = createCab(R.id.toolbar_container) {
menu(menuRes)
closeDrawable(R.drawable.ic_close)
backgroundColor(literal = RetroColorUtil.shiftBackgroundColor(surfaceColor()))
slideDown()
onCreate { cab, menu -> callback.onCabCreated(cab, menu) }
onSelection {
callback.onCabItemClicked(it)
} }
onDestroy { callback.onCabFinished(it) }
}
return cab as AttachedCab
}
private fun checkForPadding() {
val count = adapter?.itemCount ?: 0
if (_binding != null) {
binding.recyclerView.updatePadding(
bottom = if (count > 0 && playingQueue.isNotEmpty()) dip(R.dimen.mini_player_height_expanded)
else dip(R.dimen.mini_player_height)
)
} }
} }
@ -440,13 +428,11 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
} }
private fun saveScrollPosition() { private fun saveScrollPosition() {
val crumb = activeCrumb activeCrumb?.scrollPosition =
if (crumb != null) { (binding.recyclerView.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
crumb.scrollPosition =
(binding.recyclerView.layoutManager as LinearLayoutManager?)!!.findFirstVisibleItemPosition()
}
} }
private fun scanPaths(toBeScanned: Array<String?>) { private fun scanPaths(toBeScanned: Array<String?>) {
if (activity == null) { if (activity == null) {
return return
@ -496,24 +482,18 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
} }
private fun setUpRecyclerView() { private fun setUpRecyclerView() {
binding.recyclerView.layoutManager = LinearLayoutManager(activity) binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
create( create(
binding.recyclerView binding.recyclerView
) )
} }
private fun toList(file: File): ArrayList<File> {
val files = ArrayList<File>(1)
files.add(file)
return files
}
private fun updateAdapter(files: List<File>) { private fun updateAdapter(files: List<File>) {
adapter?.swapDataSet(files) adapter?.swapDataSet(files)
val crumb = activeCrumb val crumb = activeCrumb
if (crumb != null) { if (crumb != null) {
(binding.recyclerView.layoutManager as LinearLayoutManager?) (binding.recyclerView.layoutManager as LinearLayoutManager)
?.scrollToPositionWithOffset(crumb.scrollPosition, 0) .scrollToPositionWithOffset(crumb.scrollPosition, 0)
} }
} }
@ -525,7 +505,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
private suspend fun listPaths( private suspend fun listPaths(
file: File, file: File,
fileFilter: FileFilter, fileFilter: FileFilter,
doOnPathListed: (paths: Array<String?>) -> Unit doOnPathListed: (paths: Array<String?>) -> Unit,
) { ) {
val paths = try { val paths = try {
val paths: Array<String?> val paths: Array<String?>
@ -577,12 +557,12 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
} }
} }
suspend fun listSongs( private suspend fun listSongs(
context: Context, context: Context,
files: List<File>, files: List<File?>,
fileFilter: FileFilter, fileFilter: FileFilter,
fileComparator: Comparator<File>, fileComparator: Comparator<File>,
doOnSongsListed: (songs: List<Song>) -> Unit doOnSongsListed: (songs: List<Song>) -> Unit,
) { ) {
val songs = try { val songs = try {
val fileList = FileUtil.listFilesDeep(files, fileFilter) val fileList = FileUtil.listFilesDeep(files, fileFilter)
@ -607,14 +587,18 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
) )
} }
override fun scrollToTop() {
binding.recyclerView.scrollToPosition(0)
binding.appBarLayout.setExpanded(true, true)
}
private fun switchToFileAdapter() { private fun switchToFileAdapter() {
adapter = SongFileAdapter(mainActivity, LinkedList(), R.layout.item_list, this, this) adapter = SongFileAdapter(mainActivity, LinkedList(), R.layout.item_list, this)
adapter!!.registerAdapterDataObserver( adapter!!.registerAdapterDataObserver(
object : RecyclerView.AdapterDataObserver() { object : RecyclerView.AdapterDataObserver() {
override fun onChanged() { override fun onChanged() {
super.onChanged() super.onChanged()
checkIsEmpty() checkIsEmpty()
checkForPadding()
} }
}) })
binding.recyclerView.adapter = adapter binding.recyclerView.adapter = adapter

View file

@ -71,7 +71,7 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
} }
private fun setupRecyclerView() { private fun setupRecyclerView() {
songAdapter = SongAdapter(requireActivity(), ArrayList(), R.layout.item_list, null) songAdapter = SongAdapter(requireActivity(), ArrayList(), R.layout.item_list)
binding.recyclerView.apply { binding.recyclerView.apply {
itemAnimator = DefaultItemAnimator() itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(requireContext()) layoutManager = LinearLayoutManager(requireContext())

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