Compare commits

..

No commits in common. "dev" and "v5.8.5" have entirely different histories.
dev ... v5.8.5

758 changed files with 13433 additions and 14392 deletions

4
.gitattributes vendored
View file

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

View file

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

View file

@ -8,21 +8,24 @@ Material Design music player for Android music lovers
alt="Get it on F-Droid" alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/io.github.muntashirakon.Music/) height="80">](https://f-droid.org/en/packages/io.github.muntashirakon.Music/)
[<img src="https://camo.githubusercontent.com/70bffd8873ab81e1bb0bccc44e488c3a989e3bd5/68747470733a2f2f692e6962622e636f2f71306d6463345a2f6765742d69742d6f6e2d6769746875622e706e67"
alt="Get it on GitHub"
height="80">](https://github.com/MuntashirAkon/Metro/releases)
## 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="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"/> | | <img src="screenshots/home_light.jpg" width="200"/> | <img src="screenshots/home_dark.jpg" width="200"/> | <img src="screenshots/home_black.jpg" width="200"/> |
|:---:|:---:|:---:| |:---:|:---:|:---:|
|Clearly white| Kinda dark | Just black| |Clearly white| Kinda dark | Just black|
### Player screen ### Player screen
| <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"/>| | <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"/>|
|:---:|:---:|:---:|:---:|:---:| |:---:|:---:|:---:|:---:|:---:|
| Home | Songs | Albums | Artists | Settings | | Home | Songs | Albums | Artists | Settings |
@ -37,7 +40,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="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"/> | | <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"/> |
|:-----: |:-----: |:-----: |:-----: |:-----: | |:-----: |:-----: |:-----: |:-----: |:-----: |
| Normal | Fit | Flat | Color | Material | | Normal | Fit | Flat | Color | Material |

View file

@ -1,30 +1,29 @@
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 33 compileSdk 32
namespace "code.name.monkey.retromusic" buildToolsVersion = '30.0.3'
defaultConfig { defaultConfig {
minSdk 21 minSdk 21
targetSdk 33 targetSdk 32
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
applicationId 'io.github.muntashirakon.Music' applicationId 'io.github.muntashirakon.Music'
versionCode 10603 versionCode 10580
versionName '6.1.0' versionName '5.8.5'
multiDexEnabled true multiDexEnabled true
} }
buildTypes { buildTypes {
release { release {
shrinkResources true minifyEnabled false
minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }
debug { debug {
applicationIdSuffix '.debug' applicationIdSuffix '.debug'
@ -41,8 +40,8 @@ android {
} }
} }
lint { lint {
abortOnError true abortOnError false
warning 'ImpliedQuantity', 'Instantiatable', 'MissingQuantity', 'MissingTranslation' disable 'MissingTranslation', 'InvalidPackage'
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
@ -51,11 +50,8 @@ android {
kotlinOptions { kotlinOptions {
jvmTarget = "1.8" jvmTarget = "1.8"
} }
dependenciesInfo {
includeInApk = false configurations.all {
includeInBundle = false
}
configurations.configureEach {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9' resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
} }
} }
@ -64,37 +60,35 @@ 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.6.0' implementation 'androidx.annotation:annotation:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.recyclerview:recyclerview:1.3.0' implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation "androidx.preference:preference-ktx:$preference_version" implementation "androidx.preference:preference-ktx:$preference_version"
implementation "androidx.core:core-ktx:$core_version" implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.palette:palette-ktx:1.0.0' implementation 'androidx.palette:palette-ktx:1.0.0'
implementation 'androidx.mediarouter:mediarouter:1.3.1' implementation "androidx.media:media:1.6.0"
implementation "androidx.navigation:navigation-runtime-ktx:$navigation_version" implementation "androidx.navigation:navigation-runtime-ktx:$navigation_version"
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.5.1' def room_version = '2.4.2'
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"
ksp "androidx.room:room-compiler:$room_version" kapt "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" implementation "androidx.core:core-splashscreen:1.0.0-beta02"
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"
@ -103,15 +97,19 @@ dependencies {
implementation 'com.afollestad:material-cab:2.0.1' implementation 'com.afollestad:material-cab:2.0.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
def koin_version = '3.4.0' def kotlin_coroutines_version = '1.6.1'
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.15.1' def glide_version = '4.13.2'
implementation "com.github.bumptech.glide:glide:$glide_version" implementation "com.github.bumptech.glide:glide:$glide_version"
ksp "com.github.bumptech.glide:ksp:$glide_version" kapt "com.github.bumptech.glide:compiler:$glide_version"
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0' implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
@ -126,7 +124,8 @@ 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.2.0' implementation 'me.zhanghai.android.fastscroll:library:1.1.8'
implementation 'cat.ereza:customactivityoncrash:2.4.0' implementation 'cat.ereza:customactivityoncrash:2.3.0'
implementation 'me.tankery.lib:circularSeekBar:1.4.2' implementation 'me.tankery.lib:circularSeekBar:1.3.2'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
} }

View file

@ -66,6 +66,6 @@
-keep class * extends androidx.fragment.app.Fragment{} -keep class * extends androidx.fragment.app.Fragment{}
-keepnames class * extends android.os.Parcelable -keepnames class * extends android.os.Parcelable
-keepnames class * extends java.io.Serializable -keepnames class * extends java.io.Serializable
-keep class code.name.monkey.retromusic.network.model.** { *; } -keep class io.github.muntashirakon.music.network.model.** { *; }
-keep class code.name.monkey.retromusic.model.** { *; } -keep class io.github.muntashirakon.music.model.** { *; }
-keep class com.google.android.material.bottomsheet.** { *; } -keep class com.google.android.material.bottomsheet.** { *; }

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="code.name.monkey.retromusic" package="io.github.muntashirakon.music"
android:installLocation="auto"> android:installLocation="auto">
<uses-permission <uses-permission
@ -11,47 +11,36 @@
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" /> android:maxSdkVersion="28" />
<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.USE_FULL_SCREEN_INTENT" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission
android:name="android.permission.BLUETOOTH_CONNECT"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<application <application
android:name=".App" android:name=".App"
android:allowBackup="@bool/allowBackup" android:allowBackup="@bool/allowBackup"
android:appCategory="audio"
android:configChanges="locale|layoutDirection" android:configChanges="locale|layoutDirection"
android:enableOnBackInvokedCallback="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:localeConfig="@xml/locales_config"
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="UnusedAttribute"> tools:ignore="AllowBackup,GoogleAppIndexingWarning"
tools:targetApi="q">
<activity <activity
android:name=".activities.MainActivity" android:name=".activities.MainActivity"
android:exported="true" android:exported="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/Theme.RetroMusic.SplashScreen"> android:theme="@style/SplashTheme">
<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" />
@ -62,6 +51,7 @@
</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>
@ -121,6 +111,7 @@
<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=".activities.SettingsActivity" />
<activity android:name=".activities.tageditor.AlbumTagEditorActivity" /> <activity android:name=".activities.tageditor.AlbumTagEditorActivity" />
<activity android:name=".activities.tageditor.SongTagEditorActivity" /> <activity android:name=".activities.tageditor.SongTagEditorActivity" />
<activity android:name=".activities.LicenseActivity" /> <activity android:name=".activities.LicenseActivity" />
@ -128,11 +119,8 @@
<activity android:name=".activities.ShareInstagramStory" /> <activity android:name=".activities.ShareInstagramStory" />
<activity android:name=".activities.DriveModeActivity" /> <activity android:name=".activities.DriveModeActivity" />
<activity android:name=".activities.PermissionActivity" /> <activity android:name=".activities.PermissionActivity" />
<activity <activity android:name=".activities.LockScreenActivity" />
android:name=".activities.LockScreenActivity" <activity android:name=".activities.saf.SAFRequestActivity" />
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:showOnLockScreen="true" />
<activity <activity
android:name=".fragments.backup.RestoreActivity" android:name=".fragments.backup.RestoreActivity"
android:excludeFromRecents="false" android:excludeFromRecents="false"
@ -187,6 +175,16 @@
</intent-filter> </intent-filter>
</activity> </activity>
<provider
android:name=".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}"
@ -198,7 +196,7 @@
</provider> </provider>
<receiver <receiver
android:name=".service.MediaButtonIntentReceiver" android:name="androidx.media.session.MediaButtonReceiver"
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" />
@ -302,12 +300,16 @@
<service <service
android:name=".service.MusicService" android:name=".service.MusicService"
android:enabled="true"
android:exported="true" android:exported="true"
android:foregroundServiceType="mediaPlayback" android:foregroundServiceType="mediaPlayback"
android:label="@string/app_name"> android:label="@string/app_name">
<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
@ -328,16 +330,6 @@
<meta-data <meta-data
android:name="com.google.android.gms.car.notification.SmallIcon" android:name="com.google.android.gms.car.notification.SmallIcon"
android:resource="@drawable/ic_notification" /> android:resource="@drawable/ic_notification" />
<!-- For auto-storage of locale on Android 12 and lower -->
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
</application> </application>
<!-- <!--

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -62,81 +62,6 @@
</head> </head>
<body> <body>
<div>
<h5>March 30, 2023</h5>
<h2>v6.1.0</h2>
<h3>What's New</h3>
<ul>
<li>App now targets Android 13, support for Granular media permissions, Photo picker, Per-app language preferences & Predictive back gesture</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fixed playlist reordering crash</li>
<li>Other minor bugs fixes and improvements</li>
</ul>
</div>
<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

@ -1,204 +0,0 @@
package code.name.monkey.retromusic.activities.tageditor
import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.media.MediaScannerConnection
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener
import code.name.monkey.retromusic.model.AudioTagInfo
import code.name.monkey.retromusic.util.MusicUtil.createAlbumArtFile
import code.name.monkey.retromusic.util.MusicUtil.deleteAlbumArt
import code.name.monkey.retromusic.util.MusicUtil.insertAlbumArt
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.audio.exceptions.CannotReadException
import org.jaudiotagger.audio.exceptions.CannotWriteException
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException
import org.jaudiotagger.tag.FieldDataInvalidException
import org.jaudiotagger.tag.TagException
import org.jaudiotagger.tag.images.AndroidArtwork
import org.jaudiotagger.tag.images.Artwork
import java.io.File
import java.io.IOException
class TagWriter {
companion object {
suspend fun scan(context: Context, toBeScanned: List<String?>?) {
if (toBeScanned.isNullOrEmpty()) {
Log.i("scan", "scan: Empty")
context.showToast("Scan file from folder")
return
}
MediaScannerConnection.scanFile(
context,
toBeScanned.toTypedArray(),
null,
withContext(Dispatchers.Main) {
if (context is Activity) UpdateToastMediaScannerCompletionListener(
context, toBeScanned
) else null
}
)
}
suspend fun writeTagsToFiles(context: Context, info: AudioTagInfo) {
withContext(Dispatchers.IO) {
var artwork: Artwork? = null
var albumArtFile: File? = null
if (info.artworkInfo?.artwork != null) {
try {
albumArtFile = createAlbumArtFile(context).canonicalFile
info.artworkInfo.artwork.compress(
Bitmap.CompressFormat.JPEG,
100,
albumArtFile.outputStream()
)
artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
} catch (e: IOException) {
e.printStackTrace()
}
}
var wroteArtwork = false
var deletedArtwork = false
for (filePath in info.filePaths!!) {
try {
val audioFile = AudioFileIO.read(File(filePath))
val tag = audioFile.tagOrCreateAndSetDefault
if (info.fieldKeyValueMap != null) {
for ((key, value) in info.fieldKeyValueMap) {
try {
tag.setField(key, value)
} catch (e: FieldDataInvalidException) {
withContext(Dispatchers.Main) {
context.showToast(R.string.could_not_write_tags_to_file)
}
return@withContext listOf<File>()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
if (info.artworkInfo != null) {
if (info.artworkInfo.artwork == null) {
tag.deleteArtworkField()
deletedArtwork = true
} else if (artwork != null) {
tag.deleteArtworkField()
tag.setField(artwork)
wroteArtwork = true
}
}
audioFile.commit()
} catch (e: CannotReadException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: CannotWriteException) {
e.printStackTrace()
} catch (e: TagException) {
e.printStackTrace()
} catch (e: ReadOnlyFileException) {
e.printStackTrace()
} catch (e: InvalidAudioFrameException) {
e.printStackTrace()
}
}
if (wroteArtwork) {
insertAlbumArt(context, info.artworkInfo!!.albumId, albumArtFile!!.path)
} else if (deletedArtwork) {
deleteAlbumArt(context, info.artworkInfo!!.albumId)
}
scan(context, info.filePaths)
}
}
@RequiresApi(Build.VERSION_CODES.R)
suspend fun writeTagsToFilesR(context: Context, info: AudioTagInfo): List<File> =
withContext(Dispatchers.IO) {
val cacheFiles = mutableListOf<File>()
var artwork: Artwork? = null
var albumArtFile: File? = null
if (info.artworkInfo?.artwork != null) {
try {
albumArtFile = createAlbumArtFile(context).canonicalFile
info.artworkInfo.artwork.compress(
Bitmap.CompressFormat.JPEG,
100,
albumArtFile.outputStream()
)
artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
} catch (e: IOException) {
e.printStackTrace()
}
}
var wroteArtwork = false
var deletedArtwork = false
for (filePath in info.filePaths!!) {
try {
val originFile = File(filePath)
val cacheFile = File(context.cacheDir, originFile.name)
cacheFiles.add(cacheFile)
originFile.inputStream().use { input ->
cacheFile.outputStream().use { output ->
input.copyTo(output)
}
}
val audioFile = AudioFileIO.read(cacheFile)
val tag = audioFile.tagOrCreateAndSetDefault
if (info.fieldKeyValueMap != null) {
for ((key, value) in info.fieldKeyValueMap) {
try {
tag.setField(key, value)
} catch (e: FieldDataInvalidException) {
withContext(Dispatchers.Main) {
context.showToast(R.string.could_not_write_tags_to_file)
}
return@withContext listOf<File>()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
if (info.artworkInfo != null) {
if (info.artworkInfo.artwork == null) {
tag.deleteArtworkField()
deletedArtwork = true
} else if (artwork != null) {
tag.deleteArtworkField()
tag.setField(artwork)
wroteArtwork = true
}
}
audioFile.commit()
} catch (e: CannotReadException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: CannotWriteException) {
e.printStackTrace()
} catch (e: TagException) {
e.printStackTrace()
} catch (e: ReadOnlyFileException) {
e.printStackTrace()
} catch (e: InvalidAudioFrameException) {
e.printStackTrace()
}
}
if (wroteArtwork) {
insertAlbumArt(context, info.artworkInfo!!.albumId, albumArtFile!!.path)
} else if (deletedArtwork) {
deleteAlbumArt(context, info.artworkInfo!!.albumId)
}
cacheFiles
}
}
}

View file

@ -1,131 +0,0 @@
package code.name.monkey.retromusic.adapter.base
import android.graphics.Color
import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
import androidx.activity.OnBackPressedCallback
import androidx.annotation.MenuRes
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.NumberRollViewBinding
import code.name.monkey.retromusic.views.NumberRollView
abstract class AbsMultiSelectAdapter<V : RecyclerView.ViewHolder?, I>(
open val activity: FragmentActivity, @MenuRes menuRes: Int,
) : RecyclerView.Adapter<V>(), ActionMode.Callback {
var actionMode: ActionMode? = null
private val checked: MutableList<I>
private var menuRes: Int
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
val inflater = mode?.menuInflater
inflater?.inflate(menuRes, menu)
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return false
}
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
if (item?.itemId == R.id.action_multi_select_adapter_check_all) {
checkAll()
} else {
onMultipleItemAction(item!!, ArrayList(checked))
actionMode?.finish()
clearChecked()
}
return true
}
override fun onDestroyActionMode(mode: ActionMode?) {
clearChecked()
activity.window.statusBarColor = when {
VersionUtils.hasMarshmallow() -> Color.TRANSPARENT
else -> Color.BLACK
}
actionMode = null
onBackPressedCallback.remove()
}
private fun checkAll() {
if (actionMode != null) {
checked.clear()
for (i in 0 until itemCount) {
val identifier = getIdentifier(i)
if (identifier != null) {
checked.add(identifier)
}
}
notifyDataSetChanged()
updateCab()
}
}
protected abstract fun getIdentifier(position: Int): I?
protected abstract fun getName(model: I): String?
protected fun isChecked(identifier: I): Boolean {
return checked.contains(identifier)
}
protected val isInQuickSelectMode: Boolean
get() = actionMode != null
protected abstract fun onMultipleItemAction(menuItem: MenuItem, selection: List<I>)
protected fun setMultiSelectMenuRes(@MenuRes menuRes: Int) {
this.menuRes = menuRes
}
protected fun toggleChecked(position: Int): Boolean {
val identifier = getIdentifier(position) ?: return false
if (!checked.remove(identifier)) {
checked.add(identifier)
}
notifyItemChanged(position)
updateCab()
return true
}
private fun clearChecked() {
checked.clear()
notifyDataSetChanged()
}
private fun updateCab() {
if (actionMode == null) {
actionMode = activity.startActionMode(this)?.apply {
customView = NumberRollViewBinding.inflate(activity.layoutInflater).root
}
activity.onBackPressedDispatcher.addCallback(onBackPressedCallback)
}
val size = checked.size
when {
size <= 0 -> {
actionMode?.finish()
}
else -> {
actionMode?.customView?.findViewById<NumberRollView>(R.id.selection_mode_number)
?.setNumber(size, true)
}
}
}
init {
checked = ArrayList()
this.menuRes = menuRes
}
private val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (actionMode != null) {
actionMode?.finish()
remove()
}
}
}
}

View file

@ -1,11 +0,0 @@
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

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

View file

@ -1,79 +0,0 @@
package code.name.monkey.retromusic.fragments
import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import kotlinx.coroutines.*
import kotlin.math.abs
/**
* @param activity, Activity
* @param next, if the button is next, if false then it's considered previous
*/
class MusicSeekSkipTouchListener(val activity: FragmentActivity, val next: Boolean) :
View.OnTouchListener {
private var job: Job? = null
private var counter = 0
private var wasSeeking = false
private var startX = 0f
private var startY = 0f
private val scaledTouchSlop = ViewConfiguration.get(activity).scaledTouchSlop
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
when (event?.actionMasked) {
MotionEvent.ACTION_DOWN -> {
startX = event.x
startY = event.y
job = activity.lifecycleScope.launch(Dispatchers.Default) {
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)
}
withContext(Dispatchers.Main) {
MusicPlayerRemote.seekTo(seekingDuration)
}
counter += 1
}
}
}
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 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

@ -1,88 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package code.name.monkey.retromusic.fragments.settings
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.databinding.FragmentSettingsBinding
import code.name.monkey.retromusic.extensions.findNavController
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.color.ColorCallback
class SettingsFragment : Fragment(R.layout.fragment_settings), ColorCallback {
private var _binding: FragmentSettingsBinding? = null
private val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
_binding = FragmentSettingsBinding.bind(view)
setupToolbar()
}
private fun setupToolbar() {
val navController: NavController = findNavController(R.id.contentFrame)
with (binding.appBarLayout.toolbar) {
setNavigationIcon(R.drawable.ic_arrow_back)
isTitleCentered = false
setNavigationOnClickListener {
requireActivity().onBackPressedDispatcher.onBackPressed()
}
}
navController.addOnDestinationChangedListener { _, _, _ ->
binding.appBarLayout.title =
navController.currentDestination?.let { getStringFromDestination(it) }.toString()
}
}
private fun getStringFromDestination(currentDestination: NavDestination): String {
val idRes = when (currentDestination.id) {
R.id.mainSettingsFragment -> R.string.action_settings
R.id.audioSettings -> R.string.pref_header_audio
R.id.imageSettingFragment -> R.string.pref_header_images
R.id.notificationSettingsFragment -> R.string.notification
R.id.nowPlayingSettingsFragment -> R.string.now_playing
R.id.otherSettingsFragment -> R.string.others
R.id.personalizeSettingsFragment -> R.string.personalize
R.id.themeSettingsFragment -> R.string.general_settings_title
R.id.aboutActivity -> R.string.action_about
R.id.backup_fragment -> R.string.backup_restore_title
else -> R.id.action_settings
}
return getString(idRes)
}
override fun invoke(dialog: MaterialDialog, color: Int) {
ThemeStore.editTheme(requireContext()).accentColor(color).commit()
if (VersionUtils.hasNougatMR())
DynamicShortcutManager(requireContext()).updateDynamicShortcuts()
activity?.recreate()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
val TAG: String = SettingsFragment::class.java.simpleName
}
}

View file

@ -1,30 +0,0 @@
package code.name.monkey.retromusic.glide.playlistPreview
import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.toSongs
import code.name.monkey.retromusic.model.Song
class PlaylistPreview(val playlistWithSongs: PlaylistWithSongs) {
val playlistEntity: PlaylistEntity get() = playlistWithSongs.playlistEntity
val songs: List<Song> get() = playlistWithSongs.songs.toSongs()
override fun equals(other: Any?): Boolean {
println("Glide equals $this $other")
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as PlaylistPreview
if (other.playlistEntity.playListId != playlistEntity.playListId) return false
if (other.songs.size != songs.size) return false
return true
}
override fun hashCode(): Int {
var result = playlistEntity.playListId.hashCode()
result = 31 * result + playlistWithSongs.songs.size
println("Glide $result")
return result
}
}

View file

@ -1,13 +0,0 @@
package code.name.monkey.retromusic.interfaces
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Genre
interface IHomeClickListener {
fun onAlbumClick(album: Album)
fun onArtistClick(artist: Artist)
fun onGenreClick(genre: Genre)
}

View file

@ -1,649 +0,0 @@
/*
* Copyright (C) 2017 wangchenyan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package code.name.monkey.retromusic.lyrics;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Looper;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.Scroller;
import androidx.core.content.ContextCompat;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import code.name.monkey.retromusic.BuildConfig;
import code.name.monkey.retromusic.R;
/**
* 歌词 Created by wcy on 2015/11/9.
*/
@SuppressLint("StaticFieldLeak")
public class LrcView extends View {
private static final long ADJUST_DURATION = 100;
private static final long TIMELINE_KEEP_TIME = 4 * DateUtils.SECOND_IN_MILLIS;
private final List<LrcEntry> mLrcEntryList = new ArrayList<>();
private final TextPaint mLrcPaint = new TextPaint();
private final TextPaint mTimePaint = new TextPaint();
private Paint.FontMetrics mTimeFontMetrics;
private Drawable mPlayDrawable;
private float mDividerHeight;
private long mAnimationDuration;
private int mNormalTextColor;
private float mNormalTextSize;
private int mCurrentTextColor;
private float mCurrentTextSize;
private int mTimelineTextColor;
private int mTimelineColor;
private int mTimeTextColor;
private int mDrawableWidth;
private int mTimeTextWidth;
private String mDefaultLabel;
private float mLrcPadding;
private OnPlayClickListener mOnPlayClickListener;
private ValueAnimator mAnimator;
private GestureDetector mGestureDetector;
private Scroller mScroller;
private float mOffset;
private int mCurrentLine;
private Object mFlag;
private boolean isShowTimeline;
private boolean isTouching;
private boolean isFling;
private int mTextGravity; // 歌词显示位置靠左/居中/靠右
private final Runnable hideTimelineRunnable =
new Runnable() {
@Override
public void run() {
if (hasLrc() && isShowTimeline) {
isShowTimeline = false;
smoothScrollTo(mCurrentLine);
}
}
};
private final GestureDetector.SimpleOnGestureListener mSimpleOnGestureListener =
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
if (hasLrc() && mOnPlayClickListener != null) {
mScroller.forceFinished(true);
removeCallbacks(hideTimelineRunnable);
isTouching = true;
isShowTimeline = true;
invalidate();
return true;
}
return super.onDown(e);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (hasLrc()) {
mOffset -= distanceY;
mOffset = Math.min(mOffset, getOffset(0));
mOffset = Math.max(mOffset, getOffset(mLrcEntryList.size() - 1));
invalidate();
getParent().requestDisallowInterceptTouchEvent(true);
return true;
}
return super.onScroll(e1, e2, distanceX, distanceY);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (hasLrc()) {
mScroller.fling(
0,
(int) mOffset,
0,
(int) velocityY,
0,
0,
(int) getOffset(mLrcEntryList.size() - 1),
(int) getOffset(0));
isFling = true;
return true;
}
return super.onFling(e1, e2, velocityX, velocityY);
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
if (hasLrc()
&& isShowTimeline
&& mPlayDrawable.getBounds().contains((int) e.getX(), (int) e.getY())) {
int centerLine = getCenterLine();
long centerLineTime = mLrcEntryList.get(centerLine).getTime();
// onPlayClick 消费了才更新 UI
if (mOnPlayClickListener != null && mOnPlayClickListener.onPlayClick(centerLineTime)) {
isShowTimeline = false;
removeCallbacks(hideTimelineRunnable);
mCurrentLine = centerLine;
invalidate();
return true;
}
}
return super.onSingleTapConfirmed(e);
}
};
public LrcView(Context context) {
this(context, null);
}
public LrcView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LrcView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.LrcView);
mCurrentTextSize =
ta.getDimension(
R.styleable.LrcView_lrcTextSize, getResources().getDimension(R.dimen.lrc_text_size));
mNormalTextSize =
ta.getDimension(
R.styleable.LrcView_lrcNormalTextSize,
getResources().getDimension(R.dimen.lrc_text_size));
if (mNormalTextSize == 0) {
mNormalTextSize = mCurrentTextSize;
}
mDividerHeight =
ta.getDimension(
R.styleable.LrcView_lrcDividerHeight,
getResources().getDimension(R.dimen.lrc_divider_height));
int defDuration = getResources().getInteger(R.integer.lrc_animation_duration);
mAnimationDuration = ta.getInt(R.styleable.LrcView_lrcAnimationDuration, defDuration);
mAnimationDuration = (mAnimationDuration < 0) ? defDuration : mAnimationDuration;
mNormalTextColor =
ta.getColor(
R.styleable.LrcView_lrcNormalTextColor,
getResources().getColor(R.color.lrc_normal_text_color));
mCurrentTextColor =
ta.getColor(
R.styleable.LrcView_lrcCurrentTextColor,
getResources().getColor(R.color.lrc_current_text_color));
mTimelineTextColor =
ta.getColor(
R.styleable.LrcView_lrcTimelineTextColor,
getResources().getColor(R.color.lrc_timeline_text_color));
mDefaultLabel = ta.getString(R.styleable.LrcView_lrcLabel);
mDefaultLabel =
TextUtils.isEmpty(mDefaultLabel) ? getContext().getString(R.string.empty) : mDefaultLabel;
mLrcPadding = ta.getDimension(R.styleable.LrcView_lrcPadding, 0);
mTimelineColor =
ta.getColor(
R.styleable.LrcView_lrcTimelineColor,
getResources().getColor(R.color.lrc_timeline_color));
float timelineHeight =
ta.getDimension(
R.styleable.LrcView_lrcTimelineHeight,
getResources().getDimension(R.dimen.lrc_timeline_height));
mPlayDrawable = ta.getDrawable(R.styleable.LrcView_lrcPlayDrawable);
mPlayDrawable =
(mPlayDrawable == null)
? ContextCompat.getDrawable(getContext(), R.drawable.ic_play_arrow)
: mPlayDrawable;
mTimeTextColor =
ta.getColor(
R.styleable.LrcView_lrcTimeTextColor,
getResources().getColor(R.color.lrc_time_text_color));
float timeTextSize =
ta.getDimension(
R.styleable.LrcView_lrcTimeTextSize,
getResources().getDimension(R.dimen.lrc_time_text_size));
mTextGravity = ta.getInteger(R.styleable.LrcView_lrcTextGravity, LrcEntry.GRAVITY_CENTER);
ta.recycle();
mDrawableWidth = (int) getResources().getDimension(R.dimen.lrc_drawable_width);
mTimeTextWidth = (int) getResources().getDimension(R.dimen.lrc_time_width);
mLrcPaint.setAntiAlias(true);
mLrcPaint.setTextSize(mCurrentTextSize);
mLrcPaint.setTextAlign(Paint.Align.LEFT);
mTimePaint.setAntiAlias(true);
mTimePaint.setTextSize(timeTextSize);
mTimePaint.setTextAlign(Paint.Align.CENTER);
//noinspection SuspiciousNameCombination
mTimePaint.setStrokeWidth(timelineHeight);
mTimePaint.setStrokeCap(Paint.Cap.ROUND);
mTimeFontMetrics = mTimePaint.getFontMetrics();
mGestureDetector = new GestureDetector(getContext(), mSimpleOnGestureListener);
mGestureDetector.setIsLongpressEnabled(false);
mScroller = new Scroller(getContext());
}
public void setCurrentColor(int currentColor) {
mCurrentTextColor = currentColor;
postInvalidate();
}
public void setTimelineTextColor(int timelineTextColor) {
mTimelineTextColor = timelineTextColor;
postInvalidate();
}
public void setTimelineColor(int timelineColor) {
mTimelineColor = timelineColor;
postInvalidate();
}
public void setTimeTextColor(int timeTextColor) {
mTimeTextColor = timeTextColor;
postInvalidate();
}
public void setDraggable(boolean draggable, OnPlayClickListener onPlayClickListener) {
if (draggable) {
if (onPlayClickListener == null) {
throw new IllegalArgumentException(
"if draggable == true, onPlayClickListener must not be null");
}
mOnPlayClickListener = onPlayClickListener;
} else {
mOnPlayClickListener = null;
}
}
public void setLabel(String label) {
runOnUi(
() -> {
mDefaultLabel = label;
invalidate();
});
}
public void loadLrc(File lrcFile) {
loadLrc(lrcFile, null);
}
public void loadLrc(File mainLrcFile, File secondLrcFile) {
runOnUi(() -> {
reset();
StringBuilder sb = new StringBuilder("file://");
sb.append(mainLrcFile.getPath());
if (secondLrcFile != null) {
sb.append("#").append(secondLrcFile.getPath());
}
String flag = sb.toString();
setFlag(flag);
new AsyncTask<File, Integer, List<LrcEntry>>() {
@Override
protected List<LrcEntry> doInBackground(File... params) {
return LrcUtils.parseLrc(params);
}
@Override
protected void onPostExecute(List<LrcEntry> lrcEntries) {
if (getFlag() == flag) {
onLrcLoaded(lrcEntries);
setFlag(null);
}
}
}.execute(mainLrcFile, secondLrcFile);
});
}
public void loadLrc(String lrcText) {
loadLrc(lrcText, null);
}
public void loadLrc(String mainLrcText, String secondLrcText) {
runOnUi(
() -> {
reset();
StringBuilder sb = new StringBuilder("file://");
sb.append(mainLrcText);
if (secondLrcText != null) {
sb.append("#").append(secondLrcText);
}
String flag = sb.toString();
setFlag(flag);
new AsyncTask<String, Integer, List<LrcEntry>>() {
@Override
protected List<LrcEntry> doInBackground(String... params) {
return LrcUtils.parseLrc(params);
}
@Override
protected void onPostExecute(List<LrcEntry> lrcEntries) {
if (getFlag() == flag) {
onLrcLoaded(lrcEntries);
setFlag(null);
}
}
}.execute(mainLrcText, secondLrcText);
});
}
public boolean hasLrc() {
return !mLrcEntryList.isEmpty();
}
public void updateTime(long time) {
runOnUi(
() -> {
if (!hasLrc()) {
return;
}
int line = findShowLine(time);
if (line != mCurrentLine) {
mCurrentLine = line;
if (!isShowTimeline) {
smoothScrollTo(line);
} else {
invalidate();
}
}
});
}
@Deprecated
public void onDrag(long time) {
updateTime(time);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
initPlayDrawable();
initEntryList();
if (hasLrc()) {
smoothScrollTo(mCurrentLine, 0L);
}
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centerY = getHeight() / 2;
if (!hasLrc()) {
mLrcPaint.setColor(mCurrentTextColor);
@SuppressLint("DrawAllocation")
StaticLayout staticLayout =
new StaticLayout(
mDefaultLabel,
mLrcPaint,
(int) getLrcWidth(),
Layout.Alignment.ALIGN_CENTER,
1f,
0f,
false);
drawText(canvas, staticLayout, centerY);
return;
}
int centerLine = getCenterLine();
if (isShowTimeline) {
mPlayDrawable.draw(canvas);
mTimePaint.setColor(mTimelineColor);
canvas.drawLine(mTimeTextWidth, centerY, getWidth() - mTimeTextWidth, centerY, mTimePaint);
mTimePaint.setColor(mTimeTextColor);
String timeText = LrcUtils.formatTime(mLrcEntryList.get(centerLine).getTime());
float timeX = getWidth() - mTimeTextWidth / 2F;
float timeY = centerY - (mTimeFontMetrics.descent + mTimeFontMetrics.ascent) / 2;
canvas.drawText(timeText, timeX, timeY, mTimePaint);
}
canvas.translate(0, mOffset);
float y = 0;
for (int i = 0; i < mLrcEntryList.size(); i++) {
if (i > 0) {
y +=
((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1)
+ mDividerHeight;
}
if (BuildConfig.DEBUG) {
// mLrcPaint.setTypeface(ResourcesCompat.getFont(getContext(), R.font.sans));
}
if (i == mCurrentLine) {
mLrcPaint.setTextSize(mCurrentTextSize);
mLrcPaint.setColor(mCurrentTextColor);
} else if (isShowTimeline && i == centerLine) {
mLrcPaint.setColor(mTimelineTextColor);
} else {
mLrcPaint.setTextSize(mNormalTextSize);
mLrcPaint.setColor(mNormalTextColor);
}
drawText(canvas, mLrcEntryList.get(i).getStaticLayout(), y);
}
}
private void drawText(Canvas canvas, StaticLayout staticLayout, float y) {
canvas.save();
canvas.translate(mLrcPadding, y - (staticLayout.getHeight() >> 1));
staticLayout.draw(canvas);
canvas.restore();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP
|| event.getAction() == MotionEvent.ACTION_CANCEL) {
isTouching = false;
if (hasLrc() && !isFling) {
adjustCenter();
postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME);
}
}
return mGestureDetector.onTouchEvent(event);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
mOffset = mScroller.getCurrY();
invalidate();
}
if (isFling && mScroller.isFinished()) {
isFling = false;
if (hasLrc() && !isTouching) {
adjustCenter();
postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME);
}
}
}
@Override
protected void onDetachedFromWindow() {
removeCallbacks(hideTimelineRunnable);
super.onDetachedFromWindow();
}
private void onLrcLoaded(List<LrcEntry> entryList) {
if (entryList != null && !entryList.isEmpty()) {
mLrcEntryList.addAll(entryList);
}
Collections.sort(mLrcEntryList);
initEntryList();
invalidate();
}
private void initPlayDrawable() {
int l = (mTimeTextWidth - mDrawableWidth) / 2;
int t = getHeight() / 2 - mDrawableWidth / 2;
int r = l + mDrawableWidth;
int b = t + mDrawableWidth;
mPlayDrawable.setBounds(l, t, r, b);
}
private void initEntryList() {
if (!hasLrc() || getWidth() == 0) {
return;
}
for (LrcEntry lrcEntry : mLrcEntryList) {
lrcEntry.init(mLrcPaint, (int) getLrcWidth(), mTextGravity);
}
mOffset = getHeight() / 2F;
}
private void reset() {
endAnimation();
mScroller.forceFinished(true);
isShowTimeline = false;
isTouching = false;
isFling = false;
removeCallbacks(hideTimelineRunnable);
mLrcEntryList.clear();
mOffset = 0;
mCurrentLine = 0;
//invalidate();
}
private void adjustCenter() {
smoothScrollTo(getCenterLine(), ADJUST_DURATION);
}
private void smoothScrollTo(int line) {
smoothScrollTo(line, mAnimationDuration);
}
private void smoothScrollTo(int line, long duration) {
float offset = getOffset(line);
endAnimation();
mAnimator = ValueAnimator.ofFloat(mOffset, offset);
mAnimator.setDuration(duration);
mAnimator.setInterpolator(new LinearInterpolator());
mAnimator.addUpdateListener(
animation -> {
mOffset = (float) animation.getAnimatedValue();
invalidate();
});
mAnimator.start();
}
private void endAnimation() {
if (mAnimator != null && mAnimator.isRunning()) {
mAnimator.end();
}
}
private int findShowLine(long time) {
int left = 0;
int right = mLrcEntryList.size();
while (left <= right) {
int middle = (left + right) / 2;
long middleTime = mLrcEntryList.get(middle).getTime();
if (time < middleTime) {
right = middle - 1;
} else {
if (middle + 1 >= mLrcEntryList.size() || time < mLrcEntryList.get(middle + 1).getTime()) {
return middle;
}
left = middle + 1;
}
}
return 0;
}
private int getCenterLine() {
int centerLine = 0;
float minDistance = Float.MAX_VALUE;
for (int i = 0; i < mLrcEntryList.size(); i++) {
if (Math.abs(mOffset - getOffset(i)) < minDistance) {
minDistance = Math.abs(mOffset - getOffset(i));
centerLine = i;
}
}
return centerLine;
}
private float getOffset(int line) {
if (mLrcEntryList.get(line).getOffset() == Float.MIN_VALUE) {
float offset = getHeight() / 2F;
for (int i = 1; i <= line; i++) {
offset -=
((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1)
+ mDividerHeight;
}
mLrcEntryList.get(line).setOffset(offset);
}
return mLrcEntryList.get(line).getOffset();
}
private float getLrcWidth() {
return getWidth() - mLrcPadding * 2;
}
private void runOnUi(Runnable r) {
if (Looper.myLooper() == Looper.getMainLooper()) {
r.run();
} else {
post(r);
}
}
private Object getFlag() {
return mFlag;
}
private void setFlag(Object flag) {
this.mFlag = flag;
}
public interface OnPlayClickListener {
boolean onPlayClick(long time);
}
}

View file

@ -1,66 +0,0 @@
package code.name.monkey.retromusic.service
import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context
import android.media.MediaPlayer
import android.provider.Settings
import androidx.core.animation.doOnEnd
import code.name.monkey.retromusic.service.playback.Playback
import code.name.monkey.retromusic.util.PreferenceUtil
class AudioFader {
companion object {
fun createFadeAnimator(
context: Context,
fadeInMp: MediaPlayer,
fadeOutMp: MediaPlayer,
endAction: (animator: Animator) -> Unit, /* Code to run when Animator Ends*/
): Animator? {
// Get Global animator scale
val animScale = Settings.Global.getFloat(context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f)
// Set duration according to the global animation scale, so cross-fade actually lasts for the duration set by the user
val duration = (PreferenceUtil.crossFadeDuration * 1000 ) / animScale
if (duration == 0F) {
return null
}
return ValueAnimator.ofFloat(0f, 1f).apply {
this.duration = duration.toLong()
addUpdateListener { animation: ValueAnimator ->
fadeInMp.setVolume(
animation.animatedValue as Float, animation.animatedValue as Float
)
fadeOutMp.setVolume(1 - animation.animatedValue as Float,
1 - animation.animatedValue as Float)
}
doOnEnd {
endAction(it)
}
}
}
fun startFadeAnimator(
playback: Playback,
fadeIn: Boolean, /* fadeIn -> true fadeOut -> false*/
callback: Runnable? = null, /* Code to run when Animator Ends*/
) {
val duration = PreferenceUtil.audioFadeDuration.toLong()
if (duration == 0L) {
callback?.run()
return
}
val startValue = if (fadeIn) 0f else 1.0f
val endValue = if (fadeIn) 1.0f else 0f
val animator = ValueAnimator.ofFloat(startValue, endValue)
animator.duration = duration
animator.addUpdateListener { animation: ValueAnimator ->
playback.setVolume(animation.animatedValue as Float)
}
animator.doOnEnd {
callback?.run()
}
animator.start()
}
}
}

View file

@ -1,189 +0,0 @@
package code.name.monkey.retromusic.service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.media.AudioAttributes
import android.media.AudioManager
import android.media.MediaPlayer
import android.media.PlaybackParams
import androidx.annotation.CallSuper
import androidx.core.content.getSystemService
import androidx.core.net.toUri
import androidx.media.AudioAttributesCompat
import androidx.media.AudioFocusRequestCompat
import androidx.media.AudioManagerCompat
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.service.playback.Playback
import code.name.monkey.retromusic.util.PreferenceUtil.isAudioFocusEnabled
import code.name.monkey.retromusic.util.PreferenceUtil.playbackPitch
import code.name.monkey.retromusic.util.PreferenceUtil.playbackSpeed
abstract class LocalPlayback(val context: Context) : Playback, MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener {
private val becomingNoisyReceiverIntentFilter =
IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
private val audioManager: AudioManager? = context.getSystemService()
private var becomingNoisyReceiverRegistered = false
private val becomingNoisyReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != null
&& intent.action == AudioManager.ACTION_AUDIO_BECOMING_NOISY
) {
val serviceIntent = Intent(context, MusicService::class.java)
serviceIntent.action = MusicService.ACTION_PAUSE
context.startService(serviceIntent)
}
}
}
private var isPausedByTransientLossOfFocus = false
private val audioFocusListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
when (focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> {
if (!isPlaying && isPausedByTransientLossOfFocus) {
start()
callbacks?.onPlayStateChanged()
isPausedByTransientLossOfFocus = false
}
setVolume(Volume.NORMAL)
}
AudioManager.AUDIOFOCUS_LOSS -> {
// Lost focus for an unbounded amount of time: stop playback and release media playback
if (!isAudioFocusEnabled) {
pause()
callbacks?.onPlayStateChanged()
}
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
// Lost focus for a short time, but we have to stop
// playback. We don't release the media playback because playback
// is likely to resume
val wasPlaying = isPlaying
pause()
callbacks?.onPlayStateChanged()
isPausedByTransientLossOfFocus = wasPlaying
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
setVolume(Volume.DUCK)
}
}
}
private val audioFocusRequest: AudioFocusRequestCompat =
AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN)
.setOnAudioFocusChangeListener(audioFocusListener)
.setAudioAttributes(
AudioAttributesCompat.Builder()
.setContentType(AudioAttributesCompat.CONTENT_TYPE_MUSIC).build()
).build()
@CallSuper
override fun start(): Boolean {
if (!requestFocus()) {
context.showToast(R.string.audio_focus_denied)
}
registerBecomingNoisyReceiver()
return true
}
@CallSuper
override fun stop() {
abandonFocus()
unregisterBecomingNoisyReceiver()
}
@CallSuper
override fun pause(): Boolean {
unregisterBecomingNoisyReceiver()
return true
}
/**
* @param player The [MediaPlayer] to use
* @param path The path of the file, or the http/rtsp URL of the stream you want to play
* @return True if the <code>player</code> has been prepared and is ready to play, false otherwise
*/
fun setDataSourceImpl(
player: MediaPlayer,
path: String,
completion: (success: Boolean) -> Unit,
) {
player.reset()
try {
if (path.startsWith("content://")) {
player.setDataSource(context, path.toUri())
} else {
player.setDataSource(path)
}
player.setAudioAttributes(
AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
)
if (VersionUtils.hasMarshmallow())
player.playbackParams =
PlaybackParams().setSpeed(playbackSpeed).setPitch(playbackPitch)
player.setOnPreparedListener {
player.setOnPreparedListener(null)
completion(true)
}
player.prepareAsync()
} catch (e: Exception) {
completion(false)
e.printStackTrace()
}
player.setOnCompletionListener(this)
player.setOnErrorListener(this)
}
private fun unregisterBecomingNoisyReceiver() {
if (becomingNoisyReceiverRegistered) {
context.unregisterReceiver(becomingNoisyReceiver)
becomingNoisyReceiverRegistered = false
}
}
private fun registerBecomingNoisyReceiver() {
if (!becomingNoisyReceiverRegistered) {
context.registerReceiver(
becomingNoisyReceiver,
becomingNoisyReceiverIntentFilter
)
becomingNoisyReceiverRegistered = true
}
}
private fun requestFocus(): Boolean {
return AudioManagerCompat.requestAudioFocus(
audioManager!!,
audioFocusRequest
) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
}
private fun abandonFocus() {
AudioManagerCompat.abandonAudioFocusRequest(audioManager!!, audioFocusRequest)
}
object Volume {
/**
* The volume we set the media player to when we lose audio focus, but are
* allowed to reduce the volume instead of stopping playback.
*/
const val DUCK = 0.2f
/** The volume we set the media player when we have audio focus. */
const val NORMAL = 1.0f
}
}

View file

@ -1,196 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.service
import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.os.PowerManager
import android.os.PowerManager.WakeLock
import android.util.Log
import android.view.KeyEvent
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.os.BundleCompat
import androidx.media.session.MediaButtonReceiver
import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_PAUSE
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_PLAY
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_STOP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
/**
* Used to control headset playback.
* Single press: pause/resume
* Double press: actionNext track
* Triple press: previous track
*/
class MediaButtonIntentReceiver : MediaButtonReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (DEBUG) Log.v(TAG, "Received intent: $intent")
if (handleIntent(context, intent) && isOrderedBroadcast) {
abortBroadcast()
}
}
companion object {
val TAG: String = MediaButtonIntentReceiver::class.java.simpleName
private val DEBUG = BuildConfig.DEBUG
private const val MSG_HEADSET_DOUBLE_CLICK_TIMEOUT = 2
private const val DOUBLE_CLICK = 400
private var wakeLock: WakeLock? = null
private var mClickCounter = 0
private var mLastClickTime: Long = 0
private val mHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {
MSG_HEADSET_DOUBLE_CLICK_TIMEOUT -> {
val clickCount = msg.arg1
if (DEBUG) Log.v(TAG, "Handling headset click, count = $clickCount")
val command = when (clickCount) {
1 -> ACTION_TOGGLE_PAUSE
2 -> ACTION_SKIP
3 -> ACTION_REWIND
else -> null
}
if (command != null) {
val context = msg.obj as Context
startService(context, command)
}
}
}
releaseWakeLockIfHandlerIdle()
}
}
fun handleIntent(context: Context, intent: Intent): Boolean {
println("Intent Action: ${intent.action}")
val intentAction = intent.action
if (Intent.ACTION_MEDIA_BUTTON == intentAction) {
val event = intent.extras?.let { BundleCompat.getParcelable(it, Intent.EXTRA_KEY_EVENT, KeyEvent::class.java) }
?: return false
val keycode = event.keyCode
val action = event.action
val eventTime = if (event.eventTime != 0L)
event.eventTime
else
System.currentTimeMillis()
var command: String? = null
when (keycode) {
KeyEvent.KEYCODE_MEDIA_STOP -> command = ACTION_STOP
KeyEvent.KEYCODE_HEADSETHOOK, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> command =
ACTION_TOGGLE_PAUSE
KeyEvent.KEYCODE_MEDIA_NEXT -> command = ACTION_SKIP
KeyEvent.KEYCODE_MEDIA_PREVIOUS -> command = ACTION_REWIND
KeyEvent.KEYCODE_MEDIA_PAUSE -> command = ACTION_PAUSE
KeyEvent.KEYCODE_MEDIA_PLAY -> command = ACTION_PLAY
}
if (command != null) {
if (action == KeyEvent.ACTION_DOWN) {
if (event.repeatCount == 0) {
// Only consider the first event in a sequence, not the repeat events,
// so that we don't trigger in cases where the first event went to
// a different app (e.g. when the user ends a phone call by
// long pressing the headset button)
// The service may or may not be running, but we need to send it
// a command.
if (keycode == KeyEvent.KEYCODE_HEADSETHOOK || keycode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (eventTime - mLastClickTime >= DOUBLE_CLICK) {
mClickCounter = 0
}
mClickCounter++
if (DEBUG) Log.v(TAG, "Got headset click, count = $mClickCounter")
mHandler.removeMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT)
val msg = mHandler.obtainMessage(
MSG_HEADSET_DOUBLE_CLICK_TIMEOUT, mClickCounter, 0, context
)
val delay = (if (mClickCounter < 3) DOUBLE_CLICK else 0).toLong()
if (mClickCounter >= 3) {
mClickCounter = 0
}
mLastClickTime = eventTime
acquireWakeLockAndSendMessage(context, msg, delay)
} else {
startService(context, command)
}
return true
}
}
}
}
return false
}
private fun startService(context: Context, command: String?) {
val intent = Intent(context, MusicService::class.java)
intent.action = command
try {
context.startService(intent)
} catch (e: Exception) {
ContextCompat.startForegroundService(context, intent)
}
}
private fun acquireWakeLockAndSendMessage(context: Context, msg: Message, delay: Long) {
if (wakeLock == null) {
val appContext = context.applicationContext
val pm = appContext.getSystemService<PowerManager>()
wakeLock = pm?.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
"RetroMusicApp:Wakelock headset button"
)
wakeLock!!.setReferenceCounted(false)
}
if (DEBUG) Log.v(TAG, "Acquiring wake lock and sending " + msg.what)
// Make sure we don't indefinitely hold the wake lock under any circumstances
wakeLock!!.acquire(10000)
mHandler.sendMessageDelayed(msg, delay)
}
private fun releaseWakeLockIfHandlerIdle() {
if (mHandler.hasMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT)) {
if (DEBUG) Log.v(TAG, "Handler still has messages pending, not releasing wake lock")
return
}
if (wakeLock != null) {
if (DEBUG) Log.v(TAG, "Releasing wake lock")
wakeLock!!.release()
wakeLock = null
}
}
}
}

View file

@ -1,278 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.service
import android.content.Context
import android.media.MediaPlayer
import android.os.PowerManager
import android.util.Log
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.extensions.uri
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.playback.Playback.PlaybackCallbacks
import code.name.monkey.retromusic.util.PreferenceUtil.isGapLessPlayback
import code.name.monkey.retromusic.util.logE
/**
* @author Andrew Neal, Karim Abou Zeid (kabouzeid)
*/
class MultiPlayer(context: Context) : LocalPlayback(context) {
private var mCurrentMediaPlayer = MediaPlayer()
private var mNextMediaPlayer: MediaPlayer? = null
override var callbacks: PlaybackCallbacks? = null
/**
* @return True if the player is ready to go, false otherwise
*/
override var isInitialized = false
private set
init {
mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK)
}
/**
* @param song The song object you want to play
* @return True if the `player` has been prepared and is ready to play, false otherwise
*/
override fun setDataSource(
song: Song,
force: Boolean,
completion: (success: Boolean) -> Unit,
) {
isInitialized = false
setDataSourceImpl(mCurrentMediaPlayer, song.uri.toString()) { success ->
isInitialized = success
if (isInitialized) {
setNextDataSource(null)
}
completion(isInitialized)
}
}
/**
* Set the MediaPlayer to start when this MediaPlayer finishes playback.
*
* @param path The path of the file, or the http/rtsp URL of the stream you want to play
*/
override fun setNextDataSource(path: String?) {
try {
mCurrentMediaPlayer.setNextMediaPlayer(null)
} catch (e: IllegalArgumentException) {
Log.i(TAG, "Next media player is current one, continuing")
} catch (e: IllegalStateException) {
Log.e(TAG, "Media player not initialized!")
return
}
if (mNextMediaPlayer != null) {
mNextMediaPlayer?.release()
mNextMediaPlayer = null
}
if (path == null) {
return
}
if (isGapLessPlayback) {
mNextMediaPlayer = MediaPlayer()
mNextMediaPlayer?.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK)
mNextMediaPlayer?.audioSessionId = audioSessionId
setDataSourceImpl(mNextMediaPlayer!!, path) { success ->
if (success) {
try {
mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer)
} catch (e: IllegalArgumentException) {
Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e)
if (mNextMediaPlayer != null) {
mNextMediaPlayer?.release()
mNextMediaPlayer = null
}
} catch (e: IllegalStateException) {
Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e)
if (mNextMediaPlayer != null) {
mNextMediaPlayer?.release()
mNextMediaPlayer = null
}
}
} else {
if (mNextMediaPlayer != null) {
mNextMediaPlayer?.release()
mNextMediaPlayer = null
}
}
}
}
}
/**
* Starts or resumes playback.
*/
override fun start(): Boolean {
super.start()
return try {
mCurrentMediaPlayer.start()
true
} catch (e: IllegalStateException) {
false
}
}
/**
* Resets the MediaPlayer to its uninitialized state.
*/
override fun stop() {
super.stop()
mCurrentMediaPlayer.reset()
isInitialized = false
}
/**
* Releases resources associated with this MediaPlayer object.
*/
override fun release() {
stop()
mCurrentMediaPlayer.release()
mNextMediaPlayer?.release()
}
/**
* Pauses playback. Call start() to resume.
*/
override fun pause(): Boolean {
super.pause()
return try {
mCurrentMediaPlayer.pause()
true
} catch (e: IllegalStateException) {
false
}
}
/**
* Checks whether the MultiPlayer is playing.
*/
override val isPlaying: Boolean
get() = isInitialized && mCurrentMediaPlayer.isPlaying
/**
* Gets the duration of the file.
*
* @return The duration in milliseconds
*/
override fun duration(): Int {
return if (!this.isInitialized) {
-1
} else try {
mCurrentMediaPlayer.duration
} catch (e: IllegalStateException) {
-1
}
}
/**
* Gets the current playback position.
*
* @return The current position in milliseconds
*/
override fun position(): Int {
return if (!this.isInitialized) {
-1
} else try {
mCurrentMediaPlayer.currentPosition
} catch (e: IllegalStateException) {
-1
}
}
/**
* Gets the current playback position.
*
* @param whereto The offset in milliseconds from the start to seek to
* @return The offset in milliseconds from the start to seek to
*/
override fun seek(whereto: Int, force: Boolean): Int {
return try {
mCurrentMediaPlayer.seekTo(whereto)
whereto
} catch (e: IllegalStateException) {
-1
}
}
override fun setVolume(vol: Float): Boolean {
return try {
mCurrentMediaPlayer.setVolume(vol, vol)
true
} catch (e: IllegalStateException) {
false
}
}
/**
* Sets the audio session ID.
*
* @param sessionId The audio session ID
*/
override fun setAudioSessionId(sessionId: Int): Boolean {
return try {
mCurrentMediaPlayer.audioSessionId = sessionId
true
} catch (e: IllegalArgumentException) {
false
} catch (e: IllegalStateException) {
false
}
}
/**
* Returns the audio session ID.
*
* @return The current audio session ID.
*/
override val audioSessionId: Int
get() = mCurrentMediaPlayer.audioSessionId
override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
isInitialized = false
mCurrentMediaPlayer.release()
mCurrentMediaPlayer = MediaPlayer()
mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK)
context.showToast(R.string.unplayable_file)
logE(what.toString() + extra)
return false
}
override fun onCompletion(mp: MediaPlayer) {
if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) {
isInitialized = false
mCurrentMediaPlayer.release()
mCurrentMediaPlayer = mNextMediaPlayer!!
isInitialized = true
mNextMediaPlayer = null
callbacks?.onTrackWentToNext()
} else {
callbacks?.onTrackEnded()
}
}
override fun setCrossFadeDuration(duration: Int) {}
override fun setPlaybackSpeedPitch(speed: Float, pitch: Float) {
mCurrentMediaPlayer.setPlaybackSpeedPitch(speed, pitch)
mNextMediaPlayer?.setPlaybackSpeedPitch(speed, pitch)
}
companion object {
val TAG: String = MultiPlayer::class.java.simpleName
}
}

View file

@ -1,46 +0,0 @@
package code.name.monkey.retromusic.service
import android.content.Context
import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaDescriptionCompat
import androidx.core.content.edit
import androidx.core.net.toUri
import code.name.monkey.retromusic.extensions.albumArtUri
import code.name.monkey.retromusic.model.Song
class PersistentStorage(context: Context) {
private val prefs = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)
fun saveSong(song: Song) {
prefs.edit {
putLong("song_id", song.id)
putString("song_title", song.title)
putString("song_artist", song.artistName)
putString("song_cover", song.albumArtUri.toString())
}
}
fun recentSong(): MediaBrowserCompat.MediaItem {
return MediaBrowserCompat.MediaItem(
MediaDescriptionCompat.Builder()
.setMediaId(prefs.getLong("song_id", 0L).toString())
.setTitle(prefs.getString("song_title", ""))
.setSubtitle(prefs.getString("song_artist", ""))
.setIconUri(prefs.getString("song_cover", "")?.toUri())
.build(), MediaBrowserCompat.MediaItem.FLAG_PLAYABLE
)
}
companion object {
const val PREFERENCES_NAME = "retro_recent"
@Volatile
private var instance: PersistentStorage? = null
fun getInstance(context: Context) =
instance ?: synchronized(this) {
instance ?: PersistentStorage(context).also { instance = it }
}
}
}

View file

@ -1,181 +0,0 @@
package code.name.monkey.retromusic.service
import android.content.Context
import android.content.Intent
import android.media.audiofx.AudioEffect
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.playback.Playback
import code.name.monkey.retromusic.util.PreferenceUtil
class PlaybackManager(val context: Context) {
var playback: Playback? = null
private var playbackLocation = PlaybackLocation.LOCAL
val isLocalPlayback get() = playbackLocation == PlaybackLocation.LOCAL
val audioSessionId: Int
get() = if (playback != null) {
playback!!.audioSessionId
} else 0
val songDurationMillis: Int
get() = if (playback != null) {
playback!!.duration()
} else -1
val songProgressMillis: Int
get() = if (playback != null) {
playback!!.position()
} else -1
val isPlaying: Boolean
get() = playback != null && playback!!.isPlaying
init {
playback = createLocalPlayback()
}
fun setCallbacks(callbacks: Playback.PlaybackCallbacks) {
playback?.callbacks = callbacks
}
fun play(onNotInitialized: () -> Unit) {
if (playback != null && !playback!!.isPlaying) {
if (!playback!!.isInitialized) {
onNotInitialized()
} else {
openAudioEffectSession()
if (playbackLocation == PlaybackLocation.LOCAL) {
if (playback is CrossFadePlayer) {
if (!(playback as CrossFadePlayer).isCrossFading) {
AudioFader.startFadeAnimator(playback!!, true)
}
} else {
AudioFader.startFadeAnimator(playback!!, true)
}
}
playback?.start()
}
}
}
fun pause(force: Boolean, onPause: () -> Unit) {
if (playback != null && playback!!.isPlaying) {
if (force) {
playback?.pause()
closeAudioEffectSession()
onPause()
} else {
AudioFader.startFadeAnimator(playback!!, false) {
//Code to run when Animator Ends
playback?.pause()
closeAudioEffectSession()
onPause()
}
}
}
}
fun seek(millis: Int, force: Boolean): Int = playback!!.seek(millis, force)
fun setDataSource(
song: Song,
force: Boolean,
completion: (success: Boolean) -> Unit,
) {
playback?.setDataSource(song, force, completion)
}
fun setNextDataSource(trackUri: String?) {
playback?.setNextDataSource(trackUri)
}
fun setCrossFadeDuration(duration: Int) {
playback?.setCrossFadeDuration(duration)
}
/**
* @param crossFadeDuration CrossFade duration
* @return Whether switched playback
*/
fun maybeSwitchToCrossFade(crossFadeDuration: Int): Boolean {
/* Switch to MultiPlayer if CrossFade duration is 0 and
Playback is not an instance of MultiPlayer */
if (playback !is MultiPlayer && crossFadeDuration == 0) {
if (playback != null) {
playback?.release()
}
playback = null
playback = MultiPlayer(context)
return true
} else if (playback !is CrossFadePlayer && crossFadeDuration > 0) {
if (playback != null) {
playback?.release()
}
playback = null
playback = CrossFadePlayer(context)
return true
}
return false
}
fun release() {
playback?.release()
playback = null
closeAudioEffectSession()
}
private fun openAudioEffectSession() {
val intent = Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId)
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
intent.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC)
context.sendBroadcast(intent)
}
private fun closeAudioEffectSession() {
val audioEffectsIntent = Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)
if (playback != null) {
audioEffectsIntent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION,
playback!!.audioSessionId)
}
audioEffectsIntent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
context.sendBroadcast(audioEffectsIntent)
}
fun switchToLocalPlayback(onChange: (wasPlaying: Boolean, progress: Int) -> Unit) {
playbackLocation = PlaybackLocation.LOCAL
switchToPlayback(createLocalPlayback(), onChange)
}
private fun switchToPlayback(
playback: Playback,
onChange: (wasPlaying: Boolean, progress: Int) -> Unit,
) {
val oldPlayback = this.playback
val wasPlaying: Boolean = oldPlayback?.isPlaying == true
val progress: Int = oldPlayback?.position() ?: 0
this.playback = playback
oldPlayback?.stop()
onChange(wasPlaying, progress)
}
private fun createLocalPlayback(): Playback {
// Set MultiPlayer when crossfade duration is 0 i.e. off
return if (PreferenceUtil.crossFadeDuration == 0) {
MultiPlayer(context)
} else {
CrossFadePlayer(context)
}
}
fun setPlaybackSpeedPitch(playbackSpeed: Float, playbackPitch: Float) {
playback?.setPlaybackSpeedPitch(playbackSpeed, playbackPitch)
}
}
enum class PlaybackLocation {
LOCAL,
}

View file

@ -1,24 +0,0 @@
package code.name.monkey.retromusic.util
import android.util.Log
import code.name.monkey.retromusic.BuildConfig
fun Any.logD(message: Any?) {
logD(message.toString())
}
fun Any.logD(message: String) {
if (BuildConfig.DEBUG) {
Log.d(name, message)
}
}
fun Any.logE(message: String) {
Log.e(name, message)
}
fun Any.logE(e: Exception) {
Log.e(name, e.message ?: "Error")
}
private val Any.name: String get() = this::class.java.simpleName

View file

@ -1,151 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package code.name.monkey.retromusic.views
import android.animation.Animator
import android.animation.ObjectAnimator
import android.content.Context
import android.content.res.ColorStateList
import android.util.AttributeSet
import android.util.Property
import android.view.animation.LinearInterpolator
import android.widget.FrameLayout
import android.widget.TextView
import androidx.annotation.VisibleForTesting
import code.name.monkey.retromusic.R
import java.text.NumberFormat
/**
* View that shows an integer number. It provides a smooth roll animation on changing the
* number.
*/
class NumberRollView(context: Context?, attrs: AttributeSet?) :
FrameLayout(context!!, attrs) {
private var mUpNumber: TextView? = null
private var mDownNumber: TextView? = null
private var mNumber = 0f
private var mLastRollAnimator: Animator? = null
private var mStringId = R.string.x_selected
private var mStringIdForZero = 0
override fun onFinishInflate() {
super.onFinishInflate()
mUpNumber = findViewById(R.id.up)
mDownNumber = findViewById(R.id.down)
assert(mUpNumber != null)
assert(mDownNumber != null)
setNumberRoll(mNumber)
}
/**
* Sets a number to display.
* @param animate Whether it should smoothly animate to the number.
*/
fun setNumber(number: Int, animate: Boolean) {
if (mLastRollAnimator != null) mLastRollAnimator!!.cancel()
if (animate) {
val rollAnimator: Animator =
ObjectAnimator.ofFloat(this, NUMBER_PROPERTY, number.toFloat())
rollAnimator.interpolator = LinearInterpolator()
rollAnimator.start()
mLastRollAnimator = rollAnimator
} else {
setNumberRoll(number.toFloat())
}
}
/**
* @param stringId The id of the string to use for the description. The string must be a plural
* that has one placeholder for a quantity.
*/
fun setString(stringId: Int) {
mStringId = stringId
}
/**
* @param stringIdForZero The id of the string to use for the description when the number is
* zero.
*/
fun setStringForZero(stringIdForZero: Int) {
mStringIdForZero = stringIdForZero
}
/**
* Gets the current number roll position.
*/
private fun getNumberRoll(): Float {
return mNumber
}
/**
* Sets the number roll position.
*/
private fun setNumberRoll(number: Float) {
mNumber = number
val downNumber = number.toInt()
val upNumber = downNumber + 1
val numberFormatter = NumberFormat.getIntegerInstance()
var newString = if (mStringId != 0) {
if (upNumber == 0 && mStringIdForZero != 0) resources.getString(mStringIdForZero) else resources.getString(
mStringId,
upNumber
)
} else {
numberFormatter.format(upNumber.toLong())
}
if (newString != mUpNumber!!.text.toString()) {
mUpNumber!!.text = newString
}
newString = if (mStringId != 0) {
if (downNumber == 0 && mStringIdForZero != 0) resources.getString(mStringIdForZero) else resources.getString(
mStringId,
downNumber
)
} else {
numberFormatter.format(downNumber.toLong())
}
if (newString != mDownNumber!!.text.toString()) {
mDownNumber!!.text = newString
}
val offset = number % 1.0f
mUpNumber!!.translationY = mUpNumber!!.height * (offset - 1.0f)
mDownNumber!!.translationY = mDownNumber!!.height * offset
mUpNumber!!.alpha = offset
mDownNumber!!.alpha = 1.0f - offset
}
/** Ends any in-progress animations. */
@VisibleForTesting
fun endAnimationsForTesting() {
if (mLastRollAnimator != null) mLastRollAnimator!!.end()
}
/**
* Update the text color with [ColorStateList] for both [TextView].
* @param resId The new text [ColorStateList] to use.
*/
fun setTextColorStateList(colorStateList: ColorStateList?) {
mUpNumber!!.setTextColor(colorStateList)
mDownNumber!!.setTextColor(colorStateList)
}
companion object {
/**
* A Property wrapper around the `number` functionality handled by the
* [NumberRollView.setNumberRoll] and [NumberRollView.getNumberRoll]
* methods.
*/
val NUMBER_PROPERTY: Property<NumberRollView, Float> =
object : Property<NumberRollView, Float>(
Float::class.java, ""
) {
override fun set(view: NumberRollView, value: Float) {
view.setNumberRoll(value)
}
override fun get(view: NumberRollView): Float {
return view.getNumberRoll()
}
}
}
}

View file

@ -1,63 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.views
import android.content.Context
import android.content.res.ColorStateList
import android.util.AttributeSet
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.extensions.addAlpha
import code.name.monkey.retromusic.extensions.setItemColors
import code.name.monkey.retromusic.util.PreferenceUtil
import com.google.android.material.bottomnavigation.BottomNavigationView
import dev.chrisbanes.insetter.applyInsetter
class TintedBottomNavigationView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : BottomNavigationView(context, attrs, defStyleAttr) {
init {
if (!isInEditMode) {
// If we are in Immersive mode we have to just set empty OnApplyWindowInsetsListener as
// bottom, start, and end padding is always applied (with the help of OnApplyWindowInsetsListener) to
// BottomNavigationView to dodge the system navigation bar (so we basically clear that listener).
if (PreferenceUtil.isFullScreenMode) {
setOnApplyWindowInsetsListener { _, insets ->
insets
}
} else {
applyInsetter {
type(navigationBars = true) {
padding(vertical = true)
margin(horizontal = true)
}
}
}
labelVisibilityMode = PreferenceUtil.tabTitleMode
if (!PreferenceUtil.materialYou) {
val iconColor = ATHUtil.resolveColor(context, android.R.attr.colorControlNormal)
val accentColor = ThemeStore.accentColor(context)
setItemColors(iconColor, accentColor)
itemRippleColor = ColorStateList.valueOf(accentColor.addAlpha(0.08F))
itemActiveIndicatorColor = ColorStateList.valueOf(accentColor.addAlpha(0.12F))
}
}
}
}

View file

@ -1,46 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.views
import android.content.Context
import android.content.res.ColorStateList
import android.util.AttributeSet
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.addAlpha
import code.name.monkey.retromusic.extensions.setItemColors
import code.name.monkey.retromusic.util.PreferenceUtil
import com.google.android.material.navigationrail.NavigationRailView
class TintedNavigationRailView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : NavigationRailView(context, attrs, defStyleAttr) {
init {
if (!isInEditMode) {
labelVisibilityMode = PreferenceUtil.tabTitleMode
if (!PreferenceUtil.materialYou) {
val iconColor = ATHUtil.resolveColor(context, android.R.attr.colorControlNormal)
val accentColor = context.accentColor()
setItemColors(iconColor, accentColor)
itemRippleColor = ColorStateList.valueOf(accentColor.addAlpha(0.08F))
itemActiveIndicatorColor = ColorStateList.valueOf(accentColor.addAlpha(0.12F))
}
}
}
}

View file

@ -1,22 +0,0 @@
package code.name.monkey.retromusic.views.insets
import android.content.Context
import android.util.AttributeSet
import androidx.constraintlayout.widget.ConstraintLayout
import code.name.monkey.retromusic.util.PreferenceUtil
import dev.chrisbanes.insetter.applyInsetter
class InsetsConstraintLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
init {
if (!isInEditMode && !PreferenceUtil.isFullScreenMode)
applyInsetter {
type(navigationBars = true) {
padding(vertical = true)
}
}
}
}

View file

@ -1,22 +0,0 @@
package code.name.monkey.retromusic.views.insets
import android.content.Context
import android.util.AttributeSet
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.util.PreferenceUtil
import dev.chrisbanes.insetter.applyInsetter
class InsetsRecyclerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : RecyclerView(context, attrs, defStyleAttr) {
init {
if (!isInEditMode && !PreferenceUtil.isFullScreenMode)
applyInsetter {
type(navigationBars = true) {
padding(vertical = true)
}
}
}
}

View file

@ -10,19 +10,16 @@
* 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 io.github.muntashirakon.music
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 io.github.muntashirakon.music.activities.ErrorActivity
import code.name.monkey.retromusic.activities.MainActivity import io.github.muntashirakon.music.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager import io.github.muntashirakon.music.helper.WallpaperAccentManager
import code.name.monkey.retromusic.helper.WallpaperAccentManager
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin import org.koin.core.context.startKoin
@ -41,7 +38,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(code.name.monkey.appthemehelper.R.color.md_deep_purple_A200) .accentColorRes(R.color.md_deep_purple_A200)
.coloredNavigationBar(true) .coloredNavigationBar(true)
.commit() .commit()
} }
@ -51,12 +48,7 @@ class App : Application() {
DynamicShortcutManager(this).initDynamicShortcuts() DynamicShortcutManager(this).initDynamicShortcuts()
// setting Error activity // setting Error activity
CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java) CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java).apply()
.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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic package io.github.muntashirakon.music
import android.provider.BaseColumns import android.provider.BaseColumns
import android.provider.MediaStore import android.provider.MediaStore
@ -79,7 +79,12 @@ 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"
@ -87,7 +92,6 @@ const val ALBUM_COVER_STYLE = "album_cover_style_id"
const val ALBUM_COVER_TRANSFORM = "album_cover_transform" const val ALBUM_COVER_TRANSFORM = "album_cover_transform"
const val TAB_TEXT_MODE = "tab_text_mode" const val TAB_TEXT_MODE = "tab_text_mode"
const val LANGUAGE_NAME = "language_name" const val LANGUAGE_NAME = "language_name"
const val LOCALE_AUTO_STORE_ENABLED = "locale_auto_store_enabled"
const val SLEEP_TIMER_FINISH_SONG = "sleep_timer_finish_song" const val SLEEP_TIMER_FINISH_SONG = "sleep_timer_finish_song"
const val ALBUM_GRID_STYLE = "album_grid_style_home" const val ALBUM_GRID_STYLE = "album_grid_style_home"
const val ARTIST_GRID_STYLE = "artist_grid_style_home" const val ARTIST_GRID_STYLE = "artist_grid_style_home"
@ -95,6 +99,7 @@ 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"
@ -111,6 +116,7 @@ const val ARTIST_GRID_SIZE_LAND = "artist_grid_size_land"
const val PLAYLIST_GRID_SIZE = "playlist_grid_size" const val PLAYLIST_GRID_SIZE = "playlist_grid_size"
const val PLAYLIST_GRID_SIZE_LAND = "playlist_grid_size_land" const val PLAYLIST_GRID_SIZE_LAND = "playlist_grid_size_land"
const val COLORED_APP_SHORTCUTS = "colored_app_shortcuts" const val COLORED_APP_SHORTCUTS = "colored_app_shortcuts"
const val AUDIO_DUCKING = "audio_ducking"
const val LAST_ADDED_CUTOFF = "last_added_interval" const val LAST_ADDED_CUTOFF = "last_added_interval"
const val LAST_SLEEP_TIMER_VALUE = "last_sleep_timer_value" const val LAST_SLEEP_TIMER_VALUE = "last_sleep_timer_value"
const val NEXT_SLEEP_TIMER_ELAPSED_REALTIME = "next_sleep_timer_elapsed_real_time" const val NEXT_SLEEP_TIMER_ELAPSED_REALTIME = "next_sleep_timer_elapsed_real_time"
@ -126,6 +132,7 @@ 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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic package io.github.muntashirakon.music
import androidx.annotation.IntDef import androidx.annotation.IntDef

View file

@ -0,0 +1,25 @@
package io.github.muntashirakon.music
import android.content.Context
import android.content.ContextWrapper
import android.os.LocaleList
import code.name.monkey.appthemehelper.util.VersionUtils.hasNougatMR
import java.util.*
class LanguageContextWrapper(base: Context?) : ContextWrapper(base) {
companion object {
fun wrap(context: Context?, newLocale: Locale?): LanguageContextWrapper {
if (context == null) return LanguageContextWrapper(context)
val configuration = context.resources.configuration
if (hasNougatMR()) {
configuration.setLocale(newLocale)
val localeList = LocaleList(newLocale)
LocaleList.setDefault(localeList)
configuration.setLocales(localeList)
} else {
configuration.setLocale(newLocale)
}
return LanguageContextWrapper(context.createConfigurationContext(configuration))
}
}
}

View file

@ -1,16 +1,24 @@
package code.name.monkey.retromusic package io.github.muntashirakon.music
import androidx.room.Room import androidx.room.Room
import code.name.monkey.retromusic.auto.AutoMusicProvider import androidx.room.RoomDatabase
import code.name.monkey.retromusic.db.MIGRATION_23_24 import androidx.sqlite.db.SupportSQLiteDatabase
import code.name.monkey.retromusic.db.RetroDatabase import io.github.muntashirakon.music.auto.AutoMusicProvider
import code.name.monkey.retromusic.fragments.LibraryViewModel import io.github.muntashirakon.music.db.BlackListStoreDao
import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel import io.github.muntashirakon.music.db.BlackListStoreEntity
import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel import io.github.muntashirakon.music.db.PlaylistWithSongs
import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel import io.github.muntashirakon.music.db.RetroDatabase
import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel import io.github.muntashirakon.music.fragments.LibraryViewModel
import code.name.monkey.retromusic.model.Genre import io.github.muntashirakon.music.fragments.albums.AlbumDetailsViewModel
import code.name.monkey.retromusic.repository.* import io.github.muntashirakon.music.fragments.artists.ArtistDetailsViewModel
import io.github.muntashirakon.music.fragments.genres.GenreDetailsViewModel
import io.github.muntashirakon.music.fragments.playlists.PlaylistDetailsViewModel
import io.github.muntashirakon.music.model.Genre
import io.github.muntashirakon.music.repository.*
import io.github.muntashirakon.music.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
@ -20,14 +28,32 @@ private val roomModule = module {
single { single {
Room.databaseBuilder(androidContext(), RetroDatabase::class.java, "playlist.db") Room.databaseBuilder(androidContext(), RetroDatabase::class.java, "playlist.db")
.addMigrations(MIGRATION_23_24) .allowMainThreadQueries()
.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()
} }
@ -37,7 +63,7 @@ private val roomModule = module {
} }
single { single {
RealRoomRepository(get(), get(), get()) RealRoomRepository(get(), get(), get(), get(), get())
} bind RoomRepository::class } bind RoomRepository::class
} }
private val autoModule = module { private val autoModule = module {
@ -138,10 +164,10 @@ private val viewModules = module {
) )
} }
viewModel { (playlistId: Long) -> viewModel { (playlist: PlaylistWithSongs) ->
PlaylistDetailsViewModel( PlaylistDetailsViewModel(
get(), get(),
playlistId playlist
) )
} }

View file

@ -12,32 +12,35 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities package io.github.muntashirakon.music.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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import io.github.muntashirakon.music.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityDriveModeBinding import io.github.muntashirakon.music.databinding.ActivityDriveModeBinding
import code.name.monkey.retromusic.db.toSongEntity import io.github.muntashirakon.music.db.toSongEntity
import code.name.monkey.retromusic.extensions.accentColor import io.github.muntashirakon.music.extensions.accentColor
import code.name.monkey.retromusic.extensions.drawAboveSystemBars import io.github.muntashirakon.music.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.glide.BlurTransformation import io.github.muntashirakon.music.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.BlurTransformation
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.helper.MusicPlayerRemote import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback import io.github.muntashirakon.music.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler import io.github.muntashirakon.music.helper.MusicProgressViewUpdateHelper.Callback
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.helper.PlayPauseButtonOnClickHandler
import code.name.monkey.retromusic.repository.RealRepository import io.github.muntashirakon.music.misc.SimpleOnSeekbarChangeListener
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.repository.RealRepository
import com.bumptech.glide.Glide import io.github.muntashirakon.music.service.MusicService
import com.google.android.material.slider.Slider import io.github.muntashirakon.music.util.MusicUtil
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -65,7 +68,7 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
lastPlaybackControlsColor = accentColor() lastPlaybackControlsColor = accentColor()
binding.close.setOnClickListener { binding.close.setOnClickListener {
onBackPressedDispatcher.onBackPressed() onBackPressed()
} }
binding.repeatButton.drawAboveSystemBars() binding.repeatButton.drawAboveSystemBars()
} }
@ -110,15 +113,17 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
} }
private fun setUpProgressSlider() { private fun setUpProgressSlider() {
binding.progressSlider.addOnChangeListener { _: Slider, progress: Float, fromUser: Boolean -> binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
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() {
@ -186,7 +191,6 @@ 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
@ -203,7 +207,6 @@ 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(
@ -211,7 +214,6 @@ 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(
@ -239,7 +241,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
Glide.with(this) GlideApp.with(this)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.songCoverOptions(song) .songCoverOptions(song)
.transform(BlurTransformation.Builder(this).build()) .transform(BlurTransformation.Builder(this).build())
@ -247,10 +249,12 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
} }
override fun onUpdateProgressViews(progress: Int, total: Int) { override fun onUpdateProgressViews(progress: Int, total: Int) {
binding.progressSlider.run { binding.progressSlider.max = total
valueTo = total.toFloat()
value = progress.toFloat().coerceIn(valueFrom, valueTo) val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
} 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

@ -1,34 +1,34 @@
package code.name.monkey.retromusic.activities package io.github.muntashirakon.music.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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.util.FileUtils.createFile import io.github.muntashirakon.music.util.FileUtils.createFile
import code.name.monkey.retromusic.util.Share.shareFile import io.github.muntashirakon.music.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(cat.ereza.customactivityoncrash.R.layout.customactivityoncrash_default_error_activity) setContentView(R.layout.customactivityoncrash_default_error_activity)
val restartButton = val restartButton =
findViewById<Button>(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_restart_button) findViewById<Button>(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(cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_restart_app) restartButton.setText(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>(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_more_info_button) findViewById<Button>(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
MaterialAlertDialogBuilder(this@ErrorActivity) AlertDialog.Builder(this@ErrorActivity)
.setTitle(cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_error_details_title) .setTitle(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(
cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_error_details_close, 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, "text/*") shareFile(this, bugReport)
} }
.show() .show()
} }
val errorActivityDrawableId = config.errorDrawable val errorActivityDrawableId = config.errorDrawable
val errorImageView = val errorImageView =
findViewById<ImageView>(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_image) findViewById<ImageView>(R.id.customactivityoncrash_error_activity_image)
if (errorActivityDrawableId != null) { if (errorActivityDrawableId != null) {
errorImageView.setImageResource( errorImageView.setImageResource(
errorActivityDrawableId errorActivityDrawableId

View file

@ -11,7 +11,7 @@
* 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.activities package io.github.muntashirakon.music.activities
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
@ -19,11 +19,11 @@ import android.view.MenuItem
import code.name.monkey.appthemehelper.util.ATHUtil.isWindowBackgroundDark import code.name.monkey.appthemehelper.util.ATHUtil.isWindowBackgroundDark
import code.name.monkey.appthemehelper.util.ColorUtil.lightenColor import code.name.monkey.appthemehelper.util.ColorUtil.lightenColor
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.activities.base.AbsThemeActivity import io.github.muntashirakon.music.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.databinding.ActivityLicenseBinding import io.github.muntashirakon.music.databinding.ActivityLicenseBinding
import code.name.monkey.retromusic.extensions.accentColor import io.github.muntashirakon.music.extensions.accentColor
import code.name.monkey.retromusic.extensions.drawAboveSystemBars import io.github.muntashirakon.music.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.extensions.surfaceColor import io.github.muntashirakon.music.extensions.surfaceColor
import java.io.BufferedReader import java.io.BufferedReader
import java.io.InputStreamReader import java.io.InputStreamReader
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@ -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) {
onBackPressedDispatcher.onBackPressed() onBackPressed()
return true return true
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)

View file

@ -12,27 +12,25 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities package io.github.muntashirakon.music.activities
import android.app.KeyguardManager import android.app.KeyguardManager
import android.os.Bundle import android.os.Bundle
import android.view.WindowManager import android.view.WindowManager
import androidx.core.content.getSystemService 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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import io.github.muntashirakon.music.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityLockScreenBinding import io.github.muntashirakon.music.databinding.ActivityLockScreenBinding
import code.name.monkey.retromusic.extensions.hideStatusBar import io.github.muntashirakon.music.extensions.hideStatusBar
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto import io.github.muntashirakon.music.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.extensions.whichFragment import io.github.muntashirakon.music.extensions.whichFragment
import code.name.monkey.retromusic.fragments.player.lockscreen.LockScreenControlsFragment import io.github.muntashirakon.music.fragments.player.lockscreen.LockScreenControlsFragment
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicPlayerRemote import io.github.muntashirakon.music.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
@ -86,11 +84,12 @@ class LockScreenActivity : AbsMusicServiceActivity() {
private fun lockScreenInit() { private fun lockScreenInit() {
if (VersionUtils.hasOreoMR1()) { if (VersionUtils.hasOreoMR1()) {
setShowWhenLocked(true) setShowWhenLocked(true)
//setTurnScreenOn(true) val keyguardManager = getSystemService<KeyguardManager>()
keyguardManager?.requestDismissKeyguard(this, null)
} else { } else {
window.addFlags( this.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
) )
} }
} }
@ -107,7 +106,7 @@ class LockScreenActivity : AbsMusicServiceActivity() {
private fun updateSongs() { private fun updateSongs() {
val song = MusicPlayerRemote.currentSong val song = MusicPlayerRemote.currentSong
Glide.with(this) GlideApp.with(this)
.asBitmapPalette() .asBitmapPalette()
.songCoverOptions(song) .songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))

View file

@ -12,37 +12,43 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities package io.github.muntashirakon.music.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.R import io.github.muntashirakon.music.*
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.extensions.* import io.github.muntashirakon.music.databinding.SlidingMusicPanelLayoutBinding
import code.name.monkey.retromusic.helper.MusicPlayerRemote import io.github.muntashirakon.music.extensions.*
import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.IScrollHelper import io.github.muntashirakon.music.helper.SearchQueryHelper.getSongs
import code.name.monkey.retromusic.model.CategoryInfo import io.github.muntashirakon.music.interfaces.IScrollHelper
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.model.CategoryInfo
import code.name.monkey.retromusic.repository.PlaylistSongsLoader import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.repository.PlaylistSongsLoader
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.util.logE import io.github.muntashirakon.music.util.PreferenceUtil
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() { class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener {
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()
@ -50,7 +56,9 @@ class MainActivity : AbsSlidingMusicPanelActivity() {
updateTabs() updateTabs()
setupNavigationController() setupNavigationController()
if (!hasPermissions()) {
findNavController(R.id.fragment_container).navigate(R.id.permissionFragment)
}
WhatsNewFragment.showChangeLog(this) WhatsNewFragment.showChangeLog(this)
} }
@ -76,9 +84,9 @@ class MainActivity : AbsSlidingMusicPanelActivity() {
) )
} }
navController.graph = navGraph navController.graph = navGraph
navigationView.setupWithNavController(navController) bottomNavigationView.setupWithNavController(navController)
// Scroll Fragment to top // Scroll Fragment to top
navigationView.setOnItemReselectedListener { bottomNavigationView.setOnItemReselectedListener {
currentFragment(R.id.fragment_container).apply { currentFragment(R.id.fragment_container).apply {
if (this is IScrollHelper) { if (this is IScrollHelper) {
scrollToTop() scrollToTop()
@ -110,10 +118,8 @@ class MainActivity : AbsSlidingMusicPanelActivity() {
} }
private fun saveTab(id: Int) { private fun saveTab(id: Int) {
if (PreferenceUtil.libraryCategory.firstOrNull { it.category.id == id }?.visible == true) {
PreferenceUtil.lastTab = id PreferenceUtil.lastTab = id
} }
}
override fun onSupportNavigateUp(): Boolean = override fun onSupportNavigateUp(): Boolean =
findNavController(R.id.fragment_container).navigateUp() findNavController(R.id.fragment_container).navigateUp()
@ -129,6 +135,22 @@ class MainActivity : AbsSlidingMusicPanelActivity() {
} }
} }
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
@ -196,7 +218,7 @@ class MainActivity : AbsSlidingMusicPanelActivity() {
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) {
@ -205,7 +227,7 @@ class MainActivity : AbsSlidingMusicPanelActivity() {
try { try {
id = idString.toLong() id = idString.toLong()
} catch (e: NumberFormatException) { } catch (e: NumberFormatException) {
logE(e) println(e.message)
} }
} }
} }

View file

@ -12,8 +12,9 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities package io.github.muntashirakon.music.activities
import android.Manifest
import android.Manifest.permission.BLUETOOTH_CONNECT import android.Manifest.permission.BLUETOOTH_CONNECT
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
@ -21,17 +22,16 @@ 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
import androidx.core.text.parseAsHtml import androidx.core.text.parseAsHtml
import androidx.core.view.isVisible 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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import io.github.muntashirakon.music.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityPermissionBinding import io.github.muntashirakon.music.databinding.ActivityPermissionBinding
import code.name.monkey.retromusic.extensions.* import io.github.muntashirakon.music.extensions.*
class PermissionActivity : AbsMusicServiceActivity() { class PermissionActivity : AbsMusicServiceActivity() {
private lateinit var binding: ActivityPermissionBinding private lateinit var binding: ActivityPermissionBinding
@ -61,14 +61,10 @@ class PermissionActivity : AbsMusicServiceActivity() {
if (VersionUtils.hasS()) { if (VersionUtils.hasS()) {
binding.bluetoothPermission.show() binding.bluetoothPermission.show()
binding.bluetoothPermission.setButtonClick { binding.bluetoothPermission.setButtonClick {
ActivityCompat.requestPermissions( ActivityCompat.requestPermissions(this,
this,
arrayOf(BLUETOOTH_CONNECT), arrayOf(BLUETOOTH_CONNECT),
BLUETOOTH_PERMISSION_REQUEST PERMISSION_REQUEST)
)
} }
} else {
binding.audioPermission.setNumber("2")
} }
binding.finish.accentBackgroundColor() binding.finish.accentBackgroundColor()
@ -83,20 +79,12 @@ 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( getString(R.string.message_welcome,
R.string.message_welcome, "<b>Metro</b>")
"<b>Metro</b>"
)
.parseAsHtml() .parseAsHtml()
binding.appNameText.text = appName binding.appNameText.text = appName
} }
@ -126,19 +114,23 @@ class PermissionActivity : AbsMusicServiceActivity() {
} }
private fun hasStoragePermission(): Boolean { private fun hasStoragePermission(): Boolean {
return hasPermissions() return ActivityCompat.checkSelfPermission(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( return ActivityCompat.checkSelfPermission(this,
this, BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED
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

@ -0,0 +1,122 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.activities
import android.Manifest.permission.BLUETOOTH_CONNECT
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.activities.base.AbsBaseActivity
import io.github.muntashirakon.music.appshortcuts.DynamicShortcutManager
import io.github.muntashirakon.music.databinding.ActivitySettingsBinding
import io.github.muntashirakon.music.extensions.*
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.color.ColorCallback
class SettingsActivity : AbsBaseActivity(), ColorCallback, OnThemeChangedListener {
private lateinit var binding: ActivitySettingsBinding
override fun onCreate(savedInstanceState: Bundle?) {
val mSavedInstanceState = extra<Bundle>(TAG).value ?: savedInstanceState
super.onCreate(mSavedInstanceState)
binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
setupToolbar()
setPermissionDeniedMessage(getString(R.string.permission_bluetooth_denied))
}
override fun onResume() {
super.onResume()
setNavigationBarColorPreOreo(surfaceColor())
}
private fun setupToolbar() {
applyToolbar(binding.toolbar)
val navController: NavController = findNavController(R.id.contentFrame)
navController.addOnDestinationChangedListener { _, _, _ ->
binding.collapsingToolbarLayout.title =
navController.currentDestination?.let { getStringFromDestination(it) }
}
}
private fun getStringFromDestination(currentDestination: NavDestination): String {
val idRes = when (currentDestination.id) {
R.id.mainSettingsFragment -> R.string.action_settings
R.id.audioSettings -> R.string.pref_header_audio
R.id.imageSettingFragment -> R.string.pref_header_images
R.id.notificationSettingsFragment -> R.string.notification
R.id.nowPlayingSettingsFragment -> R.string.now_playing
R.id.otherSettingsFragment -> R.string.others
R.id.personalizeSettingsFragment -> R.string.personalize
R.id.themeSettingsFragment -> R.string.general_settings_title
R.id.aboutActivity -> R.string.action_about
R.id.backup_fragment -> R.string.backup_restore_title
else -> R.id.action_settings
}
return getString(idRes)
}
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.contentFrame).navigateUp() || super.onSupportNavigateUp()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
}
return super.onOptionsItemSelected(item)
}
override fun getPermissionsToRequest(): Array<String> {
return if (VersionUtils.hasS()) {
arrayOf(BLUETOOTH_CONNECT)
} else {
arrayOf()
}
}
override fun invoke(dialog: MaterialDialog, color: Int) {
ThemeStore.editTheme(this).accentColor(color).commit()
if (VersionUtils.hasNougatMR())
DynamicShortcutManager(this).updateDynamicShortcuts()
restart()
}
override fun onThemeValuesChanged() {
restart()
}
private fun restart() {
val savedInstanceState = Bundle().apply {
onSaveInstanceState(this)
}
finish()
val intent = Intent(this, this::class.java).putExtra(TAG, savedInstanceState)
startActivity(intent)
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
}
companion object {
val TAG: String = SettingsActivity::class.java.simpleName
}
}
interface OnThemeChangedListener {
fun onThemeValuesChanged()
}

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities package io.github.muntashirakon.music.activities
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Bitmap import android.graphics.Bitmap
@ -22,28 +22,26 @@ 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.AbsThemeActivity import io.github.muntashirakon.music.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.databinding.ActivityShareInstagramBinding import io.github.muntashirakon.music.databinding.ActivityShareInstagramBinding
import code.name.monkey.retromusic.extensions.accentColor import io.github.muntashirakon.music.extensions.accentColor
import code.name.monkey.retromusic.extensions.setStatusBarColor import io.github.muntashirakon.music.extensions.setLightStatusBar
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.extensions.setStatusBarColor
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.util.Share import io.github.muntashirakon.music.util.Share
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
/** /**
* Created by hemanths on 2020-02-02. * Created by hemanths on 2020-02-02.
*/ */
class ShareInstagramStory : AbsThemeActivity() { class ShareInstagramStory : AbsBaseActivity() {
private lateinit var binding: ActivityShareInstagramBinding private lateinit var binding: ActivityShareInstagramBinding
@ -53,7 +51,7 @@ class ShareInstagramStory : 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) {
onBackPressedDispatcher.onBackPressed() onBackPressed()
return true return true
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
@ -68,15 +66,16 @@ class ShareInstagramStory : AbsThemeActivity() {
binding.toolbar.setBackgroundColor(Color.TRANSPARENT) binding.toolbar.setBackgroundColor(Color.TRANSPARENT)
setSupportActionBar(binding.toolbar) setSupportActionBar(binding.toolbar)
val song = intent.extras?.let { BundleCompat.getParcelable(it, EXTRA_SONG, Song::class.java) } val song = intent.extras?.getParcelable<Song>(EXTRA_SONG)
song?.let { songFinal -> song?.let { songFinal ->
Glide.with(this) GlideApp.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) {
setColors(colors.backgroundColor) val isColorLight = ColorUtil.isColorLight(colors.backgroundColor)
setColors(isColorLight, colors.backgroundColor)
} }
}) })
@ -104,7 +103,22 @@ class ShareInstagramStory : AbsThemeActivity() {
ColorStateList.valueOf(accentColor()) ColorStateList.valueOf(accentColor())
} }
private fun setColors(color: Int) { private fun setColors(colorLight: Boolean, 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,16 +1,12 @@
package code.name.monkey.retromusic.activities package io.github.muntashirakon.music.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.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
@ -18,12 +14,12 @@ import code.name.monkey.appthemehelper.util.ATHUtil.isWindowBackgroundDark
import code.name.monkey.appthemehelper.util.ColorUtil.isColorLight import code.name.monkey.appthemehelper.util.ColorUtil.isColorLight
import code.name.monkey.appthemehelper.util.ColorUtil.lightenColor import code.name.monkey.appthemehelper.util.ColorUtil.lightenColor
import code.name.monkey.appthemehelper.util.MaterialValueHelper.getPrimaryTextColor import code.name.monkey.appthemehelper.util.MaterialValueHelper.getPrimaryTextColor
import code.name.monkey.retromusic.BuildConfig import io.github.muntashirakon.music.BuildConfig
import code.name.monkey.retromusic.Constants import io.github.muntashirakon.music.Constants
import code.name.monkey.retromusic.databinding.FragmentWhatsNewBinding import io.github.muntashirakon.music.databinding.FragmentWhatsNewBinding
import code.name.monkey.retromusic.extensions.accentColor import io.github.muntashirakon.music.extensions.accentColor
import code.name.monkey.retromusic.extensions.openUrl import io.github.muntashirakon.music.extensions.openUrl
import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion import io.github.muntashirakon.music.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.*
@ -80,17 +76,6 @@ 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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities.base package io.github.muntashirakon.music.activities.base
import android.Manifest import android.Manifest
import android.content.Intent import android.content.Intent
@ -30,10 +30,8 @@ import android.widget.EditText
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.getSystemService 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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.extensions.accentColor import io.github.muntashirakon.music.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() {
@ -54,7 +52,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
} }
private val snackBarContainer: View private val snackBarContainer: View
get() = rootView get() = window.decorView
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -77,7 +75,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
logD(hasPermissions) println(hasPermissions)
} }
override fun dispatchKeyEvent(event: KeyEvent): Boolean { override fun dispatchKeyEvent(event: KeyEvent): Boolean {
@ -116,19 +114,33 @@ 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.READ_EXTERNAL_STORAGE, this@AbsBaseActivity, Manifest.permission.WRITE_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_SHORT Snackbar.LENGTH_INDEFINITE
) )
.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(
@ -153,34 +165,11 @@ 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

@ -12,29 +12,27 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities.base package io.github.muntashirakon.music.activities.base
import android.Manifest import android.Manifest
import android.content.* import android.content.*
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.db.toPlayCount import io.github.muntashirakon.music.db.toPlayCount
import code.name.monkey.retromusic.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener import io.github.muntashirakon.music.interfaces.IMusicServiceEventListener
import code.name.monkey.retromusic.repository.RealRepository import io.github.muntashirakon.music.repository.RealRepository
import code.name.monkey.retromusic.service.MusicService.Companion.FAVORITE_STATE_CHANGED import io.github.muntashirakon.music.service.MusicService.Companion.FAVORITE_STATE_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.MEDIA_STORE_CHANGED import io.github.muntashirakon.music.service.MusicService.Companion.MEDIA_STORE_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.META_CHANGED import io.github.muntashirakon.music.service.MusicService.Companion.META_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.PLAY_STATE_CHANGED import io.github.muntashirakon.music.service.MusicService.Companion.PLAY_STATE_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.QUEUE_CHANGED import io.github.muntashirakon.music.service.MusicService.Companion.QUEUE_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.REPEAT_MODE_CHANGED import io.github.muntashirakon.music.service.MusicService.Companion.REPEAT_MODE_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.SHUFFLE_MODE_CHANGED import io.github.muntashirakon.music.service.MusicService.Companion.SHUFFLE_MODE_CHANGED
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.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
@ -97,7 +95,8 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventLi
filter.addAction(MEDIA_STORE_CHANGED) filter.addAction(MEDIA_STORE_CHANGED)
filter.addAction(FAVORITE_STATE_CHANGED) filter.addAction(FAVORITE_STATE_CHANGED)
ContextCompat.registerReceiver(this, musicStateReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED) registerReceiver(musicStateReceiver, filter)
receiverRegistered = true receiverRegistered = true
} }
@ -122,14 +121,23 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventLi
listener.onPlayingMetaChanged() listener.onPlayingMetaChanged()
} }
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val entity = repository.songPresentInHistory(MusicPlayerRemote.currentSong)
if (entity != null) {
repository.updateHistorySong(MusicPlayerRemote.currentSong)
} else {
// Check whether pause history option is ON or OFF
if (!PreferenceUtil.pauseHistory) { if (!PreferenceUtil.pauseHistory) {
repository.upsertSongInHistory(MusicPlayerRemote.currentSong) repository.addSongToHistory(MusicPlayerRemote.currentSong)
}
}
val songs = repository.checkSongExistInPlayCount(MusicPlayerRemote.currentSong.id)
if (songs.isNotEmpty()) {
repository.updateSongInPlayCount(songs.first().apply {
playCount += 1
})
} else {
repository.insertSongInPlayCount(MusicPlayerRemote.currentSong.toPlayCount())
} }
val song = repository.findSongExistInPlayCount(MusicPlayerRemote.currentSong.id)
?.apply { playCount += 1 }
?: MusicPlayerRemote.currentSong.toPlayCount()
repository.upsertSongInPlayCount(song)
} }
} }
@ -177,18 +185,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)
logD("sendBroadcast $hasPermissions") println("sendBroadcast $hasPermissions")
} }
override fun getPermissionsToRequest(): Array<String> { override fun getPermissionsToRequest(): Array<String> {
return mutableListOf<String>().apply { return mutableListOf(Manifest.permission.READ_EXTERNAL_STORAGE).apply {
if (VersionUtils.hasT()) { if (!VersionUtils.hasQ()) {
add(Manifest.permission.READ_MEDIA_AUDIO)
add(Manifest.permission.POST_NOTIFICATIONS)
} else {
add(Manifest.permission.READ_EXTERNAL_STORAGE)
}
if (!VersionUtils.hasR()) {
add(Manifest.permission.WRITE_EXTERNAL_STORAGE) add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
} }
}.toTypedArray() }.toTypedArray()

View file

@ -12,12 +12,10 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities.base package io.github.muntashirakon.music.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
@ -26,74 +24,48 @@ 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.ADAPTIVE_COLOR_APP import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.ALBUM_COVER_STYLE import io.github.muntashirakon.music.databinding.SlidingMusicPanelLayoutBinding
import code.name.monkey.retromusic.ALBUM_COVER_TRANSFORM import io.github.muntashirakon.music.extensions.*
import code.name.monkey.retromusic.CAROUSEL_EFFECT import io.github.muntashirakon.music.fragments.LibraryViewModel
import code.name.monkey.retromusic.CIRCLE_PLAY_BUTTON import io.github.muntashirakon.music.fragments.NowPlayingScreen
import code.name.monkey.retromusic.EXTRA_SONG_INFO import io.github.muntashirakon.music.fragments.NowPlayingScreen.*
import code.name.monkey.retromusic.KEEP_SCREEN_ON import io.github.muntashirakon.music.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.LIBRARY_CATEGORIES import io.github.muntashirakon.music.fragments.other.MiniPlayerFragment
import code.name.monkey.retromusic.NOW_PLAYING_SCREEN_ID import io.github.muntashirakon.music.fragments.player.adaptive.AdaptiveFragment
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.fragments.player.blur.BlurPlayerFragment
import code.name.monkey.retromusic.SCREEN_ON_LYRICS import io.github.muntashirakon.music.fragments.player.card.CardFragment
import code.name.monkey.retromusic.SWIPE_ANYWHERE_NOW_PLAYING import io.github.muntashirakon.music.fragments.player.cardblur.CardBlurFragment
import code.name.monkey.retromusic.SWIPE_DOWN_DISMISS import io.github.muntashirakon.music.fragments.player.circle.CirclePlayerFragment
import code.name.monkey.retromusic.TAB_TEXT_MODE import io.github.muntashirakon.music.fragments.player.classic.ClassicPlayerFragment
import code.name.monkey.retromusic.TOGGLE_ADD_CONTROLS import io.github.muntashirakon.music.fragments.player.color.ColorFragment
import code.name.monkey.retromusic.TOGGLE_FULL_SCREEN import io.github.muntashirakon.music.fragments.player.fit.FitFragment
import code.name.monkey.retromusic.TOGGLE_VOLUME import io.github.muntashirakon.music.fragments.player.flat.FlatPlayerFragment
import code.name.monkey.retromusic.activities.PermissionActivity import io.github.muntashirakon.music.fragments.player.full.FullPlayerFragment
import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding import io.github.muntashirakon.music.fragments.player.gradient.GradientPlayerFragment
import code.name.monkey.retromusic.extensions.* import io.github.muntashirakon.music.fragments.player.material.MaterialFragment
import code.name.monkey.retromusic.fragments.LibraryViewModel import io.github.muntashirakon.music.fragments.player.md3.MD3PlayerFragment
import code.name.monkey.retromusic.fragments.NowPlayingScreen import io.github.muntashirakon.music.fragments.player.normal.PlayerFragment
import code.name.monkey.retromusic.fragments.NowPlayingScreen.* import io.github.muntashirakon.music.fragments.player.peek.PeekPlayerFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import io.github.muntashirakon.music.fragments.player.plain.PlainPlayerFragment
import code.name.monkey.retromusic.fragments.other.MiniPlayerFragment import io.github.muntashirakon.music.fragments.player.simple.SimplePlayerFragment
import code.name.monkey.retromusic.fragments.player.adaptive.AdaptiveFragment import io.github.muntashirakon.music.fragments.player.tiny.TinyPlayerFragment
import code.name.monkey.retromusic.fragments.player.blur.BlurPlayerFragment import io.github.muntashirakon.music.fragments.queue.PlayingQueueFragment
import code.name.monkey.retromusic.fragments.player.card.CardFragment import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.fragments.player.cardblur.CardBlurFragment import io.github.muntashirakon.music.model.CategoryInfo
import code.name.monkey.retromusic.fragments.player.circle.CirclePlayerFragment import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.fragments.player.classic.ClassicPlayerFragment import io.github.muntashirakon.music.util.ViewUtil
import code.name.monkey.retromusic.fragments.player.color.ColorFragment
import code.name.monkey.retromusic.fragments.player.fit.FitFragment
import code.name.monkey.retromusic.fragments.player.flat.FlatPlayerFragment
import code.name.monkey.retromusic.fragments.player.full.FullPlayerFragment
import code.name.monkey.retromusic.fragments.player.gradient.GradientPlayerFragment
import code.name.monkey.retromusic.fragments.player.material.MaterialFragment
import code.name.monkey.retromusic.fragments.player.md3.MD3PlayerFragment
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
import code.name.monkey.retromusic.fragments.player.peek.PeekPlayerFragment
import code.name.monkey.retromusic.fragments.player.plain.PlainPlayerFragment
import code.name.monkey.retromusic.fragments.player.simple.SimplePlayerFragment
import code.name.monkey.retromusic.fragments.player.tiny.TinyPlayerFragment
import code.name.monkey.retromusic.fragments.queue.PlayingQueueFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.CategoryInfo
import code.name.monkey.retromusic.util.PreferenceUtil
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.BottomSheetCallback import com.google.android.material.bottomsheet.BottomSheetBehavior.*
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
} }
@ -102,13 +74,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 lateinit var playerFragment: AbsPlayerFragment private var playerFragment: AbsPlayerFragment? = null
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
@ -117,18 +89,7 @@ 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 onBackPressedCallback = object : OnBackPressedCallback(true) { private val bottomSheetCallbackList = object : BottomSheetCallback() {
override fun handleOnBackPressed() {
println("Handle back press ${bottomSheetBehavior.state}")
if (!handleBackPress()) {
remove()
onBackPressedDispatcher.onBackPressed()
}
}
}
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)
@ -143,7 +104,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
} }
override fun onStateChanged(bottomSheet: View, newState: Int) { override fun onStateChanged(bottomSheet: View, newState: Int) {
onBackPressedCallback.isEnabled = newState == STATE_EXPANDED
when (newState) { when (newState) {
STATE_EXPANDED -> { STATE_EXPANDED -> {
onPanelExpanded() onPanelExpanded()
@ -151,28 +111,23 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
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.navigationView.bringToFront() binding.bottomNavigationView.bringToFront()
fromNotification = false fromNotification = false
} }
} }
STATE_HIDDEN -> { STATE_HIDDEN -> {
MusicPlayerRemote.clearQueue() MusicPlayerRemote.clearQueue()
} }
else -> { else -> {
logD("Do a flip") println("Do a flip")
}
} }
} }
} }
@ -182,14 +137,12 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (!hasPermissions()) { binding = createContentView()
startActivity(Intent(this, PermissionActivity::class.java))
finish()
}
binding = SlidingMusicPanelLayoutBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
binding.root.setOnApplyWindowInsetsListener { _, insets -> ViewCompat.setOnApplyWindowInsetsListener(
windowInsets = WindowInsetsCompat.toWindowInsetsCompat(insets) binding.root
) { _, insets ->
windowInsets = insets
insets insets
} }
chooseFragmentForTheme() chooseFragmentForTheme()
@ -198,25 +151,21 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
updateColor() updateColor()
if (!PreferenceUtil.materialYou) { if (!PreferenceUtil.materialYou) {
binding.slidingPanel.backgroundTintList = ColorStateList.valueOf(darkAccentColor()) binding.slidingPanel.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
navigationView.backgroundTintList = ColorStateList.valueOf(darkAccentColor()) bottomNavigationView.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
} }
navigationBarColor = surfaceColor() navigationBarColor = surfaceColor()
onBackPressedDispatcher.addCallback(onBackPressedCallback)
} }
private fun setupBottomSheet() { private fun setupBottomSheet() {
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()
} }
@ -228,69 +177,10 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList) bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList)
PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { protected fun wrapSlidingMusicPanel(): SlidingMusicPanelLayoutBinding {
when (key) { return SlidingMusicPanelLayoutBinding.inflate(layoutInflater)
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() {
@ -306,10 +196,8 @@ 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
if (!isLandscape) { binding.bottomNavigationView.translationY = progress * 500
binding.navigationView.translationY = progress * 500 binding.bottomNavigationView.alpha = alpha
binding.navigationView.alpha = alpha
}
binding.playerFragmentContainer.alpha = (progress - 0.2F) / 0.2F binding.playerFragmentContainer.alpha = (progress - 0.2F) / 0.2F
} }
@ -336,13 +224,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() {
@ -366,16 +254,22 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
}) })
} }
val navigationView get() = binding.navigationView val bottomNavigationView get() = binding.bottomNavigationView
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()) {
binding.slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
binding.slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
hideBottomSheet(false) hideBottomSheet(false)
} }
})
} // don't call hideBottomSheet(true) here as it causes a bug with the SlidingUpPanelLayout
}
override fun onQueueChanged() { override fun onQueueChanged() {
super.onQueueChanged() super.onQueueChanged()
@ -386,7 +280,12 @@ 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 (panelState == STATE_EXPANDED) { if (panelState == STATE_EXPANDED) {
collapsePanel() collapsePanel()
return true return true
@ -433,20 +332,18 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
} }
fun updateTabs() { fun updateTabs() {
binding.navigationView.menu.clear() binding.bottomNavigationView.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.navigationView.menu.add(0, menu.id, 0, menu.stringRes) binding.bottomNavigationView.menu.add(0, menu.id, 0, menu.stringRes)
.setIcon(menu.icon) .setIcon(menu.icon)
} }
} }
if (binding.navigationView.menu.size() == 1) { if (binding.bottomNavigationView.menu.size() == 1) {
isInOneTabMode = true isInOneTabMode = true
binding.navigationView.isVisible = false binding.bottomNavigationView.hide()
} else {
isInOneTabMode = false
} }
} }
@ -462,7 +359,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
animate: Boolean = false, animate: Boolean = false,
hideBottomSheet: Boolean = MusicPlayerRemote.playingQueue.isEmpty(), hideBottomSheet: Boolean = MusicPlayerRemote.playingQueue.isEmpty(),
) { ) {
if (!ViewCompat.isLaidOut(navigationView)) { if (!ViewCompat.isLaidOut(bottomNavigationView)) {
return return
} }
if (isInOneTabMode) { if (isInOneTabMode) {
@ -473,38 +370,38 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
) )
return return
} }
if (visible xor navigationView.isVisible) {
val mAnimate = animate && bottomSheetBehavior.state == STATE_COLLAPSED val mAnimate = animate && bottomSheetBehavior.state == STATE_COLLAPSED
if (mAnimate) { if (mAnimate) {
if (visible) { if (visible) {
binding.navigationView.bringToFront() binding.bottomNavigationView.bringToFront()
binding.navigationView.show() binding.bottomNavigationView.show()
} else { } else {
binding.navigationView.hide() binding.bottomNavigationView.hide()
} }
} else { } else {
binding.navigationView.isVisible = visible binding.bottomNavigationView.isVisible = false
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) { if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
binding.navigationView.bringToFront() binding.bottomNavigationView.bringToFront()
}
} }
} }
hideBottomSheet( hideBottomSheet(
hide = hideBottomSheet, hide = hideBottomSheet,
animate = animate, animate = animate,
isBottomNavVisible = visible && navigationView is BottomNavigationView isBottomNavVisible = visible
) )
} }
fun hideBottomSheet( fun hideBottomSheet(
hide: Boolean, hide: Boolean,
animate: Boolean = false, animate: Boolean = false,
isBottomNavVisible: Boolean = navigationView.isVisible && navigationView is BottomNavigationView, isBottomNavVisible: Boolean = bottomNavigationView.isVisible,
) { ) {
val heightOfBar = windowInsets.getBottomInsets() + dip(R.dimen.mini_player_height) val heightOfBar =
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.getBottomInsets() bottomSheetBehavior.peekHeight = -windowInsets.safeGetBottomInsets()
bottomSheetBehavior.state = STATE_COLLAPSED bottomSheetBehavior.state = STATE_COLLAPSED
libraryViewModel.setFabMargin( libraryViewModel.setFabMargin(
this, this,
@ -513,20 +410,17 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
} else { } else {
if (MusicPlayerRemote.playingQueue.isNotEmpty()) { if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
binding.slidingPanel.elevation = 0F binding.slidingPanel.elevation = 0F
binding.navigationView.elevation = 5F binding.bottomNavigationView.elevation = 5F
if (isBottomNavVisible) { if (isBottomNavVisible) {
logD("List") println("List")
if (animate) { if (animate) {
bottomSheetBehavior.peekHeightAnimate(heightOfBarWithTabs) bottomSheetBehavior.peekHeightAnimate(heightOfBarWithTabs)
} else { } else {
bottomSheetBehavior.peekHeight = heightOfBarWithTabs bottomSheetBehavior.peekHeight = heightOfBarWithTabs
} }
libraryViewModel.setFabMargin( libraryViewModel.setFabMargin(this, dip(R.dimen.mini_player_height_expanded))
this,
dip(R.dimen.bottom_nav_mini_player_height)
)
} else { } else {
logD("Details") println("Details")
if (animate) { if (animate) {
bottomSheetBehavior.peekHeightAnimate(heightOfBar).doOnEnd { bottomSheetBehavior.peekHeightAnimate(heightOfBar).doOnEnd {
binding.slidingPanel.bringToFront() binding.slidingPanel.bringToFront()
@ -549,7 +443,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
private fun chooseFragmentForTheme() { private fun chooseFragmentForTheme() {
nowPlayingScreen = PreferenceUtil.nowPlayingScreen nowPlayingScreen = PreferenceUtil.nowPlayingScreen
val fragment: AbsPlayerFragment = when (nowPlayingScreen) { val fragment: Fragment = when (nowPlayingScreen) {
Blur -> BlurPlayerFragment() Blur -> BlurPlayerFragment()
Adaptive -> AdaptiveFragment() Adaptive -> AdaptiveFragment()
Normal -> PlayerFragment() Normal -> PlayerFragment()
@ -569,12 +463,12 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
Classic -> ClassicPlayerFragment() Classic -> ClassicPlayerFragment()
MD3 -> MD3PlayerFragment() MD3 -> MD3PlayerFragment()
else -> PlayerFragment() else -> PlayerFragment()
} // must extend AbsPlayerFragment } // must implement AbsPlayerFragment
supportFragmentManager.commit { supportFragmentManager.commit {
replace(R.id.playerFragmentContainer, fragment) replace(R.id.playerFragmentContainer, fragment)
} }
supportFragmentManager.executePendingTransactions() supportFragmentManager.executePendingTransactions()
playerFragment = whichFragment(R.id.playerFragmentContainer) playerFragment = whichFragment<AbsPlayerFragment>(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

@ -12,35 +12,38 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities.base package io.github.muntashirakon.music.activities.base
import android.content.Context import android.content.Context
import android.content.res.Resources
import android.os.Bundle 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 androidx.appcompat.app.AppCompatDelegate import android.view.View
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
import androidx.core.os.LocaleListCompat 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.R import io.github.muntashirakon.music.LanguageContextWrapper
import code.name.monkey.retromusic.extensions.* import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.extensions.*
import code.name.monkey.retromusic.util.theme.getNightMode import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.theme.getThemeResValue import io.github.muntashirakon.music.util.theme.getNightMode
import io.github.muntashirakon.music.util.theme.getThemeResValue
import java.util.*
abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable { abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
updateLocale()
updateTheme() updateTheme()
hideStatusBar() hideStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setEdgeToEdgeOrImmersive() setEdgeToEdgeOrImmersive()
maybeSetScreenOn() registerSystemUiVisibility()
toggleScreenOn()
setLightNavigationBarAuto() setLightNavigationBarAuto()
setLightStatusBarAuto(surfaceColor()) setLightStatusBarAuto(surfaceColor())
if (VersionUtils.hasQ()) { if (VersionUtils.hasQ()) {
@ -57,13 +60,8 @@ 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)
private fun updateLocale() {
val localeCode = PreferenceUtil.languageCode
if (PreferenceUtil.isLocaleAutoStorageEnabled) {
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(localeCode))
PreferenceUtil.isLocaleAutoStorageEnabled = true
} }
} }
@ -78,6 +76,20 @@ 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()
} }
@ -89,6 +101,7 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
public override fun onDestroy() { public override fun onDestroy() {
super.onDestroy() super.onDestroy()
unregisterSystemUiVisibility()
exitFullscreen() exitFullscreen()
} }
@ -101,6 +114,13 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
} }
override fun attachBaseContext(newBase: Context?) { override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase) val code = PreferenceUtil.languageCode
val locale = if (code == "auto") {
// Get the device default locale
ConfigurationCompat.getLocales(Resources.getSystem().configuration)[0]
} else {
Locale.forLanguageTag(code)
}
super.attachBaseContext(LanguageContextWrapper.wrap(newBase, locale))
} }
} }

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities.bugreport package io.github.muntashirakon.music.activities.bugreport
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
@ -23,13 +23,13 @@ import androidx.core.content.getSystemService
import androidx.core.net.toUri import androidx.core.net.toUri
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.base.AbsThemeActivity import io.github.muntashirakon.music.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.activities.bugreport.model.DeviceInfo import io.github.muntashirakon.music.activities.bugreport.model.DeviceInfo
import code.name.monkey.retromusic.databinding.ActivityBugReportBinding import io.github.muntashirakon.music.databinding.ActivityBugReportBinding
import code.name.monkey.retromusic.extensions.accentColor import io.github.muntashirakon.music.extensions.accentColor
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto import io.github.muntashirakon.music.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.extensions.showToast import io.github.muntashirakon.music.extensions.showToast
open class BugReportActivity : AbsThemeActivity() { open class BugReportActivity : AbsThemeActivity() {
@ -64,6 +64,7 @@ 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
@ -79,11 +80,17 @@ 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) {
onBackPressedDispatcher.onBackPressed() 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

@ -1,15 +1,15 @@
package code.name.monkey.retromusic.activities.bugreport.model package io.github.muntashirakon.music.activities.bugreport.model
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import androidx.annotation.IntRange import androidx.annotation.IntRange
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.pm.PackageInfoCompat import androidx.core.content.pm.PackageInfoCompat
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil.isAdaptiveColor import io.github.muntashirakon.music.util.PreferenceUtil.isAdaptiveColor
import code.name.monkey.retromusic.util.PreferenceUtil.nowPlayingScreen import io.github.muntashirakon.music.util.PreferenceUtil.languageCode
import io.github.muntashirakon.music.util.PreferenceUtil.nowPlayingScreen
import java.util.* import java.util.*
class DeviceInfo(context: Context) { class DeviceInfo(context: Context) {
@ -106,6 +106,6 @@ class DeviceInfo(context: Context) {
baseTheme = PreferenceUtil.baseTheme baseTheme = PreferenceUtil.baseTheme
nowPlayingTheme = context.getString(nowPlayingScreen.titleRes) nowPlayingTheme = context.getString(nowPlayingScreen.titleRes)
isAdaptive = isAdaptiveColor isAdaptive = isAdaptiveColor
selectedLang = AppCompatDelegate.getApplicationLocales().toLanguageTags() selectedLang = languageCode
} }
} }

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
package code.name.monkey.retromusic.activities.saf; package io.github.muntashirakon.music.activities.saf;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
@ -22,7 +22,7 @@ import androidx.annotation.Nullable;
import com.heinrichreimersoftware.materialintro.app.IntroActivity; import com.heinrichreimersoftware.materialintro.app.IntroActivity;
import com.heinrichreimersoftware.materialintro.slide.SimpleSlide; import com.heinrichreimersoftware.materialintro.slide.SimpleSlide;
import code.name.monkey.retromusic.R; import io.github.muntashirakon.music.R;
/** Created by hemanths on 2019-07-31. */ /** Created by hemanths on 2019-07-31. */
public class SAFGuideActivity extends IntroActivity { public class SAFGuideActivity extends IntroActivity {
@ -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(code.name.monkey.appthemehelper.R.color.md_deep_purple_300) .background(R.color.md_deep_purple_300)
.backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_400) .backgroundDark(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(code.name.monkey.appthemehelper.R.color.md_deep_purple_500) .background(R.color.md_deep_purple_500)
.backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_600) .backgroundDark(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(code.name.monkey.appthemehelper.R.color.md_deep_purple_700) .background(R.color.md_deep_purple_700)
.backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_800) .backgroundDark(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

@ -11,19 +11,19 @@
* 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.activities.saf package io.github.muntashirakon.music.activities.saf
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity.REQUEST_CODE_SAF_GUIDE import io.github.muntashirakon.music.activities.saf.SAFGuideActivity.REQUEST_CODE_SAF_GUIDE
import code.name.monkey.retromusic.util.SAFUtil import io.github.muntashirakon.music.util.SAFUtil
/** Created by buliasz on 2021-02-07. */ /** Created by buliasz on 2021-02-07. */
class SAFRequestActivity : Activity() { class SAFRequestActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val intent = Intent(this, code.name.monkey.retromusic.activities.saf.SAFGuideActivity::class.java) val intent = Intent(this, SAFGuideActivity::class.java)
startActivityForResult(intent, REQUEST_CODE_SAF_GUIDE) startActivityForResult(intent, REQUEST_CODE_SAF_GUIDE)
} }

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities.tageditor package io.github.muntashirakon.music.activities.tageditor
import android.app.Activity import android.app.Activity
import android.app.SearchManager import android.app.SearchManager
@ -29,23 +29,25 @@ import android.view.animation.OvershootInterpolator
import android.widget.ImageView import android.widget.ImageView
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.IntentSenderRequest import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts 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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import io.github.muntashirakon.music.R.drawable
import code.name.monkey.retromusic.extensions.accentColor import io.github.muntashirakon.music.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.extensions.colorButtons import io.github.muntashirakon.music.activities.saf.SAFGuideActivity
import code.name.monkey.retromusic.extensions.hideSoftKeyboard import io.github.muntashirakon.music.extensions.accentColor
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto import io.github.muntashirakon.music.extensions.colorButtons
import code.name.monkey.retromusic.model.ArtworkInfo import io.github.muntashirakon.music.extensions.hideSoftKeyboard
import code.name.monkey.retromusic.model.AudioTagInfo import io.github.muntashirakon.music.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.repository.Repository import io.github.muntashirakon.music.model.ArtworkInfo
import code.name.monkey.retromusic.util.logD import io.github.muntashirakon.music.model.AudioTagInfo
import code.name.monkey.retromusic.util.logE import io.github.muntashirakon.music.repository.Repository
import io.github.muntashirakon.music.util.SAFUtil
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,6 +57,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.*
abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() { abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
abstract val editorImage: ImageView abstract val editorImage: ImageView
@ -98,8 +101,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -108,8 +110,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TITLE) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TITLE)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -117,8 +118,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.COMPOSER) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.COMPOSER)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -127,8 +127,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -137,8 +136,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ARTIST) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ARTIST)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -147,8 +145,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -157,8 +154,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.GENRE) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.GENRE)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -167,8 +163,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.YEAR) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.YEAR)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -177,8 +172,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TRACK) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TRACK)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -187,8 +181,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.DISC_NO) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.DISC_NO)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -197,8 +190,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
get() { get() {
return try { return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.LYRICS) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.LYRICS)
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
null null
} }
} }
@ -216,17 +208,11 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
) )
} }
return null return null
} catch (e: Exception) { } catch (ignored: Exception) {
logE(e)
return null return null
} }
} }
private val pickArtworkImage =
registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
loadImageFromFile(uri)
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
_binding = bindingInflater.invoke(layoutInflater) _binding = bindingInflater.invoke(layoutInflater)
@ -237,7 +223,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
getIntentExtras() getIntentExtras()
songPaths = getSongPaths() songPaths = getSongPaths()
logD(songPaths?.size) println(songPaths?.size)
if (songPaths!!.isEmpty()) { if (songPaths!!.isEmpty()) {
finish() finish()
} }
@ -267,7 +253,14 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
} }
private fun startImagePicker() { private fun startImagePicker() {
pickArtworkImage.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(
Intent.createChooser(
intent,
getString(R.string.pick_from_local_storage)
), REQUEST_CODE_SELECT_IMAGE
)
} }
protected abstract fun loadCurrentImage() protected abstract fun loadCurrentImage()
@ -283,6 +276,7 @@ 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)
} }
} }
@ -315,7 +309,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 -> {
onBackPressedDispatcher.onBackPressed() super.onBackPressed()
return true return true
} }
} }
@ -340,7 +334,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) { protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) {
if (bitmap == null) { if (bitmap == null) {
editorImage.setImageResource(R.drawable.default_audio_art) editorImage.setImageResource(drawable.default_audio_art)
} else { } else {
editorImage.setImageBitmap(bitmap) editorImage.setImageBitmap(bitmap)
} }
@ -358,7 +352,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
hideSoftKeyboard() hideSoftKeyboard()
hideFab() hideFab()
logD(fieldKeyValueMap) println(fieldKeyValueMap)
GlobalScope.launch { GlobalScope.launch {
if (VersionUtils.hasR()) { if (VersionUtils.hasR()) {
cacheFiles = TagWriter.writeTagsToFilesR( cacheFiles = TagWriter.writeTagsToFilesR(
@ -368,12 +362,9 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
artworkInfo artworkInfo
) )
) )
val pendingIntent = MediaStore.createWriteRequest(contentResolver, getSongUris())
if (cacheFiles.isNotEmpty()) {
val pendingIntent =
MediaStore.createWriteRequest(contentResolver, getSongUris())
launcher.launch(IntentSenderRequest.Builder(pendingIntent).build()) launcher.launch(IntentSenderRequest.Builder(pendingIntent).build())
}
} else { } else {
TagWriter.writeTagsToFiles( TagWriter.writeTagsToFiles(
this@AbsTagEditorActivity, AudioTagInfo( this@AbsTagEditorActivity, AudioTagInfo(
@ -411,14 +402,36 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
} }
} }
private lateinit var audioFile: AudioFile
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
when (requestCode) {
REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
intent?.data?.let {
loadImageFromFile(it)
}
}
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE -> {
SAFUtil.openTreePicker(this)
}
SAFUtil.REQUEST_SAF_PICK_TREE -> {
if (resultCode == Activity.RESULT_OK) {
SAFUtil.saveTreeUri(this, intent)
writeTags(savedSongPaths)
}
}
SAFUtil.REQUEST_SAF_PICK_FILE -> {
if (resultCode == Activity.RESULT_OK) {
writeTags(Collections.singletonList(currentSongPath + SAFUtil.SEPARATOR + intent!!.dataString))
}
}
}
}
private fun getAudioFile(path: String): AudioFile { private fun getAudioFile(path: String): AudioFile {
return try { return try {
if (!this::audioFile.isInitialized) { AudioFileIO.read(File(path))
audioFile = AudioFileIO.read(File(path))
}
audioFile
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Could not read audio file $path", e) Log.e(TAG, "Could not read audio file $path", e)
AudioFile() AudioFile()

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities.tageditor package io.github.muntashirakon.music.activities.tageditor
import android.app.Activity import android.app.Activity
import android.content.res.ColorStateList import android.content.res.ColorStateList
@ -28,19 +28,17 @@ import android.widget.ImageView
import android.widget.Toast import android.widget.Toast
import androidx.core.widget.doAfterTextChanged 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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding import io.github.muntashirakon.music.databinding.ActivityAlbumTagEditorBinding
import code.name.monkey.retromusic.extensions.* import io.github.muntashirakon.music.extensions.*
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.ArtworkInfo import io.github.muntashirakon.music.model.ArtworkInfo
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.util.ImageUtil import io.github.muntashirakon.music.util.ImageUtil
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette import io.github.muntashirakon.music.util.RetroColorUtil.generatePalette
import code.name.monkey.retromusic.util.RetroColorUtil.getColor import io.github.muntashirakon.music.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
@ -100,7 +98,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)
logD(albumTitle + albumArtistName) println(albumTitle + albumArtistName)
} }
override fun loadCurrentImage() { override fun loadCurrentImage() {
@ -133,9 +131,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
} }
override fun loadImageFromFile(selectedFile: Uri?) { override fun loadImageFromFile(selectedFile: Uri?) {
Glide.with(this@AlbumTagEditorActivity) GlideApp.with(this@AlbumTagEditorActivity).asBitmapPalette().load(selectedFile)
.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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.activities.tageditor package io.github.muntashirakon.music.activities.tageditor
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
@ -28,18 +28,16 @@ import android.widget.ImageView
import android.widget.Toast import android.widget.Toast
import androidx.core.widget.doAfterTextChanged 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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.databinding.ActivitySongTagEditorBinding import io.github.muntashirakon.music.databinding.ActivitySongTagEditorBinding
import code.name.monkey.retromusic.extensions.* import io.github.muntashirakon.music.extensions.*
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.ArtworkInfo import io.github.muntashirakon.music.model.ArtworkInfo
import code.name.monkey.retromusic.repository.SongRepository import io.github.muntashirakon.music.repository.SongRepository
import code.name.monkey.retromusic.util.ImageUtil import io.github.muntashirakon.music.util.ImageUtil
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.RetroColorUtil import io.github.muntashirakon.music.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
@ -104,7 +102,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)
logD(songTitle + songYear) println(songTitle + songYear)
} }
override fun loadCurrentImage() { override fun loadCurrentImage() {
@ -172,11 +170,8 @@ 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?) {
Glide.with(this@SongTagEditorActivity) GlideApp.with(this@SongTagEditorActivity).asBitmapPalette().load(selectedFile)
.asBitmapPalette() .diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
.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

@ -0,0 +1,201 @@
package io.github.muntashirakon.music.activities.tageditor
import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.media.MediaScannerConnection
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import io.github.muntashirakon.music.extensions.showToast
import io.github.muntashirakon.music.misc.UpdateToastMediaScannerCompletionListener
import io.github.muntashirakon.music.model.AudioTagInfo
import io.github.muntashirakon.music.util.MusicUtil.createAlbumArtFile
import io.github.muntashirakon.music.util.MusicUtil.deleteAlbumArt
import io.github.muntashirakon.music.util.MusicUtil.insertAlbumArt
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.audio.exceptions.CannotReadException
import org.jaudiotagger.audio.exceptions.CannotWriteException
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException
import org.jaudiotagger.tag.TagException
import org.jaudiotagger.tag.images.AndroidArtwork
import org.jaudiotagger.tag.images.Artwork
import java.io.File
import java.io.IOException
class TagWriter {
companion object {
suspend fun scan(context: Context, toBeScanned: List<String?>?) {
if (toBeScanned == null || toBeScanned.isEmpty()) {
Log.i("scan", "scan: Empty")
context.showToast( "Scan file from folder")
return
}
MediaScannerConnection.scanFile(
context,
toBeScanned.toTypedArray(),
null,
withContext(Dispatchers.Main) {
if (context is Activity) UpdateToastMediaScannerCompletionListener(
context, toBeScanned
) else null
}
)
}
suspend fun writeTagsToFiles(context: Context, info: AudioTagInfo) {
withContext(Dispatchers.IO) {
runCatching {
var artwork: Artwork? = null
var albumArtFile: File? = null
if (info.artworkInfo?.artwork != null) {
try {
albumArtFile = createAlbumArtFile(context).canonicalFile
info.artworkInfo.artwork.compress(
Bitmap.CompressFormat.JPEG,
100,
albumArtFile.outputStream()
)
artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
} catch (e: IOException) {
e.printStackTrace()
}
}
var wroteArtwork = false
var deletedArtwork = false
for (filePath in info.filePaths!!) {
try {
val audioFile = AudioFileIO.read(File(filePath))
val tag = audioFile.tagOrCreateAndSetDefault
if (info.fieldKeyValueMap != null) {
for ((key, value) in info.fieldKeyValueMap) {
try {
tag.setField(key, value)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
if (info.artworkInfo != null) {
if (info.artworkInfo.artwork == null) {
tag.deleteArtworkField()
deletedArtwork = true
} else if (artwork != null) {
tag.deleteArtworkField()
tag.setField(artwork)
wroteArtwork = true
}
}
audioFile.commit()
} catch (e: CannotReadException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: CannotWriteException) {
e.printStackTrace()
} catch (e: TagException) {
e.printStackTrace()
} catch (e: ReadOnlyFileException) {
e.printStackTrace()
} catch (e: InvalidAudioFrameException) {
e.printStackTrace()
}
}
if (wroteArtwork) {
insertAlbumArt(context, info.artworkInfo!!.albumId, albumArtFile!!.path)
} else if (deletedArtwork) {
deleteAlbumArt(context, info.artworkInfo!!.albumId)
}
scan(context, info.filePaths)
}.onFailure {
it.printStackTrace()
}
}
}
@RequiresApi(Build.VERSION_CODES.R)
suspend fun writeTagsToFilesR(context: Context, info: AudioTagInfo): List<File> =
withContext(Dispatchers.IO) {
val cacheFiles = mutableListOf<File>()
runCatching {
var artwork: Artwork? = null
var albumArtFile: File? = null
if (info.artworkInfo?.artwork != null) {
try {
albumArtFile = createAlbumArtFile(context).canonicalFile
info.artworkInfo.artwork.compress(
Bitmap.CompressFormat.JPEG,
100,
albumArtFile.outputStream()
)
artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
} catch (e: IOException) {
e.printStackTrace()
}
}
var wroteArtwork = false
var deletedArtwork = false
for (filePath in info.filePaths!!) {
try {
val originFile = File(filePath)
val cacheFile = File(context.cacheDir, originFile.name)
cacheFiles.add(cacheFile)
originFile.inputStream().use { input ->
cacheFile.outputStream().use { output ->
input.copyTo(output)
}
}
val audioFile = AudioFileIO.read(cacheFile)
val tag = audioFile.tagOrCreateAndSetDefault
if (info.fieldKeyValueMap != null) {
for ((key, value) in info.fieldKeyValueMap) {
try {
tag.setField(key, value)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
if (info.artworkInfo != null) {
if (info.artworkInfo.artwork == null) {
tag.deleteArtworkField()
deletedArtwork = true
} else if (artwork != null) {
tag.deleteArtworkField()
tag.setField(artwork)
wroteArtwork = true
}
}
audioFile.commit()
} catch (e: CannotReadException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: CannotWriteException) {
e.printStackTrace()
} catch (e: TagException) {
e.printStackTrace()
} catch (e: ReadOnlyFileException) {
e.printStackTrace()
} catch (e: InvalidAudioFrameException) {
e.printStackTrace()
}
}
if (wroteArtwork) {
insertAlbumArt(context, info.artworkInfo!!.albumId, albumArtFile!!.path)
} else if (deletedArtwork) {
deleteAlbumArt(context, info.artworkInfo!!.albumId)
}
}.onFailure {
it.printStackTrace()
}
cacheFiles
}
}
}

View file

@ -11,7 +11,7 @@
* 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.adapter package io.github.muntashirakon.music.adapter
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.res.ColorStateList import android.content.res.ColorStateList
@ -22,15 +22,15 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.databinding.PreferenceDialogLibraryCategoriesListitemBinding import io.github.muntashirakon.music.databinding.PreferenceDialogLibraryCategoriesListitemBinding
import code.name.monkey.retromusic.extensions.showToast import io.github.muntashirakon.music.extensions.showToast
import code.name.monkey.retromusic.model.CategoryInfo import io.github.muntashirakon.music.model.CategoryInfo
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.SwipeAndDragHelper import io.github.muntashirakon.music.util.SwipeAndDragHelper
import code.name.monkey.retromusic.util.SwipeAndDragHelper.ActionCompletionContract import io.github.muntashirakon.music.util.SwipeAndDragHelper.ActionCompletionContract
class CategoryInfoAdapter : RecyclerView.Adapter<code.name.monkey.retromusic.adapter.CategoryInfoAdapter.ViewHolder>(), class CategoryInfoAdapter : RecyclerView.Adapter<CategoryInfoAdapter.ViewHolder>(),
ActionCompletionContract { ActionCompletionContract {
var categoryInfos: MutableList<CategoryInfo> = var categoryInfos: MutableList<CategoryInfo> =
PreferenceUtil.libraryCategory.toMutableList() PreferenceUtil.libraryCategory.toMutableList()

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter package io.github.muntashirakon.music.adapter
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.view.LayoutInflater import android.view.LayoutInflater
@ -21,17 +21,15 @@ import android.view.ViewGroup
import android.view.ViewOutlineProvider import android.view.ViewOutlineProvider
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.databinding.ItemGenreBinding import io.github.muntashirakon.music.databinding.ItemGenreBinding
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.interfaces.IGenreClickListener
import code.name.monkey.retromusic.interfaces.IGenreClickListener import io.github.muntashirakon.music.model.Genre
import code.name.monkey.retromusic.model.Genre import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import java.util.* import java.util.*
/** /**
@ -70,10 +68,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)
Glide.with(activity) GlideApp.with(activity)
.asBitmapPalette() .asBitmapPalette()
.songCoverOptions(genreSong)
.load(RetroGlideExtension.getSongModel(genreSong)) .load(RetroGlideExtension.getSongModel(genreSong))
.songCoverOptions(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

@ -12,12 +12,13 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter package io.github.muntashirakon.music.adapter
import android.annotation.SuppressLint 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
@ -27,21 +28,21 @@ import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.* import io.github.muntashirakon.music.*
import code.name.monkey.retromusic.adapter.album.AlbumAdapter import io.github.muntashirakon.music.adapter.album.AlbumAdapter
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
import code.name.monkey.retromusic.adapter.song.SongAdapter import io.github.muntashirakon.music.adapter.song.SongAdapter
import code.name.monkey.retromusic.fragments.home.HomeFragment import io.github.muntashirakon.music.fragments.home.HomeFragment
import code.name.monkey.retromusic.interfaces.IAlbumClickListener import io.github.muntashirakon.music.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.IArtistClickListener import io.github.muntashirakon.music.interfaces.IArtistClickListener
import code.name.monkey.retromusic.model.Album import io.github.muntashirakon.music.interfaces.IGenreClickListener
import code.name.monkey.retromusic.model.Artist import io.github.muntashirakon.music.model.*
import code.name.monkey.retromusic.model.Home import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil
class HomeAdapter(private val activity: AppCompatActivity) : class HomeAdapter(
RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener { private val activity: AppCompatActivity
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener,
IGenreClickListener {
private var list = listOf<Home>() private var list = listOf<Home>()
@ -133,7 +134,6 @@ class HomeAdapter(private val activity: AppCompatActivity) :
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,7 +144,6 @@ class HomeAdapter(private val activity: AppCompatActivity) :
} }
} }
@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)
@ -155,7 +154,6 @@ class HomeAdapter(private val activity: AppCompatActivity) :
} }
} }
@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)
@ -163,7 +161,7 @@ class HomeAdapter(private val activity: AppCompatActivity) :
val songAdapter = SongAdapter( val songAdapter = SongAdapter(
activity, activity,
home.arrayList as MutableList<Song>, home.arrayList as MutableList<Song>,
R.layout.item_favourite_card R.layout.item_favourite_card, null
) )
layoutManager = linearLayoutManager() layoutManager = linearLayoutManager()
adapter = songAdapter adapter = songAdapter
@ -174,14 +172,15 @@ class HomeAdapter(private val activity: AppCompatActivity) :
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, this) ArtistAdapter(activity, artists, PreferenceUtil.homeArtistGridStyle, null, this)
private fun albumAdapter(albums: List<Album>) = private fun albumAdapter(albums: List<Album>) =
AlbumAdapter(activity, albums, PreferenceUtil.homeAlbumGridStyle, this) AlbumAdapter(activity, albums, PreferenceUtil.homeAlbumGridStyle, null, this)
private fun gridLayoutManager() = private fun gridLayoutManager() =
GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false) GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
@ -210,4 +209,16 @@ class HomeAdapter(private val activity: AppCompatActivity) :
) )
) )
} }
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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter package io.github.muntashirakon.music.adapter
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.view.LayoutInflater import android.view.LayoutInflater
@ -26,21 +26,18 @@ import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController 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 io.github.muntashirakon.music.*
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.db.PlaylistWithSongs import io.github.muntashirakon.music.db.PlaylistWithSongs
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.albumCoverOptions import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.artistImageOptions import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.helper.MusicPlayerRemote import io.github.muntashirakon.music.model.Album
import code.name.monkey.retromusic.helper.menu.SongMenuHelper import io.github.muntashirakon.music.model.Artist
import code.name.monkey.retromusic.model.Album import io.github.muntashirakon.music.model.Genre
import code.name.monkey.retromusic.model.Artist import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.model.Genre import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import com.bumptech.glide.Glide
import java.util.* import java.util.*
class SearchAdapter( class SearchAdapter(
@ -63,29 +60,27 @@ class SearchAdapter(
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return when (viewType) { return if (viewType == HEADER) ViewHolder(
HEADER -> ViewHolder(
LayoutInflater.from(activity).inflate( LayoutInflater.from(activity).inflate(
R.layout.sub_header, R.layout.sub_header,
parent, parent,
false false
), viewType ), viewType
) )
else if (viewType == ALBUM || viewType == ARTIST || viewType== ALBUM_ARTIST)
ALBUM, ARTIST, ALBUM_ARTIST -> ViewHolder( 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
else -> ViewHolder( 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) {
when (getItemViewType(position)) { when (getItemViewType(position)) {
@ -94,30 +89,24 @@ 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
Glide.with(activity).asDrawable().albumCoverOptions(album.safeGetFirstSong()) GlideApp.with(activity).asDrawable().albumCoverOptions(album.safeGetFirstSong()).load(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)
Glide.with(activity).asDrawable().artistImageOptions(artist).load( GlideApp.with(activity).asDrawable().artistImageOptions(artist).load(
RetroGlideExtension.getArtistModel(artist) RetroGlideExtension.getArtistModel(artist)).into(holder.image!!)
).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
Glide.with(activity).asDrawable().songCoverOptions(song) GlideApp.with(activity).asDrawable().songCoverOptions(song).load(RetroGlideExtension.getSongModel(song)).into(holder.image!!)
.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
@ -130,23 +119,19 @@ 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)
Glide.with(activity).asDrawable().artistImageOptions(artist).load( GlideApp.with(activity).asDrawable().artistImageOptions(artist).load(
RetroGlideExtension.getArtistModel(artist) RetroGlideExtension.getArtistModel(artist)).into(holder.image!!)
).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))
@ -192,35 +177,30 @@ 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_ID to (item as PlaylistWithSongs).playlistEntity.playListId) bundleOf(EXTRA_PLAYLIST to (item as PlaylistWithSongs))
) )
} }
SONG -> { SONG -> {
MusicPlayerRemote.playNext(item as Song) MusicPlayerRemote.playNext(item as Song)
MusicPlayerRemote.playNextSong() MusicPlayerRemote.playNextSong()

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter package io.github.muntashirakon.music.adapter
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.view.LayoutInflater import android.view.LayoutInflater
@ -22,14 +22,16 @@ import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible import androidx.core.view.isVisible
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.extensions.getTintedDrawable import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.audiocover.AudioFileCover import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.interfaces.ICallbacks import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.glide.audiocover.AudioFileCover
import com.bumptech.glide.Glide import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.interfaces.ICallbacks
import io.github.muntashirakon.music.util.MusicUtil
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
@ -42,9 +44,10 @@ 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, R.menu.menu_media_selection activity, iCabHolder, R.menu.menu_media_selection
), PopupTextProvider { ), PopupTextProvider {
init { init {
@ -94,7 +97,7 @@ class SongFileAdapter(
} }
private fun loadFileImage(file: File, holder: ViewHolder) { private fun loadFileImage(file: File, holder: ViewHolder) {
val iconColor = ATHUtil.resolveColor(activity, androidx.appcompat.R.attr.colorControlNormal) val iconColor = ATHUtil.resolveColor(activity, R.attr.colorControlNormal)
if (file.isDirectory) { if (file.isDirectory) {
holder.image?.let { holder.image?.let {
it.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN) it.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN)
@ -103,12 +106,12 @@ class SongFileAdapter(
holder.imageTextContainer?.setCardBackgroundColor( holder.imageTextContainer?.setCardBackgroundColor(
ATHUtil.resolveColor( ATHUtil.resolveColor(
activity, activity,
com.google.android.material.R.attr.colorSurface R.attr.colorSurface
) )
) )
} else { } else {
val error = activity.getTintedDrawable(R.drawable.ic_audio_file, iconColor) val error = activity.getTintedDrawable(R.drawable.ic_file_music, iconColor)
Glide.with(activity) GlideApp.with(activity)
.load(AudioFileCover(file.path)) .load(AudioFileCover(file.path))
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)
.error(error) .error(error)
@ -144,7 +147,7 @@ class SongFileAdapter(
return MusicUtil.getSectionName(dataSet[position].name) return MusicUtil.getSectionName(dataSet[position].name)
} }
inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init { init {
if (menu != null && iCallbacks != null) { if (menu != null && iCallbacks != null) {

View file

@ -1,11 +1,11 @@
package code.name.monkey.retromusic.adapter package io.github.muntashirakon.music.adapter
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.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import java.io.File import java.io.File
class StorageAdapter( class StorageAdapter(

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.album package io.github.muntashirakon.music.adapter.album
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.view.LayoutInflater import android.view.LayoutInflater
@ -21,31 +21,32 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.albumCoverOptions import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.helper.SortOrder
import code.name.monkey.retromusic.helper.SortOrder import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import io.github.muntashirakon.music.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.IAlbumClickListener import io.github.muntashirakon.music.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Album import io.github.muntashirakon.music.model.Album
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import io.github.muntashirakon.music.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,9 +113,7 @@ open class AlbumAdapter(
return return
} }
val song = album.safeGetFirstSong() val song = album.safeGetFirstSong()
Glide.with(activity) GlideApp.with(activity).asBitmapPalette().albumCoverOptions(song)
.asBitmapPalette()
.albumCoverOptions(song)
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.into(object : RetroMusicColoredTarget(holder.image!!) { .into(object : RetroMusicColoredTarget(holder.image!!) {
@ -164,7 +163,6 @@ 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

View file

@ -12,33 +12,30 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.album package io.github.muntashirakon.music.adapter.album
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.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
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.MainActivity import io.github.muntashirakon.music.activities.MainActivity
import code.name.monkey.retromusic.fragments.AlbumCoverStyle import io.github.muntashirakon.music.fragments.AlbumCoverStyle
import code.name.monkey.retromusic.fragments.NowPlayingScreen.* import io.github.muntashirakon.music.fragments.NowPlayingScreen.*
import code.name.monkey.retromusic.fragments.base.goToLyrics import io.github.muntashirakon.music.fragments.base.goToLyrics
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.misc.CustomFragmentStatePagerAdapter
import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.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
@ -98,7 +95,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 = BundleCompat.getParcelable(requireArguments(), SONG_ARG, Song::class.java)!! song = requireArguments().getParcelable(SONG_ARG)!!
} }
} }
@ -122,7 +119,7 @@ class AlbumCoverPagerAdapter(
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
MaterialAlertDialogBuilder( MaterialAlertDialogBuilder(
requireContext(), requireContext(),
com.google.android.material.R.style.ThemeOverlay_MaterialComponents_Dialog_Alert 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)
@ -167,9 +164,7 @@ class AlbumCoverPagerAdapter(
} }
private fun loadAlbumCover(albumCover: ImageView) { private fun loadAlbumCover(albumCover: ImageView) {
Glide.with(this) GlideApp.with(this).asBitmapPalette().songCoverOptions(song)
.asBitmapPalette()
.songCoverOptions(song)
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.dontAnimate() .dontAnimate()

View file

@ -12,28 +12,28 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.album package io.github.muntashirakon.music.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.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.albumCoverOptions import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.helper.HorizontalAdapterHelper
import code.name.monkey.retromusic.helper.HorizontalAdapterHelper import io.github.muntashirakon.music.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.IAlbumClickListener import io.github.muntashirakon.music.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Album import io.github.muntashirakon.music.model.Album
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import io.github.muntashirakon.music.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, albumClickListener activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, ICabHolder, albumClickListener
) { ) {
override fun createViewHolder(view: View, viewType: Int): ViewHolder { override fun createViewHolder(view: View, viewType: Int): ViewHolder {
@ -49,9 +49,7 @@ 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
Glide.with(activity) GlideApp.with(activity).asBitmapPalette().albumCoverOptions(album.safeGetFirstSong())
.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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.artist package io.github.muntashirakon.music.adapter.artist
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.res.ColorStateList import android.content.res.ColorStateList
@ -23,32 +23,34 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.extensions.hide import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.extensions.hide
import code.name.monkey.retromusic.glide.RetroGlideExtension.artistImageOptions import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.IAlbumArtistClickListener import io.github.muntashirakon.music.interfaces.IAlbumArtistClickListener
import code.name.monkey.retromusic.interfaces.IArtistClickListener import io.github.muntashirakon.music.interfaces.IArtistClickListener
import code.name.monkey.retromusic.model.Artist import io.github.muntashirakon.music.interfaces.ICabHolder
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.model.Artist
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import io.github.muntashirakon.music.util.PreferenceUtil
import com.bumptech.glide.Glide import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
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>(activity, R.menu.menu_media_selection), ) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>(
PopupTextProvider { activity, ICabHolder, R.menu.menu_media_selection
), PopupTextProvider {
var albumArtistsOnly = false var albumArtistsOnly = false
@ -110,10 +112,10 @@ class ArtistAdapter(
if (holder.image == null) { if (holder.image == null) {
return return
} }
Glide.with(activity) GlideApp.with(activity)
.asBitmapPalette() .asBitmapPalette()
.artistImageOptions(artist)
.load(RetroGlideExtension.getArtistModel(artist)) .load(RetroGlideExtension.getArtistModel(artist))
.artistImageOptions(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) {
@ -157,7 +159,7 @@ class ArtistAdapter(
return MusicUtil.getSectionName(dataSet[position].name) return MusicUtil.getSectionName(dataSet[position].name)
} }
inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init { init {
menu?.isVisible = false menu?.isVisible = false

View file

@ -1,4 +1,4 @@
package code.name.monkey.retromusic.adapter.backup package io.github.muntashirakon.music.adapter.backup
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.view.LayoutInflater import android.view.LayoutInflater
@ -7,8 +7,8 @@ import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.databinding.ItemListBackupBinding import io.github.muntashirakon.music.databinding.ItemListBackupBinding
import java.io.File import java.io.File

View file

@ -0,0 +1,125 @@
package io.github.muntashirakon.music.adapter.base
import android.annotation.SuppressLint
import android.graphics.Color
import android.view.Menu
import android.view.MenuItem
import androidx.annotation.MenuRes
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.util.VersionUtils
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.extensions.surfaceColor
import io.github.muntashirakon.music.interfaces.ICabCallback
import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.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>(
open val activity: FragmentActivity, private val ICabHolder: ICabHolder?, @MenuRes menuRes: Int
) : RecyclerView.Adapter<V>(), ICabCallback {
private var cab: AttachedCab? = null
private val checked: MutableList<I>
private var menuRes: Int
override fun onCabCreated(cab: AttachedCab, menu: Menu): Boolean {
activity.window.statusBarColor =
RetroColorUtil.shiftBackgroundColor(activity.surfaceColor())
return true
}
override fun onCabFinished(cab: AttachedCab): Boolean {
clearChecked()
activity.window.statusBarColor = when {
VersionUtils.hasMarshmallow() -> Color.TRANSPARENT
else -> Color.BLACK
}
return true
}
override fun onCabItemClicked(item: MenuItem): Boolean {
if (item.itemId == R.id.action_multi_select_adapter_check_all) {
checkAll()
} else {
onMultipleItemAction(item, ArrayList(checked))
cab?.destroy()
clearChecked()
}
return true
}
private fun checkAll() {
if (ICabHolder != null) {
checked.clear()
for (i in 0 until itemCount) {
val identifier = getIdentifier(i)
if (identifier != null) {
checked.add(identifier)
}
}
notifyDataSetChanged()
updateCab()
}
}
protected abstract fun getIdentifier(position: Int): I?
protected abstract fun getName(model: I): String?
protected fun isChecked(identifier: I): Boolean {
return checked.contains(identifier)
}
protected val isInQuickSelectMode: Boolean
get() = cab != null && cab!!.isActive()
protected abstract fun onMultipleItemAction(menuItem: MenuItem, selection: List<I>)
protected fun setMultiSelectMenuRes(@MenuRes menuRes: Int) {
this.menuRes = menuRes
}
protected fun toggleChecked(position: Int): Boolean {
if (ICabHolder != null) {
val identifier = getIdentifier(position) ?: return false
if (!checked.remove(identifier)) {
checked.add(identifier)
}
notifyItemChanged(position)
updateCab()
return true
}
return false
}
private fun clearChecked() {
checked.clear()
notifyDataSetChanged()
}
@SuppressLint("StringFormatInvalid", "StringFormatMatches")
private fun updateCab() {
if (ICabHolder != null) {
if (cab == null || !cab!!.isActive()) {
cab = ICabHolder.openCab(menuRes, this)
}
val size = checked.size
when {
size <= 0 -> {
cab?.destroy()
}
size == 1 -> {
cab?.title(literal = getName(checked[0]))
}
else -> {
cab?.title(literal = activity.getString(R.string.x_selected, size))
}
}
}
}
init {
checked = ArrayList()
this.menuRes = menuRes
}
}

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
package code.name.monkey.retromusic.adapter.base; package io.github.muntashirakon.music.adapter.base;
import android.graphics.Color; import android.graphics.Color;
import android.view.View; import android.view.View;
@ -27,7 +27,7 @@ import androidx.appcompat.widget.AppCompatImageView;
import com.google.android.material.card.MaterialCardView; import com.google.android.material.card.MaterialCardView;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableSwipeableItemViewHolder; import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableSwipeableItemViewHolder;
import code.name.monkey.retromusic.R; import io.github.muntashirakon.music.R;
public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHolder public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHolder
implements View.OnLongClickListener, View.OnClickListener { implements View.OnLongClickListener, View.OnClickListener {

View file

@ -12,15 +12,16 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.playlist package io.github.muntashirakon.music.adapter.playlist
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 androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.model.Playlist import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.model.Playlist
import io.github.muntashirakon.music.util.MusicUtil
class LegacyPlaylistAdapter( class LegacyPlaylistAdapter(
private val activity: FragmentActivity, private val activity: FragmentActivity,
@ -35,7 +36,7 @@ class LegacyPlaylistAdapter(
notifyDataSetChanged() notifyDataSetChanged()
} }
class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView)
override fun onCreateViewHolder( override fun onCreateViewHolder(
parent: ViewGroup, parent: ViewGroup,

View file

@ -12,10 +12,9 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.playlist package io.github.muntashirakon.music.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
@ -24,33 +23,34 @@ 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 io.github.muntashirakon.music.R
import code.name.monkey.appthemehelper.util.TintHelper import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import io.github.muntashirakon.music.db.PlaylistEntity
import code.name.monkey.retromusic.db.PlaylistEntity import io.github.muntashirakon.music.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.PlaylistWithSongs import io.github.muntashirakon.music.db.toSongs
import code.name.monkey.retromusic.db.toSongs import io.github.muntashirakon.music.extensions.dipToPix
import code.name.monkey.retromusic.extensions.dipToPix import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.playlistOptions import io.github.muntashirakon.music.glide.playlistPreview.PlaylistPreview
import code.name.monkey.retromusic.glide.playlistPreview.PlaylistPreview import io.github.muntashirakon.music.helper.SortOrder.PlaylistSortOrder
import code.name.monkey.retromusic.helper.SortOrder.PlaylistSortOrder import io.github.muntashirakon.music.helper.menu.PlaylistMenuHelper
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import io.github.muntashirakon.music.interfaces.ICabHolder
import code.name.monkey.retromusic.interfaces.IPlaylistClickListener import io.github.muntashirakon.music.interfaces.IPlaylistClickListener
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.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 {
@ -72,7 +72,7 @@ class PlaylistAdapter(
return createViewHolder(view) return createViewHolder(view)
} }
private fun createViewHolder(view: View): ViewHolder { fun createViewHolder(view: View): ViewHolder {
return ViewHolder(view) return ViewHolder(view)
} }
@ -101,22 +101,16 @@ 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)
.load(
if (itemLayoutRes == R.layout.item_list) { if (itemLayoutRes == R.layout.item_list) {
holder.image?.setPadding(activity.dipToPix(8F).toInt()) holder.image?.setPadding(activity.dipToPix(8F).toInt())
holder.image?.setImageDrawable(getIconRes()) R.drawable.ic_playlist_play
} else { } else PlaylistPreview(playlist)
Glide.with(activity) )
.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
@ -148,7 +142,7 @@ class PlaylistAdapter(
return songs return songs
} }
inner class ViewHolder(itemView: View) : code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init { init {
menu?.setOnClickListener { view -> menu?.setOnClickListener { view ->
val popupMenu = PopupMenu(activity, view) val popupMenu = PopupMenu(activity, view)

View file

@ -12,22 +12,24 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.song package io.github.muntashirakon.music.adapter.song
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 androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.model.Song
abstract class AbsOffsetSongAdapter( abstract class AbsOffsetSongAdapter(
activity: FragmentActivity, activity: FragmentActivity,
dataSet: MutableList<Song>, dataSet: MutableList<Song>,
@LayoutRes itemLayoutRes: Int @LayoutRes itemLayoutRes: Int,
) : SongAdapter(activity, dataSet, itemLayoutRes) { ICabHolder: ICabHolder?
) : 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

@ -12,21 +12,25 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.song package io.github.muntashirakon.music.adapter.song
import android.view.MenuItem import android.view.MenuItem
import android.view.View 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 androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.db.PlaylistEntity import io.github.muntashirakon.music.db.PlaylistEntity
import code.name.monkey.retromusic.db.toSongEntity import io.github.muntashirakon.music.db.toSongEntity
import code.name.monkey.retromusic.db.toSongsEntity import io.github.muntashirakon.music.db.toSongsEntity
import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog import io.github.muntashirakon.music.dialogs.RemoveSongFromPlaylistDialog
import code.name.monkey.retromusic.fragments.LibraryViewModel import io.github.muntashirakon.music.extensions.accentColor
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.extensions.accentOutlineColor
import code.name.monkey.retromusic.util.ViewUtil import io.github.muntashirakon.music.fragments.LibraryViewModel
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.ICabHolder
import io.github.muntashirakon.music.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
@ -34,11 +38,12 @@ 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 playlistId: Long, private val playlist: PlaylistEntity,
activity: FragmentActivity, activity: FragmentActivity,
dataSet: MutableList<Song>, dataSet: MutableList<Song>,
itemLayoutRes: Int, itemLayoutRes: Int,
) : SongAdapter(activity, dataSet, itemLayoutRes), ICabHolder: ICabHolder?,
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, ICabHolder),
DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> { DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
val libraryViewModel: LibraryViewModel by activity.viewModel() val libraryViewModel: LibraryViewModel by activity.viewModel()
@ -51,27 +56,56 @@ class OrderablePlaylistSongAdapter(
override fun getItemId(position: Int): Long { override fun getItemId(position: Int): Long {
// requires static value, it means need to keep the same value // requires static value, it means need to keep the same value
// even if the item position has been changed. // even if the item position has been changed.
return dataSet[position].id return if (position != 0) {
dataSet[position - 1].id
} else {
-1
}
} }
override fun createViewHolder(view: View): SongAdapter.ViewHolder { override fun createViewHolder(view: View): SongAdapter.ViewHolder {
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(
playlistId playlist
) )
) )
.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) : SongAdapter.ViewHolder(itemView) { inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) {
val playAction: MaterialButton? = itemView.findViewById(R.id.playAction)
val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction)
override var songMenuRes: Int override var songMenuRes: Int
get() = R.menu.menu_item_playlist_song get() = R.menu.menu_item_playlist_song
@ -82,7 +116,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(playlistId)) RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlist.playListId))
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
return true return true
} }
@ -96,22 +130,26 @@ class OrderablePlaylistSongAdapter(
} }
override fun onCheckCanStartDrag(holder: ViewHolder, position: Int, x: Int, y: Int): Boolean { override fun onCheckCanStartDrag(holder: ViewHolder, position: Int, x: Int, y: Int): Boolean {
if (isInQuickSelectMode) { if (dataSet.size == 0 or 1 || isInQuickSelectMode) {
return false return false
} }
return ViewUtil.hitTest(holder.imageText!!, x, y) || ViewUtil.hitTest( val dragHandle = holder.dragView ?: return false
holder.dragView!!,
x, val handleWidth = dragHandle.width
y val handleHeight = dragHandle.height
) val handleLeft = dragHandle.left
val handleTop = dragHandle.top
return (x >= handleLeft && x < handleLeft + handleWidth &&
y >= handleTop && y < handleTop + handleHeight) && position != 0
} }
override fun onMoveItem(fromPosition: Int, toPosition: Int) { override fun onMoveItem(fromPosition: Int, toPosition: Int) {
dataSet.add(toPosition, dataSet.removeAt(fromPosition)) dataSet.add(toPosition - 1, dataSet.removeAt(fromPosition - 1))
} }
override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange? { override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange {
return null return ItemDraggableRange(1, itemCount - 1)
} }
override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean { override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean {

View file

@ -12,23 +12,22 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.song package io.github.muntashirakon.music.adapter.song
import android.view.MenuItem import android.view.MenuItem
import android.view.View 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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicPlayerRemote.isPlaying import io.github.muntashirakon.music.helper.MusicPlayerRemote.isPlaying
import code.name.monkey.retromusic.helper.MusicPlayerRemote.playNextSong import io.github.muntashirakon.music.helper.MusicPlayerRemote.playNextSong
import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue import io.github.muntashirakon.music.helper.MusicPlayerRemote.removeFromQueue
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.ViewUtil import io.github.muntashirakon.music.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
@ -43,9 +42,10 @@ 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(activity, dataSet, itemLayoutRes), ) : SongAdapter(
DraggableItemAdapter<PlayingQueueAdapter.ViewHolder>, activity, dataSet, itemLayoutRes, null
), 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
} }
Glide.with(activity) GlideApp.with(activity)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.songCoverOptions(song) .songCoverOptions(song)
.into(holder.image!!) .into(holder.image!!)
@ -153,14 +153,6 @@ 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 -> {
@ -196,7 +188,7 @@ class PlayingQueueAdapter(
return if (result == SwipeableItemConstants.RESULT_CANCELED) { return if (result == SwipeableItemConstants.RESULT_CANCELED) {
SwipeResultActionDefault() SwipeResultActionDefault()
} else { } else {
SwipedResultActionRemoveItem(this, position) SwipedResultActionRemoveItem(this, position, activity)
} }
} }
@ -217,9 +209,12 @@ 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

@ -12,25 +12,27 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.song package io.github.muntashirakon.music.adapter.song
import android.view.View 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 io.github.muntashirakon.music.R
import code.name.monkey.retromusic.extensions.accentColor import io.github.muntashirakon.music.extensions.accentColor
import code.name.monkey.retromusic.extensions.accentOutlineColor import io.github.muntashirakon.music.extensions.accentOutlineColor
import code.name.monkey.retromusic.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.interfaces.ICabHolder
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.util.RetroUtil import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil
import com.google.android.material.button.MaterialButton 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,
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes) { ICabHolder: ICabHolder?
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, ICabHolder) {
override fun createViewHolder(view: View): SongAdapter.ViewHolder { override fun createViewHolder(view: View): SongAdapter.ViewHolder {

View file

@ -12,19 +12,22 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.song package io.github.muntashirakon.music.adapter.song
import android.view.LayoutInflater import android.view.LayoutInflater
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.model.Song import io.github.muntashirakon.music.interfaces.ICabHolder
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.MusicUtil
class SimpleSongAdapter( class SimpleSongAdapter(
context: FragmentActivity, context: FragmentActivity,
songs: ArrayList<Song>, songs: ArrayList<Song>,
layoutRes: Int layoutRes: Int,
) : SongAdapter(context, songs, layoutRes) { ICabHolder: ICabHolder?
) : 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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.adapter.song package io.github.muntashirakon.music.adapter.song
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.Resources import android.content.res.Resources
@ -25,24 +25,24 @@ import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController import androidx.navigation.findNavController
import code.name.monkey.retromusic.EXTRA_ALBUM_ID import io.github.muntashirakon.music.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.SortOrder
import code.name.monkey.retromusic.helper.SortOrder import io.github.muntashirakon.music.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.helper.menu.SongMenuHelper import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import io.github.muntashirakon.music.interfaces.ICabCallback
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.interfaces.ICabHolder
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.RetroUtil import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import io.github.muntashirakon.music.util.RetroUtil
import com.bumptech.glide.Glide import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
import me.zhanghai.android.fastscroll.PopupTextProvider import me.zhanghai.android.fastscroll.PopupTextProvider
/** /**
@ -53,11 +53,13 @@ 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
), PopupTextProvider { ), ICabCallback, PopupTextProvider {
private var showSectionName = true private var showSectionName = true
@ -118,9 +120,7 @@ open class SongAdapter(
if (holder.image == null) { if (holder.image == null) {
return return
} }
Glide.with(activity) GlideApp.with(activity).asBitmapPalette().songCoverOptions(song)
.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) {
@ -159,11 +159,6 @@ 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
@ -221,7 +216,6 @@ 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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appshortcuts package io.github.muntashirakon.music.appshortcuts
import android.content.Context import android.content.Context
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
@ -22,9 +22,9 @@ import android.util.TypedValue
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.extensions.getTintedDrawable import io.github.muntashirakon.music.extensions.getTintedDrawable
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
@RequiresApi(Build.VERSION_CODES.N_MR1) @RequiresApi(Build.VERSION_CODES.N_MR1)
object AppShortcutIconGenerator { object AppShortcutIconGenerator {

View file

@ -12,26 +12,26 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appshortcuts package io.github.muntashirakon.music.appshortcuts
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType import io.github.muntashirakon.music.appshortcuts.shortcuttype.LastAddedShortcutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType import io.github.muntashirakon.music.appshortcuts.shortcuttype.ShuffleAllShortcutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType import io.github.muntashirakon.music.appshortcuts.shortcuttype.TopTracksShortcutType
import code.name.monkey.retromusic.extensions.extraNotNull import io.github.muntashirakon.music.extensions.extraNotNull
import code.name.monkey.retromusic.model.Playlist import io.github.muntashirakon.music.model.Playlist
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist import io.github.muntashirakon.music.model.smartplaylist.LastAddedPlaylist
import code.name.monkey.retromusic.model.smartplaylist.ShuffleAllPlaylist import io.github.muntashirakon.music.model.smartplaylist.ShuffleAllPlaylist
import code.name.monkey.retromusic.model.smartplaylist.TopTracksPlaylist import io.github.muntashirakon.music.model.smartplaylist.TopTracksPlaylist
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_PLAY_PLAYLIST import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_PLAY_PLAYLIST
import code.name.monkey.retromusic.service.MusicService.Companion.INTENT_EXTRA_PLAYLIST import io.github.muntashirakon.music.service.MusicService.Companion.INTENT_EXTRA_PLAYLIST
import code.name.monkey.retromusic.service.MusicService.Companion.INTENT_EXTRA_SHUFFLE_MODE import io.github.muntashirakon.music.service.MusicService.Companion.INTENT_EXTRA_SHUFFLE_MODE
import code.name.monkey.retromusic.service.MusicService.Companion.SHUFFLE_MODE_NONE import io.github.muntashirakon.music.service.MusicService.Companion.SHUFFLE_MODE_NONE
import code.name.monkey.retromusic.service.MusicService.Companion.SHUFFLE_MODE_SHUFFLE import io.github.muntashirakon.music.service.MusicService.Companion.SHUFFLE_MODE_SHUFFLE
class AppShortcutLauncherActivity : Activity() { class AppShortcutLauncherActivity : Activity() {

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appshortcuts package io.github.muntashirakon.music.appshortcuts
import android.annotation.TargetApi import android.annotation.TargetApi
import android.content.Context import android.content.Context
@ -22,9 +22,9 @@ import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.os.Build import android.os.Build
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType import io.github.muntashirakon.music.appshortcuts.shortcuttype.LastAddedShortcutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType import io.github.muntashirakon.music.appshortcuts.shortcuttype.ShuffleAllShortcutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType import io.github.muntashirakon.music.appshortcuts.shortcuttype.TopTracksShortcutType
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
class DynamicShortcutManager(private val context: Context) { class DynamicShortcutManager(private val context: Context) {

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appshortcuts.shortcuttype package io.github.muntashirakon.music.appshortcuts.shortcuttype
import android.annotation.TargetApi import android.annotation.TargetApi
import android.content.Context import android.content.Context
@ -20,7 +20,7 @@ import android.content.Intent
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.os.Build import android.os.Build
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity import io.github.muntashirakon.music.appshortcuts.AppShortcutLauncherActivity
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
abstract class BaseShortcutType(internal var context: Context) { abstract class BaseShortcutType(internal var context: Context) {

View file

@ -12,15 +12,15 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appshortcuts.shortcuttype package io.github.muntashirakon.music.appshortcuts.shortcuttype
import android.annotation.TargetApi import android.annotation.TargetApi
import android.content.Context import android.content.Context
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.os.Build import android.os.Build
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator import io.github.muntashirakon.music.appshortcuts.AppShortcutIconGenerator
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity import io.github.muntashirakon.music.appshortcuts.AppShortcutLauncherActivity
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
class LastAddedShortcutType(context: Context) : BaseShortcutType(context) { class LastAddedShortcutType(context: Context) : BaseShortcutType(context) {

View file

@ -12,15 +12,15 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appshortcuts.shortcuttype package io.github.muntashirakon.music.appshortcuts.shortcuttype
import android.annotation.TargetApi import android.annotation.TargetApi
import android.content.Context import android.content.Context
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.os.Build import android.os.Build
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator import io.github.muntashirakon.music.appshortcuts.AppShortcutIconGenerator
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity import io.github.muntashirakon.music.appshortcuts.AppShortcutLauncherActivity
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
class ShuffleAllShortcutType(context: Context) : BaseShortcutType(context) { class ShuffleAllShortcutType(context: Context) : BaseShortcutType(context) {

View file

@ -11,15 +11,15 @@
* 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.appshortcuts.shortcuttype package io.github.muntashirakon.music.appshortcuts.shortcuttype
import android.annotation.TargetApi import android.annotation.TargetApi
import android.content.Context import android.content.Context
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.os.Build import android.os.Build
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator import io.github.muntashirakon.music.appshortcuts.AppShortcutIconGenerator
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity import io.github.muntashirakon.music.appshortcuts.AppShortcutLauncherActivity
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
class TopTracksShortcutType(context: Context) : BaseShortcutType(context) { class TopTracksShortcutType(context: Context) : BaseShortcutType(context) {

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
@ -25,17 +25,18 @@ import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.MainActivity import io.github.muntashirakon.music.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import io.github.muntashirakon.music.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import io.github.muntashirakon.music.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.util.RetroUtil import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
@ -151,7 +152,7 @@ class AppWidgetBig : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = Glide.with(appContext) target = GlideApp.with(appContext)
.asBitmap() .asBitmap()
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
@ -25,19 +25,18 @@ import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.MainActivity import io.github.muntashirakon.music.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import io.github.muntashirakon.music.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import io.github.muntashirakon.music.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
@ -144,9 +143,7 @@ class AppWidgetCard : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = Glide.with(service) target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
@ -24,20 +24,19 @@ import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.MainActivity import io.github.muntashirakon.music.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import io.github.muntashirakon.music.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import io.github.muntashirakon.music.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE import io.github.muntashirakon.music.service.MusicService.Companion.TOGGLE_FAVORITE
import code.name.monkey.retromusic.service.MusicService.Companion.TOGGLE_FAVORITE import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.util.RetroUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.target.CustomTarget
@ -90,7 +89,7 @@ class AppWidgetCircle : BaseAppWidget() {
).toBitmap() ).toBitmap()
) )
val isFavorite = runBlocking(Dispatchers.IO) { val isFavorite = runBlocking(Dispatchers.IO) {
return@runBlocking MusicUtil.isFavorite(song) return@runBlocking MusicUtil.repository.isSongFavorite(song.id)
} }
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
@ -115,9 +114,7 @@ class AppWidgetCircle : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = Glide.with(service) target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
@ -26,19 +26,18 @@ import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.MainActivity import io.github.muntashirakon.music.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import io.github.muntashirakon.music.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import io.github.muntashirakon.music.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
@ -120,9 +119,7 @@ class AppWidgetClassic : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = Glide.with(service) target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.asBitmapPalette()
.songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.centerCrop() .centerCrop()

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
@ -25,20 +25,19 @@ import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.MainActivity import io.github.muntashirakon.music.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import io.github.muntashirakon.music.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import io.github.muntashirakon.music.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE import io.github.muntashirakon.music.util.DensityUtil
import code.name.monkey.retromusic.util.DensityUtil import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
@ -145,9 +144,7 @@ class AppWidgetMD3 : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = Glide.with(service) target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.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

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
@ -25,19 +25,18 @@ import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.MainActivity import io.github.muntashirakon.music.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import io.github.muntashirakon.music.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import io.github.muntashirakon.music.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.RetroGlideExtension import io.github.muntashirakon.music.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension.asBitmapPalette import io.github.muntashirakon.music.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE import io.github.muntashirakon.music.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
@ -123,9 +122,7 @@ class AppWidgetSmall : BaseAppWidget() {
if (target != null) { if (target != null) {
Glide.with(service).clear(target) Glide.with(service).clear(target)
} }
target = Glide.with(service) target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.asBitmapPalette()
.songCoverOptions(song)
//.checkIgnoreMediaStore() //.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song)) .load(RetroGlideExtension.getSongModel(song))
.centerCrop() .centerCrop()

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appwidgets package io.github.muntashirakon.music.appwidgets
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
@ -23,15 +23,15 @@ import android.widget.RemoteViews
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.activities.MainActivity import io.github.muntashirakon.music.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget import io.github.muntashirakon.music.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.extensions.getTintedDrawable import io.github.muntashirakon.music.extensions.getTintedDrawable
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE import io.github.muntashirakon.music.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
class AppWidgetText : BaseAppWidget() { class AppWidgetText : BaseAppWidget() {
override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) { override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) {
@ -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, code.name.monkey.appthemehelper.R.color.md_white_1000 context, 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, code.name.monkey.appthemehelper.R.color.md_white_1000 context, 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, code.name.monkey.appthemehelper.R.color.md_white_1000 context, R.color.md_white_1000
) )
).toBitmap() ).toBitmap()
) )
appWidgetView.setTextColor( appWidgetView.setTextColor(
R.id.title, ContextCompat.getColor(context, code.name.monkey.appthemehelper.R.color.md_white_1000) R.id.title, ContextCompat.getColor(context, R.color.md_white_1000)
) )
appWidgetView.setTextColor( appWidgetView.setTextColor(
R.id.text, ContextCompat.getColor(context, code.name.monkey.appthemehelper.R.color.md_white_1000) R.id.text, ContextCompat.getColor(context, 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, code.name.monkey.appthemehelper.R.color.md_white_1000) service, 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,
code.name.monkey.appthemehelper.R.color.md_white_1000 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, code.name.monkey.appthemehelper.R.color.md_white_1000 service, R.color.md_white_1000
) )
).toBitmap() ).toBitmap()
) )

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appwidgets package io.github.muntashirakon.music.appwidgets
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
@ -20,7 +20,7 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.service.MusicService
class BootReceiver : BroadcastReceiver() { class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
*/ */
package code.name.monkey.retromusic.appwidgets.base package io.github.muntashirakon.music.appwidgets.base
import android.app.PendingIntent import android.app.PendingIntent
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
@ -26,14 +26,14 @@ import android.graphics.drawable.Drawable
import android.widget.RemoteViews import android.widget.RemoteViews
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.APP_WIDGET_UPDATE import io.github.muntashirakon.music.service.MusicService.Companion.APP_WIDGET_UPDATE
import code.name.monkey.retromusic.service.MusicService.Companion.EXTRA_APP_WIDGET_NAME import io.github.muntashirakon.music.service.MusicService.Companion.EXTRA_APP_WIDGET_NAME
import code.name.monkey.retromusic.service.MusicService.Companion.FAVORITE_STATE_CHANGED import io.github.muntashirakon.music.service.MusicService.Companion.FAVORITE_STATE_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.META_CHANGED import io.github.muntashirakon.music.service.MusicService.Companion.META_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.PLAY_STATE_CHANGED import io.github.muntashirakon.music.service.MusicService.Companion.PLAY_STATE_CHANGED
abstract class BaseAppWidget : AppWidgetProvider() { abstract class BaseAppWidget : AppWidgetProvider() {

View file

@ -12,7 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
package code.name.monkey.retromusic.auto; package io.github.muntashirakon.music.auto;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;

View file

@ -11,19 +11,19 @@
* 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.auto package io.github.muntashirakon.music.auto
import android.content.Context import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.support.v4.media.MediaBrowserCompat import android.support.v4.media.MediaBrowserCompat
import code.name.monkey.retromusic.R import io.github.muntashirakon.music.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote import io.github.muntashirakon.music.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.CategoryInfo import io.github.muntashirakon.music.model.CategoryInfo
import code.name.monkey.retromusic.model.Song import io.github.muntashirakon.music.model.Song
import code.name.monkey.retromusic.repository.* import io.github.muntashirakon.music.repository.*
import code.name.monkey.retromusic.service.MusicService import io.github.muntashirakon.music.service.MusicService
import code.name.monkey.retromusic.util.MusicUtil import io.github.muntashirakon.music.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import io.github.muntashirakon.music.util.PreferenceUtil
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -31,7 +31,7 @@ import java.lang.ref.WeakReference
* Created by Beesham Sarendranauth (Beesham) * Created by Beesham Sarendranauth (Beesham)
*/ */
class AutoMusicProvider( class AutoMusicProvider(
private val mContext: Context, 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,

View file

@ -1,4 +1,4 @@
package code.name.monkey.retromusic.auto package io.github.muntashirakon.music.auto
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri

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