Merge branch 'dev' of https://github.com/RetroMusicPlayer/Private into dev
This commit is contained in:
commit
80739f412a
105 changed files with 2235 additions and 625 deletions
|
@ -33,7 +33,7 @@ android {
|
||||||
versionNameSuffix "_" + getDate()
|
versionNameSuffix "_" + getDate()
|
||||||
shrinkResources true
|
shrinkResources true
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
debug {
|
debug {
|
||||||
|
@ -95,7 +95,7 @@ dependencies {
|
||||||
implementation 'androidx.annotation:annotation:1.3.0'
|
implementation 'androidx.annotation:annotation:1.3.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.3.0-alpha01'
|
implementation 'androidx.recyclerview:recyclerview:1.3.0-alpha01'
|
||||||
implementation 'androidx.preference:preference-ktx:1.2.0-beta01'
|
implementation "androidx.preference:preference-ktx:$preference_version"
|
||||||
implementation 'androidx.core:core-ktx:1.7.0'
|
implementation 'androidx.core:core-ktx:1.7.0'
|
||||||
implementation 'androidx.palette:palette-ktx:1.0.0'
|
implementation 'androidx.palette:palette-ktx:1.0.0'
|
||||||
|
|
||||||
|
@ -105,12 +105,11 @@ dependencies {
|
||||||
//WebServer by NanoHttpd
|
//WebServer by NanoHttpd
|
||||||
implementation "org.nanohttpd:nanohttpd:2.3.1"
|
implementation "org.nanohttpd:nanohttpd:2.3.1"
|
||||||
|
|
||||||
def nav_version = '2.4.0-beta02'
|
implementation "androidx.navigation:navigation-runtime-ktx:$navigation_version"
|
||||||
implementation "androidx.navigation:navigation-runtime-ktx:$nav_version"
|
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
|
||||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
|
||||||
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
|
|
||||||
|
|
||||||
def room_version = '2.4.0-rc01'
|
def room_version = '2.4.0'
|
||||||
implementation "androidx.room:room-runtime:$room_version"
|
implementation "androidx.room:room-runtime:$room_version"
|
||||||
implementation "androidx.room:room-ktx:$room_version"
|
implementation "androidx.room:room-ktx:$room_version"
|
||||||
kapt "androidx.room:room-compiler:$room_version"
|
kapt "androidx.room:room-compiler:$room_version"
|
||||||
|
@ -121,7 +120,7 @@ dependencies {
|
||||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
||||||
|
|
||||||
implementation 'com.google.android.play:core-ktx:1.8.1'
|
implementation 'com.google.android.play:core-ktx:1.8.1'
|
||||||
implementation 'com.google.android.material:material:1.5.0-beta01'
|
implementation "com.google.android.material:material:$mdc_version"
|
||||||
|
|
||||||
def retrofit_version = '2.9.0'
|
def retrofit_version = '2.9.0'
|
||||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||||
|
@ -138,7 +137,7 @@ dependencies {
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
|
|
||||||
def kotlin_coroutines_version = '1.6.0-RC'
|
def kotlin_coroutines_version = '1.6.0-RC3'
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||||
|
|
||||||
|
@ -153,12 +152,13 @@ dependencies {
|
||||||
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
|
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
|
||||||
|
|
||||||
implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5'
|
implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5'
|
||||||
implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3'
|
implementation 'com.github.Adonai:jaudiotagger:2.3.15'
|
||||||
implementation 'com.anjlab.android.iab.v3:library:2.0.3'
|
implementation 'com.anjlab.android.iab.v3:library:2.0.3'
|
||||||
implementation 'com.r0adkll:slidableactivity:2.1.0'
|
implementation 'com.r0adkll:slidableactivity:2.1.0'
|
||||||
implementation 'com.heinrichreimersoftware:material-intro:2.0.0'
|
implementation 'com.heinrichreimersoftware:material-intro:2.0.0'
|
||||||
implementation 'com.github.dhaval2404:imagepicker:2.1'
|
implementation 'com.github.dhaval2404:imagepicker:2.1'
|
||||||
implementation 'me.zhanghai.android.fastscroll:library:1.1.7'
|
implementation 'me.zhanghai.android.fastscroll:library:1.1.7'
|
||||||
implementation 'cat.ereza:customactivityoncrash:2.3.0'
|
implementation 'cat.ereza:customactivityoncrash:2.3.0'
|
||||||
|
implementation 'me.tankery.lib:circularSeekBar:1.3.2'
|
||||||
debugImplementation 'com.github.amitshekhariitbhu:Android-Debug-Database:1.0.6'
|
debugImplementation 'com.github.amitshekhariitbhu:Android-Debug-Database:1.0.6'
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<bool name="md3_available">true</bool>
|
<bool name="md3_available">true</bool>
|
||||||
|
<bool name="allowBackup">false</bool>
|
||||||
</resources>
|
</resources>
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".App"
|
android:name=".App"
|
||||||
android:allowBackup="true"
|
android:allowBackup="@bool/allowBackup"
|
||||||
android:configChanges="locale|layoutDirection"
|
android:configChanges="locale|layoutDirection"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
@ -123,15 +123,38 @@
|
||||||
<activity android:name=".activities.LockScreenActivity" />
|
<activity android:name=".activities.LockScreenActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".fragments.backup.RestoreActivity"
|
android:name=".fragments.backup.RestoreActivity"
|
||||||
android:exported="true">
|
android:excludeFromRecents="false"
|
||||||
|
android:exported="true"
|
||||||
|
android:label="@string/restore"
|
||||||
|
android:theme="@style/Theme.RetroMusic.Dialog">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data android:mimeType="application/octet-stream" />
|
||||||
|
<data android:mimeType="application/x-zip-compressed" />
|
||||||
|
<data android:mimeType="application/zip" />
|
||||||
|
|
||||||
<data android:scheme="file" />
|
<data android:scheme="file" />
|
||||||
|
<data android:scheme="content" />
|
||||||
<data android:mimeType="*/*" />
|
<data android:mimeType="*/*" />
|
||||||
|
<!--
|
||||||
|
Work around Android's ugly primitive PatternMatcher
|
||||||
|
implementation that can't cope with finding a . early in
|
||||||
|
the path unless it's explicitly matched.
|
||||||
|
-->
|
||||||
|
<data android:host="*" />
|
||||||
<data android:pathPattern=".*\\.rmbak" />
|
<data android:pathPattern=".*\\.rmbak" />
|
||||||
|
<data android:pathPattern=".*\\..*\\.rmbak" />
|
||||||
|
<data android:pathPattern=".*\\..*\\..*\\.rmbak" />
|
||||||
|
<data android:pathPattern=".*\\..*\\..*\\..*\\.rmbak" />
|
||||||
|
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.rmbak" />
|
||||||
|
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.rmbak" />
|
||||||
|
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.rmbak" />
|
||||||
|
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.rmbak" />
|
||||||
|
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.rmbak" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
@ -273,10 +296,9 @@
|
||||||
<service
|
<service
|
||||||
android:name=".service.MusicService"
|
android:name=".service.MusicService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true"
|
android:exported="false"
|
||||||
android:foregroundServiceType="mediaPlayback"
|
android:foregroundServiceType="mediaPlayback"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name">
|
||||||
tools:ignore="ExportedService">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.media.browse.MediaBrowserService" />
|
<action android:name="android.media.browse.MediaBrowserService" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
|
@ -24,40 +24,48 @@
|
||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<p><b><a href="https://github.com/kabouzeid/Phonograph" title="Phonograph"> Phonograph</a></b> by
|
<p><b><a href="https://github.com/kabouzeid/Phonograph" title="Phonograph"> Phonograph</a></b> by
|
||||||
Karim Abou Zeid</p>
|
Karim Abou Zeid</p>
|
||||||
<p><b><a href="https://github.com/afollestad" title="Material Dialogs"> Material Dialogs and Cab</a></b>
|
|
||||||
by Aidan Michael Follestad</p>
|
|
||||||
<p><b><a href="http://developer.android.com/tools/support-library/index.html"
|
<p><b><a href="http://developer.android.com/tools/support-library/index.html"
|
||||||
title="AOSP Support Libraries"> AOSP Support Libraries</a></b>by AOSP contributors</p>
|
title="AOSP Support Libraries">AOSP Support Libraries</a></b> by AOSP contributors</p>
|
||||||
<p><b><a href="https://github.com/bumptech/glide" title="Glide"> Glide</a></b> by Sam Judd</p>
|
<p><b><a href="https://github.com/bumptech/glide" title="Glide"> Glide</a></b> by Sam Judd</p>
|
||||||
<p><b><a href="https://github.com/square/retrofit" title="Retrofit"> Retrofit</a></b> by Square team
|
<p><b><a href="https://github.com/square/retrofit" title="Retrofit"> Retrofit</a></b> by Square team
|
||||||
</p>
|
</p>
|
||||||
|
<p><b><a href="http://square.github.io/okhttp/" title="OkHttp"> OkHttp</a></b> by Square team</p>
|
||||||
|
<p><b><a href="https://github.com/InsertKoinIO/koin"
|
||||||
|
title="Koin">Koin</a></b> by Arnaud Giuliani</p>
|
||||||
|
<p><b><a href="https://github.com/afollestad" title="Material Dialogs"> Material Dialogs and Cab</a></b>
|
||||||
|
by Aidan Michael Follestad</p>
|
||||||
<p><b><a href="https://github.com/afollestad/material-cab" title="Material Contextual Action Bar">
|
<p><b><a href="https://github.com/afollestad/material-cab" title="Material Contextual Action Bar">
|
||||||
Material Contextual Action Bar</a></b> by Aidan Michael Follestad</p>
|
Material Contextual Action Bar</a></b> by Aidan Michael Follestad</p>
|
||||||
<p><b><a href="http://square.github.io/okhttp/" title="OkHttp"> OkHttp</a></b> by Square team</p>
|
|
||||||
<p><b><a href="https://github.com/hdodenhof/CircleImageView" title="CircleImageView">
|
|
||||||
CircleImageView</a></b> by Henning Dodenhof</p>
|
|
||||||
<p><b><a href="https://github.com/DreaminginCodeZH/MaterialProgressBar" title="MaterialProgressBar">
|
|
||||||
MaterialProgressBar</a></b> by Zhang Hai</p>
|
|
||||||
<p><b><a href="https://github.com/anjlab/android-inapp-billing-v3"
|
<p><b><a href="https://github.com/anjlab/android-inapp-billing-v3"
|
||||||
title="Android In-App Billing v3 Library"> Android In-App Billing v3 Library</a></b> by
|
title="Android In-App Billing v3 Library"> Android In-App Billing v3 Library</a></b> by
|
||||||
Henning Dodenhof</p>
|
Henning Dodenhof</p>
|
||||||
<p><b><a href="https://github.com/h6ah4i/android-advancedrecyclerview"
|
<p><b><a href="https://github.com/h6ah4i/android-advancedrecyclerview"
|
||||||
title="Advanced RecyclerView"> Advanced RecyclerView</a></b> by Haruki Hasegawa</p>
|
title="Advanced RecyclerView"> Advanced RecyclerView</a></b> by Haruki Hasegawa</p>
|
||||||
<p><b><a href="https://github.com/ksoichiro/Android-ObservableScrollView"
|
<p><b><a href="https://github.com/Ereza/CustomActivityOnCrash"
|
||||||
title="Android-ObservableScrollView"> Android-ObservableScrollView</a></b> by Soichiro
|
title="Custom Activity on Crash">Custom Activity on Crash</a></b> by Eduard Ereza Martínez
|
||||||
Kashima</p>
|
</p>
|
||||||
|
<p><b><a href="https://github.com/NanoHttpd/nanohttpd"
|
||||||
|
title="NanoHttpd">NanoHttpd</a></b> by NanoHttpd Team</p>
|
||||||
|
<p><b><a href="https://github.com/tankery/CircularSeekBar"
|
||||||
|
title="Circular Seekbar">Circular Seekbar</a></b> by Tankery</p>
|
||||||
|
<p><b><a href="https://github.com/Kaned1as/jaudiotagger"
|
||||||
|
title="jAudioTagger">jAudioTagger</a></b> by Kanedias</p>
|
||||||
|
<p><b><a href="https://github.com/zhanghai/AndroidFastScroll"
|
||||||
|
title="Android Fast Scroll">Android Fast Scroll</a></b> by Zhang Hai</p>
|
||||||
|
<p><b><a href="https://github.com/Dhaval2404/ImagePicker"
|
||||||
|
title="Image Picker">Image Picker</a></b> by Dhaval Patel</p>
|
||||||
|
<p><b><a href="https://github.com/heinrichreimer/material-intro"
|
||||||
|
title="Material Intro">Material Intro</a></b> by Jan Heinrich Reimer</p>
|
||||||
|
<p><b><a href="https://github.com/r0adkll/Slidr"
|
||||||
|
title="Slidr">Slidr</a></b> by Drew Heavner</p>
|
||||||
<p><b><a href="https://materialdesignicons.com" title="Icons"> Icons</a></b> by Austin Andrews</p>
|
<p><b><a href="https://materialdesignicons.com" title="Icons"> Icons</a></b> by Austin Andrews</p>
|
||||||
<p><b><a href="https://www.techjuice.pk" title="City wallpaper"> Material Design City Wallpaper</a></b>
|
<p><b><a href="https://www.techjuice.pk" title="City wallpaper"> Material Design City Wallpaper</a></b>
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -21,7 +21,6 @@ import android.graphics.PorterDuff
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.animation.LinearInterpolator
|
import android.view.animation.LinearInterpolator
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import androidx.activity.viewModels
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
@ -29,8 +28,6 @@ import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
|
||||||
import code.name.monkey.retromusic.databinding.ActivityDriveModeBinding
|
import code.name.monkey.retromusic.databinding.ActivityDriveModeBinding
|
||||||
import code.name.monkey.retromusic.db.toSongEntity
|
import code.name.monkey.retromusic.db.toSongEntity
|
||||||
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
||||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
|
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
|
||||||
import code.name.monkey.retromusic.glide.BlurTransformation
|
import code.name.monkey.retromusic.glide.BlurTransformation
|
||||||
import code.name.monkey.retromusic.glide.GlideApp
|
import code.name.monkey.retromusic.glide.GlideApp
|
||||||
|
@ -50,7 +47,6 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,8 +16,6 @@ package code.name.monkey.retromusic.activities
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.webkit.WebView
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
|
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil.isWindowBackgroundDark
|
import code.name.monkey.appthemehelper.util.ATHUtil.isWindowBackgroundDark
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor
|
import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor
|
||||||
|
@ -25,29 +23,30 @@ 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.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
|
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
|
||||||
|
import code.name.monkey.retromusic.databinding.ActivityLicenseBinding
|
||||||
|
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
||||||
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
|
||||||
|
|
||||||
/** Created by hemanths on 2019-09-27. */
|
/** Created by hemanths on 2019-09-27. */
|
||||||
class LicenseActivity : AbsThemeActivity() {
|
class LicenseActivity : AbsThemeActivity() {
|
||||||
|
private lateinit var binding: ActivityLicenseBinding
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_license)
|
binding = ActivityLicenseBinding.inflate(layoutInflater)
|
||||||
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
setContentView(binding.root)
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(binding.toolbar)
|
||||||
ToolbarContentTintHelper.colorBackButton(toolbar)
|
ToolbarContentTintHelper.colorBackButton(binding.toolbar)
|
||||||
toolbar.setBackgroundColor(resolveColor(this, R.attr.colorSurface))
|
|
||||||
val webView = findViewById<WebView>(R.id.license)
|
|
||||||
try {
|
try {
|
||||||
val buf = StringBuilder()
|
val buf = StringBuilder()
|
||||||
val json = assets.open("oldindex.html")
|
val json = assets.open("oldindex.html")
|
||||||
val br = BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8))
|
BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8)).use { br ->
|
||||||
var str: String?
|
var str: String?
|
||||||
while (br.readLine().also { str = it } != null) {
|
while (br.readLine().also { str = it } != null) {
|
||||||
buf.append(str)
|
buf.append(str)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
br.close()
|
|
||||||
|
|
||||||
// Inject color values for WebView body background and links
|
// Inject color values for WebView body background and links
|
||||||
val isDark = isWindowBackgroundDark(this)
|
val isDark = isWindowBackgroundDark(this)
|
||||||
|
@ -72,12 +71,13 @@ class LicenseActivity : AbsThemeActivity() {
|
||||||
lightenColor(accentColor(this))
|
lightenColor(accentColor(this))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
webView.loadData(changeLog, "text/html", "UTF-8")
|
binding.license.loadData(changeLog, "text/html", "UTF-8")
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
webView.loadData(
|
binding.license.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"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
binding.license.drawAboveSystemBars()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
|
|
@ -22,9 +22,9 @@ import android.net.Uri
|
||||||
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 android.view.View
|
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
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.base.AbsMusicServiceActivity
|
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
|
||||||
|
@ -84,12 +84,12 @@ class PermissionActivity : AbsMusicServiceActivity() {
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
@RequiresApi(Build.VERSION_CODES.M)
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
if (hasStoragePermission()) {
|
if (hasStoragePermission()) {
|
||||||
binding.storagePermission.checkImage.visibility = View.VISIBLE
|
binding.storagePermission.checkImage.isVisible = true
|
||||||
binding.storagePermission.checkImage.imageTintList =
|
binding.storagePermission.checkImage.imageTintList =
|
||||||
ColorStateList.valueOf(ThemeStore.accentColor(this))
|
ColorStateList.valueOf(ThemeStore.accentColor(this))
|
||||||
}
|
}
|
||||||
if (hasAudioPermission()) {
|
if (hasAudioPermission()) {
|
||||||
binding.audioPermission.checkImage.visibility = View.VISIBLE
|
binding.audioPermission.checkImage.isVisible = true
|
||||||
binding.audioPermission.checkImage.imageTintList =
|
binding.audioPermission.checkImage.imageTintList =
|
||||||
ColorStateList.valueOf(ThemeStore.accentColor(this))
|
ColorStateList.valueOf(ThemeStore.accentColor(this))
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,16 @@ class SettingsActivity : AbsThemeActivity(), ColorCallback, OnThemeChangedListen
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
val mSavedInstanceState = extra<Bundle>(TAG).value ?: savedInstanceState
|
val mSavedInstanceState = extra<Bundle>(TAG).value ?: savedInstanceState
|
||||||
super.onCreate(mSavedInstanceState)
|
super.onCreate(mSavedInstanceState)
|
||||||
setLightStatusBarAuto(surfaceColor())
|
|
||||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
setupToolbar()
|
setupToolbar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
setNavigationBarColorPreOreo(surfaceColor())
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupToolbar() {
|
private fun setupToolbar() {
|
||||||
applyToolbar(binding.toolbar)
|
applyToolbar(binding.toolbar)
|
||||||
val navController: NavController = findNavController(R.id.contentFrame)
|
val navController: NavController = findNavController(R.id.contentFrame)
|
||||||
|
@ -81,7 +85,6 @@ class SettingsActivity : AbsThemeActivity(), ColorCallback, OnThemeChangedListen
|
||||||
ThemeStore.editTheme(this).accentColor(color).commit()
|
ThemeStore.editTheme(this).accentColor(color).commit()
|
||||||
if (VersionUtils.hasNougatMR())
|
if (VersionUtils.hasNougatMR())
|
||||||
DynamicShortcutManager(this).updateDynamicShortcuts()
|
DynamicShortcutManager(this).updateDynamicShortcuts()
|
||||||
|
|
||||||
restart()
|
restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
|
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
|
||||||
import code.name.monkey.retromusic.databinding.ActivityWhatsNewBinding
|
import code.name.monkey.retromusic.databinding.ActivityWhatsNewBinding
|
||||||
import code.name.monkey.retromusic.extensions.accentColor
|
import code.name.monkey.retromusic.extensions.accentColor
|
||||||
|
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
||||||
import code.name.monkey.retromusic.extensions.setLightStatusBarAuto
|
import code.name.monkey.retromusic.extensions.setLightStatusBarAuto
|
||||||
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
|
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion
|
import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion
|
||||||
|
@ -38,12 +39,12 @@ class WhatsNewActivity : AbsThemeActivity() {
|
||||||
try {
|
try {
|
||||||
val buf = StringBuilder()
|
val buf = StringBuilder()
|
||||||
val json = assets.open("retro-changelog.html")
|
val json = assets.open("retro-changelog.html")
|
||||||
val br = BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8))
|
BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8)).use { br ->
|
||||||
var str: String?
|
var str: String?
|
||||||
while (br.readLine().also { str = it } != null) {
|
while (br.readLine().also { str = it } != null) {
|
||||||
buf.append(str)
|
buf.append(str)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
br.close()
|
|
||||||
|
|
||||||
// Inject color values for WebView body background and links
|
// Inject color values for WebView body background and links
|
||||||
val isDark = isWindowBackgroundDark(this)
|
val isDark = isWindowBackgroundDark(this)
|
||||||
|
@ -100,6 +101,7 @@ class WhatsNewActivity : AbsThemeActivity() {
|
||||||
binding.tgFab.extend()
|
binding.tgFab.extend()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
binding.webView.drawAboveSystemBars()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -14,12 +14,15 @@
|
||||||
*/
|
*/
|
||||||
package code.name.monkey.retromusic.activities.base
|
package code.name.monkey.retromusic.activities.base
|
||||||
|
|
||||||
|
import android.animation.ArgbEvaluator
|
||||||
|
import android.animation.ValueAnimator
|
||||||
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
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewTreeObserver
|
import android.view.ViewTreeObserver
|
||||||
|
import android.view.animation.PathInterpolator
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.core.animation.doOnEnd
|
import androidx.core.animation.doOnEnd
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
|
@ -28,7 +31,6 @@ import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.commit
|
import androidx.fragment.app.commit
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
||||||
|
@ -61,9 +63,11 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.model.CategoryInfo
|
import code.name.monkey.retromusic.model.CategoryInfo
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
import code.name.monkey.retromusic.util.ViewUtil
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
|
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
|
||||||
|
|
||||||
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||||
companion object {
|
companion object {
|
||||||
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
|
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
|
||||||
|
@ -78,14 +82,27 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||||
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
|
||||||
protected abstract fun createContentView(): SlidingMusicPanelLayoutBinding
|
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
|
||||||
|
|
||||||
|
private var navigationBarColorAnimator: ValueAnimator? = null
|
||||||
|
private val argbEvaluator: ArgbEvaluator = ArgbEvaluator()
|
||||||
|
|
||||||
private val bottomSheetCallbackList = object : BottomSheetCallback() {
|
private val bottomSheetCallbackList = object : BottomSheetCallback() {
|
||||||
|
|
||||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||||
setMiniPlayerAlphaProgress(slideOffset)
|
setMiniPlayerAlphaProgress(slideOffset)
|
||||||
|
navigationBarColorAnimator?.cancel()
|
||||||
|
setNavigationBarColorPreOreo(
|
||||||
|
argbEvaluator.evaluate(
|
||||||
|
slideOffset,
|
||||||
|
surfaceColor(),
|
||||||
|
navigationBarColor
|
||||||
|
) as Int
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||||
|
@ -131,6 +148,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||||
updateColor()
|
updateColor()
|
||||||
binding.slidingPanel.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
|
binding.slidingPanel.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
|
||||||
bottomNavigationView.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
|
bottomNavigationView.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
|
||||||
|
navigationBarColor = surfaceColor()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupBottomSheet() {
|
private fun setupBottomSheet() {
|
||||||
|
@ -177,9 +195,25 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||||
binding.playerFragmentContainer.alpha = (progress - 0.2F) / 0.2F
|
binding.playerFragmentContainer.alpha = (progress - 0.2F) / 0.2F
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun animateNavigationBarColor(color: Int) {
|
||||||
|
navigationBarColorAnimator?.cancel()
|
||||||
|
navigationBarColorAnimator = ValueAnimator
|
||||||
|
.ofArgb(window.navigationBarColor, color).apply {
|
||||||
|
duration = ViewUtil.RETRO_MUSIC_ANIM_TIME.toLong()
|
||||||
|
interpolator = PathInterpolator(0.4f, 0f, 1f, 1f)
|
||||||
|
addUpdateListener { animation: ValueAnimator ->
|
||||||
|
setNavigationBarColorPreOreo(
|
||||||
|
animation.animatedValue as Int
|
||||||
|
)
|
||||||
|
}
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open fun onPanelCollapsed() {
|
open fun onPanelCollapsed() {
|
||||||
setMiniPlayerAlphaProgress(0F)
|
setMiniPlayerAlphaProgress(0F)
|
||||||
// restore values
|
// restore values
|
||||||
|
animateNavigationBarColor(surfaceColor())
|
||||||
setLightStatusBarAuto(surfaceColor())
|
setLightStatusBarAuto(surfaceColor())
|
||||||
setLightNavigationAuto()
|
setLightNavigationAuto()
|
||||||
setTaskDescriptionColor(taskColor)
|
setTaskDescriptionColor(taskColor)
|
||||||
|
@ -252,18 +286,25 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||||
|
|
||||||
private fun onPaletteColorChanged() {
|
private fun onPaletteColorChanged() {
|
||||||
if (panelState == STATE_EXPANDED) {
|
if (panelState == STATE_EXPANDED) {
|
||||||
|
navigationBarColor = surfaceColor()
|
||||||
setTaskDescColor(paletteColor)
|
setTaskDescColor(paletteColor)
|
||||||
val isColorLight = ColorUtil.isColorLight(paletteColor)
|
val isColorLight = ColorUtil.isColorLight(paletteColor)
|
||||||
if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat)) {
|
if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat)) {
|
||||||
setLightNavigationBar(true)
|
setLightNavigationBar(true)
|
||||||
setLightStatusBar(isColorLight)
|
setLightStatusBar(isColorLight)
|
||||||
} else if (nowPlayingScreen == Card || nowPlayingScreen == Blur || nowPlayingScreen == BlurCard) {
|
} else if (nowPlayingScreen == Card || nowPlayingScreen == Blur || nowPlayingScreen == BlurCard) {
|
||||||
|
animateNavigationBarColor(Color.BLACK)
|
||||||
|
navigationBarColor = Color.BLACK
|
||||||
setLightStatusBar(false)
|
setLightStatusBar(false)
|
||||||
setLightNavigationBar(true)
|
setLightNavigationBar(true)
|
||||||
} else if (nowPlayingScreen == Color || nowPlayingScreen == Tiny || nowPlayingScreen == Gradient) {
|
} else if (nowPlayingScreen == Color || nowPlayingScreen == Tiny || nowPlayingScreen == Gradient) {
|
||||||
|
animateNavigationBarColor(paletteColor)
|
||||||
|
navigationBarColor = paletteColor
|
||||||
setLightNavigationBar(isColorLight)
|
setLightNavigationBar(isColorLight)
|
||||||
setLightStatusBar(isColorLight)
|
setLightStatusBar(isColorLight)
|
||||||
} else if (nowPlayingScreen == Full) {
|
} else if (nowPlayingScreen == Full) {
|
||||||
|
animateNavigationBarColor(paletteColor)
|
||||||
|
navigationBarColor = paletteColor
|
||||||
setLightNavigationBar(isColorLight)
|
setLightNavigationBar(isColorLight)
|
||||||
setLightStatusBar(false)
|
setLightStatusBar(false)
|
||||||
} else if (nowPlayingScreen == Classic) {
|
} else if (nowPlayingScreen == Classic) {
|
||||||
|
@ -273,10 +314,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||||
} else {
|
} else {
|
||||||
setLightStatusBar(
|
setLightStatusBar(
|
||||||
ColorUtil.isColorLight(
|
ColorUtil.isColorLight(
|
||||||
ATHUtil.resolveColor(
|
surfaceColor()
|
||||||
this,
|
|
||||||
android.R.attr.windowBackground
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
setLightNavigationBar(true)
|
setLightNavigationBar(true)
|
||||||
|
|
|
@ -34,7 +34,6 @@ 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.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
|
||||||
import code.name.monkey.appthemehelper.util.TintHelper
|
import code.name.monkey.appthemehelper.util.TintHelper
|
||||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
@ -60,14 +59,13 @@ import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
|
abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
|
||||||
abstract val editorImage: ImageView?
|
abstract val editorImage: ImageView
|
||||||
val repository by inject<Repository>()
|
val repository by inject<Repository>()
|
||||||
|
|
||||||
lateinit var saveFab: MaterialButton
|
lateinit var saveFab: MaterialButton
|
||||||
protected var id: Long = 0
|
protected var id: Long = 0
|
||||||
private set
|
private set
|
||||||
private var paletteColorPrimary: Int = 0
|
private var paletteColorPrimary: Int = 0
|
||||||
private var isInNoImageMode: Boolean = false
|
|
||||||
private var songPaths: List<String>? = null
|
private var songPaths: List<String>? = null
|
||||||
private var savedSongPaths: List<String>? = null
|
private var savedSongPaths: List<String>? = null
|
||||||
private val currentSongPath: String? = null
|
private val currentSongPath: String? = null
|
||||||
|
@ -176,6 +174,15 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected val discNumber: String?
|
||||||
|
get() {
|
||||||
|
return try {
|
||||||
|
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.DISC_NO)
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected val lyrics: String?
|
protected val lyrics: String?
|
||||||
get() {
|
get() {
|
||||||
return try {
|
return try {
|
||||||
|
@ -239,7 +246,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
|
||||||
getString(R.string.web_search),
|
getString(R.string.web_search),
|
||||||
getString(R.string.remove_cover)
|
getString(R.string.remove_cover)
|
||||||
)
|
)
|
||||||
editorImage?.setOnClickListener { show }
|
editorImage.setOnClickListener { show }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startImagePicker() {
|
private fun startImagePicker() {
|
||||||
|
@ -306,17 +313,6 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
|
||||||
return super.onOptionsItemSelected(item)
|
return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun setNoImageMode() {
|
|
||||||
isInNoImageMode = true
|
|
||||||
setColors(
|
|
||||||
intent.getIntExtra(
|
|
||||||
EXTRA_PALETTE,
|
|
||||||
ATHUtil.resolveColor(this, R.attr.colorPrimary)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected fun dataChanged() {
|
protected fun dataChanged() {
|
||||||
showFab()
|
showFab()
|
||||||
}
|
}
|
||||||
|
@ -335,9 +331,9 @@ 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(drawable.default_audio_art)
|
editorImage.setImageResource(drawable.default_audio_art)
|
||||||
} else {
|
} else {
|
||||||
editorImage?.setImageBitmap(bitmap)
|
editorImage.setImageBitmap(bitmap)
|
||||||
}
|
}
|
||||||
setColors(bgColor)
|
setColors(bgColor)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,11 @@ import android.view.LayoutInflater
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
|
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding
|
import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding
|
||||||
import code.name.monkey.retromusic.extensions.appHandleColor
|
import code.name.monkey.retromusic.extensions.appHandleColor
|
||||||
|
import code.name.monkey.retromusic.extensions.isColorLight
|
||||||
import code.name.monkey.retromusic.extensions.setTint
|
import code.name.monkey.retromusic.extensions.setTint
|
||||||
import code.name.monkey.retromusic.glide.GlideApp
|
import code.name.monkey.retromusic.glide.GlideApp
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||||
|
@ -63,41 +65,6 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
|
||||||
window.enterTransition = slide
|
window.enterTransition = slide
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadImageFromFile(selectedFile: Uri?) {
|
|
||||||
GlideApp.with(this@AlbumTagEditorActivity).asBitmapPalette().load(selectedFile)
|
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
|
|
||||||
.into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) {
|
|
||||||
override fun onResourceReady(
|
|
||||||
resource: BitmapPaletteWrapper,
|
|
||||||
transition: Transition<in BitmapPaletteWrapper>?
|
|
||||||
) {
|
|
||||||
getColor(resource.palette, Color.TRANSPARENT)
|
|
||||||
albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
|
|
||||||
setImageBitmap(
|
|
||||||
albumArtBitmap,
|
|
||||||
getColor(
|
|
||||||
resource.palette,
|
|
||||||
ATHUtil.resolveColor(
|
|
||||||
this@AlbumTagEditorActivity,
|
|
||||||
R.attr.defaultFooterColor
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
deleteAlbumArt = false
|
|
||||||
dataChanged()
|
|
||||||
setResult(Activity.RESULT_OK)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
|
||||||
super.onLoadFailed(errorDrawable)
|
|
||||||
Toast.makeText(this@AlbumTagEditorActivity, "Load Failed", Toast.LENGTH_LONG)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setResource(resource: BitmapPaletteWrapper?) {}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private var albumArtBitmap: Bitmap? = null
|
private var albumArtBitmap: Bitmap? = null
|
||||||
private var deleteAlbumArt: Boolean = false
|
private var deleteAlbumArt: Boolean = false
|
||||||
|
|
||||||
|
@ -171,6 +138,41 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
|
||||||
dataChanged()
|
dataChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun loadImageFromFile(selectedFile: Uri?) {
|
||||||
|
GlideApp.with(this@AlbumTagEditorActivity).asBitmapPalette().load(selectedFile)
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
|
||||||
|
.into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) {
|
||||||
|
override fun onResourceReady(
|
||||||
|
resource: BitmapPaletteWrapper,
|
||||||
|
transition: Transition<in BitmapPaletteWrapper>?
|
||||||
|
) {
|
||||||
|
getColor(resource.palette, Color.TRANSPARENT)
|
||||||
|
albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
|
||||||
|
setImageBitmap(
|
||||||
|
albumArtBitmap,
|
||||||
|
getColor(
|
||||||
|
resource.palette,
|
||||||
|
ATHUtil.resolveColor(
|
||||||
|
this@AlbumTagEditorActivity,
|
||||||
|
R.attr.defaultFooterColor
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
deleteAlbumArt = false
|
||||||
|
dataChanged()
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
|
super.onLoadFailed(errorDrawable)
|
||||||
|
Toast.makeText(this@AlbumTagEditorActivity, "Load Failed", Toast.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setResource(resource: BitmapPaletteWrapper?) {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
override fun save() {
|
override fun save() {
|
||||||
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
|
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
|
||||||
fieldKeyValueMap[FieldKey.ALBUM] = binding.albumText.text.toString()
|
fieldKeyValueMap[FieldKey.ALBUM] = binding.albumText.text.toString()
|
||||||
|
@ -213,6 +215,16 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
|
||||||
override fun setColors(color: Int) {
|
override fun setColors(color: Int) {
|
||||||
super.setColors(color)
|
super.setColors(color)
|
||||||
saveFab.backgroundTintList = ColorStateList.valueOf(color)
|
saveFab.backgroundTintList = ColorStateList.valueOf(color)
|
||||||
|
saveFab.backgroundTintList = ColorStateList.valueOf(color)
|
||||||
|
ColorStateList.valueOf(
|
||||||
|
MaterialValueHelper.getPrimaryTextColor(
|
||||||
|
this,
|
||||||
|
color.isColorLight
|
||||||
|
)
|
||||||
|
).also {
|
||||||
|
saveFab.iconTint = it
|
||||||
|
saveFab.setTextColor(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,17 +15,36 @@
|
||||||
package code.name.monkey.retromusic.activities.tageditor
|
package code.name.monkey.retromusic.activities.tageditor
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import android.widget.Toast
|
||||||
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
|
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.databinding.ActivitySongTagEditorBinding
|
import code.name.monkey.retromusic.databinding.ActivitySongTagEditorBinding
|
||||||
import code.name.monkey.retromusic.extensions.appHandleColor
|
import code.name.monkey.retromusic.extensions.appHandleColor
|
||||||
|
import code.name.monkey.retromusic.extensions.isColorLight
|
||||||
import code.name.monkey.retromusic.extensions.setTint
|
import code.name.monkey.retromusic.extensions.setTint
|
||||||
|
import code.name.monkey.retromusic.glide.GlideApp
|
||||||
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||||
|
import code.name.monkey.retromusic.model.ArtworkInfo
|
||||||
import code.name.monkey.retromusic.repository.SongRepository
|
import code.name.monkey.retromusic.repository.SongRepository
|
||||||
|
import code.name.monkey.retromusic.util.ImageUtil
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
|
import code.name.monkey.retromusic.util.RetroColorUtil
|
||||||
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
|
import com.bumptech.glide.request.target.ImageViewTarget
|
||||||
|
import com.bumptech.glide.request.transition.Transition
|
||||||
import com.google.android.material.shape.MaterialShapeDrawable
|
import com.google.android.material.shape.MaterialShapeDrawable
|
||||||
import org.jaudiotagger.tag.FieldKey
|
import org.jaudiotagger.tag.FieldKey
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
@ -39,12 +58,14 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
||||||
|
|
||||||
private val songRepository by inject<SongRepository>()
|
private val songRepository by inject<SongRepository>()
|
||||||
|
|
||||||
|
private var albumArtBitmap: Bitmap? = null
|
||||||
|
private var deleteAlbumArt: Boolean = false
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setUpViews()
|
setUpViews()
|
||||||
setNoImageMode()
|
|
||||||
setSupportActionBar(binding.toolbar)
|
setSupportActionBar(binding.toolbar)
|
||||||
binding.appBarLayout.statusBarForeground =
|
binding.appBarLayout?.statusBarForeground =
|
||||||
MaterialShapeDrawable.createWithElevationOverlay(this)
|
MaterialShapeDrawable.createWithElevationOverlay(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +80,7 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
||||||
binding.yearContainer.setTint(false)
|
binding.yearContainer.setTint(false)
|
||||||
binding.genreContainer.setTint(false)
|
binding.genreContainer.setTint(false)
|
||||||
binding.trackNumberContainer.setTint(false)
|
binding.trackNumberContainer.setTint(false)
|
||||||
|
binding.discNumberContainer.setTint(false)
|
||||||
binding.lyricsContainer.setTint(false)
|
binding.lyricsContainer.setTint(false)
|
||||||
|
|
||||||
binding.songText.appHandleColor().addTextChangedListener(this)
|
binding.songText.appHandleColor().addTextChangedListener(this)
|
||||||
|
@ -68,13 +90,9 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
||||||
binding.genreText.appHandleColor().addTextChangedListener(this)
|
binding.genreText.appHandleColor().addTextChangedListener(this)
|
||||||
binding.yearText.appHandleColor().addTextChangedListener(this)
|
binding.yearText.appHandleColor().addTextChangedListener(this)
|
||||||
binding.trackNumberText.appHandleColor().addTextChangedListener(this)
|
binding.trackNumberText.appHandleColor().addTextChangedListener(this)
|
||||||
|
binding.discNumberText.appHandleColor().addTextChangedListener(this)
|
||||||
binding.lyricsText.appHandleColor().addTextChangedListener(this)
|
binding.lyricsText.appHandleColor().addTextChangedListener(this)
|
||||||
binding.songComposerText.appHandleColor().addTextChangedListener(this)
|
binding.songComposerText.appHandleColor().addTextChangedListener(this)
|
||||||
|
|
||||||
binding.lyricsText.setOnTouchListener { view, _ ->
|
|
||||||
view.parent.requestDisallowInterceptTouchEvent(true)
|
|
||||||
return@setOnTouchListener false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fillViewsWithFileTags() {
|
private fun fillViewsWithFileTags() {
|
||||||
|
@ -85,16 +103,50 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
||||||
binding.genreText.setText(genreName)
|
binding.genreText.setText(genreName)
|
||||||
binding.yearText.setText(songYear)
|
binding.yearText.setText(songYear)
|
||||||
binding.trackNumberText.setText(trackNumber)
|
binding.trackNumberText.setText(trackNumber)
|
||||||
|
binding.discNumberText.setText(discNumber)
|
||||||
binding.lyricsText.setText(lyrics)
|
binding.lyricsText.setText(lyrics)
|
||||||
binding.songComposerText.setText(composer)
|
binding.songComposerText.setText(composer)
|
||||||
println(songTitle + songYear)
|
println(songTitle + songYear)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadCurrentImage() {}
|
override fun loadCurrentImage() {
|
||||||
|
val bitmap = albumArt
|
||||||
|
setImageBitmap(
|
||||||
|
bitmap,
|
||||||
|
RetroColorUtil.getColor(
|
||||||
|
RetroColorUtil.generatePalette(bitmap),
|
||||||
|
ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
deleteAlbumArt = false
|
||||||
|
}
|
||||||
|
|
||||||
override fun searchImageOnWeb() {}
|
override fun searchImageOnWeb() {
|
||||||
|
searchWebFor(binding.songText.text.toString(), binding.artistText.text.toString())
|
||||||
|
}
|
||||||
|
|
||||||
override fun deleteImage() {}
|
override fun deleteImage() {
|
||||||
|
setImageBitmap(
|
||||||
|
BitmapFactory.decodeResource(resources, R.drawable.default_audio_art),
|
||||||
|
ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
|
||||||
|
)
|
||||||
|
deleteAlbumArt = true
|
||||||
|
dataChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setColors(color: Int) {
|
||||||
|
super.setColors(color)
|
||||||
|
saveFab.backgroundTintList = ColorStateList.valueOf(color)
|
||||||
|
ColorStateList.valueOf(
|
||||||
|
MaterialValueHelper.getPrimaryTextColor(
|
||||||
|
this,
|
||||||
|
color.isColorLight
|
||||||
|
)
|
||||||
|
).also {
|
||||||
|
saveFab.iconTint = it
|
||||||
|
saveFab.setTextColor(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun save() {
|
override fun save() {
|
||||||
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
|
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
|
||||||
|
@ -104,10 +156,16 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
||||||
fieldKeyValueMap[FieldKey.GENRE] = binding.genreText.text.toString()
|
fieldKeyValueMap[FieldKey.GENRE] = binding.genreText.text.toString()
|
||||||
fieldKeyValueMap[FieldKey.YEAR] = binding.yearText.text.toString()
|
fieldKeyValueMap[FieldKey.YEAR] = binding.yearText.text.toString()
|
||||||
fieldKeyValueMap[FieldKey.TRACK] = binding.trackNumberText.text.toString()
|
fieldKeyValueMap[FieldKey.TRACK] = binding.trackNumberText.text.toString()
|
||||||
|
fieldKeyValueMap[FieldKey.DISC_NO] = binding.discNumberText.text.toString()
|
||||||
fieldKeyValueMap[FieldKey.LYRICS] = binding.lyricsText.text.toString()
|
fieldKeyValueMap[FieldKey.LYRICS] = binding.lyricsText.text.toString()
|
||||||
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = binding.albumArtistText.text.toString()
|
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = binding.albumArtistText.text.toString()
|
||||||
fieldKeyValueMap[FieldKey.COMPOSER] = binding.songComposerText.text.toString()
|
fieldKeyValueMap[FieldKey.COMPOSER] = binding.songComposerText.text.toString()
|
||||||
writeValuesToFiles(fieldKeyValueMap, null)
|
writeValuesToFiles(fieldKeyValueMap, when {
|
||||||
|
deleteAlbumArt -> ArtworkInfo(id, null)
|
||||||
|
albumArtBitmap == null -> null
|
||||||
|
else -> ArtworkInfo(id, albumArtBitmap!!)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSongPaths(): List<String> = listOf(songRepository.song(id).data)
|
override fun getSongPaths(): List<String> = listOf(songRepository.song(id).data)
|
||||||
|
@ -115,6 +173,38 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
||||||
override fun getSongUris(): List<Uri> = listOf(MusicUtil.getSongFileUri(id))
|
override fun getSongUris(): List<Uri> = listOf(MusicUtil.getSongFileUri(id))
|
||||||
|
|
||||||
override fun loadImageFromFile(selectedFile: Uri?) {
|
override fun loadImageFromFile(selectedFile: Uri?) {
|
||||||
|
GlideApp.with(this@SongTagEditorActivity).asBitmapPalette().load(selectedFile)
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
|
||||||
|
.into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) {
|
||||||
|
override fun onResourceReady(
|
||||||
|
resource: BitmapPaletteWrapper,
|
||||||
|
transition: Transition<in BitmapPaletteWrapper>?
|
||||||
|
) {
|
||||||
|
RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT)
|
||||||
|
albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
|
||||||
|
setImageBitmap(
|
||||||
|
albumArtBitmap,
|
||||||
|
RetroColorUtil.getColor(
|
||||||
|
resource.palette,
|
||||||
|
ATHUtil.resolveColor(
|
||||||
|
this@SongTagEditorActivity,
|
||||||
|
R.attr.defaultFooterColor
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
deleteAlbumArt = false
|
||||||
|
dataChanged()
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
|
super.onLoadFailed(errorDrawable)
|
||||||
|
Toast.makeText(this@SongTagEditorActivity, "Load Failed", Toast.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setResource(resource: BitmapPaletteWrapper?) {}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
||||||
|
@ -131,6 +221,6 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
||||||
val TAG: String = SongTagEditorActivity::class.java.simpleName
|
val TAG: String = SongTagEditorActivity::class.java.simpleName
|
||||||
}
|
}
|
||||||
|
|
||||||
override val editorImage: ImageView?
|
override val editorImage: ImageView
|
||||||
get() = null
|
get() = binding.editorImage
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ import org.jaudiotagger.audio.exceptions.CannotWriteException
|
||||||
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException
|
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException
|
||||||
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException
|
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException
|
||||||
import org.jaudiotagger.tag.TagException
|
import org.jaudiotagger.tag.TagException
|
||||||
|
import org.jaudiotagger.tag.images.AndroidArtwork
|
||||||
import org.jaudiotagger.tag.images.Artwork
|
import org.jaudiotagger.tag.images.Artwork
|
||||||
import org.jaudiotagger.tag.images.ArtworkFactory
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
@ -58,11 +58,11 @@ class TagWriter {
|
||||||
try {
|
try {
|
||||||
albumArtFile = createAlbumArtFile(context).canonicalFile
|
albumArtFile = createAlbumArtFile(context).canonicalFile
|
||||||
info.artworkInfo.artwork.compress(
|
info.artworkInfo.artwork.compress(
|
||||||
Bitmap.CompressFormat.PNG,
|
Bitmap.CompressFormat.JPEG,
|
||||||
0,
|
100,
|
||||||
FileOutputStream(albumArtFile)
|
FileOutputStream(albumArtFile)
|
||||||
)
|
)
|
||||||
artwork = ArtworkFactory.createArtworkFromFile(albumArtFile)
|
artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
@ -131,11 +131,11 @@ class TagWriter {
|
||||||
try {
|
try {
|
||||||
albumArtFile = createAlbumArtFile(context).canonicalFile
|
albumArtFile = createAlbumArtFile(context).canonicalFile
|
||||||
info.artworkInfo.artwork.compress(
|
info.artworkInfo.artwork.compress(
|
||||||
Bitmap.CompressFormat.PNG,
|
Bitmap.CompressFormat.JPEG,
|
||||||
0,
|
100,
|
||||||
FileOutputStream(albumArtFile)
|
FileOutputStream(albumArtFile)
|
||||||
)
|
)
|
||||||
artwork = ArtworkFactory.createArtworkFromFile(albumArtFile)
|
artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,10 @@ import code.name.monkey.retromusic.glide.GlideApp
|
||||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.helper.menu.SongMenuHelper
|
import code.name.monkey.retromusic.helper.menu.SongMenuHelper
|
||||||
import code.name.monkey.retromusic.model.*
|
import code.name.monkey.retromusic.model.Album
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
import code.name.monkey.retromusic.repository.PlaylistSongsLoader
|
import code.name.monkey.retromusic.model.Genre
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@ import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.widget.PopupMenu
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.widget.AppCompatImageView
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
|
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 code.name.monkey.retromusic.R
|
||||||
|
|
|
@ -30,7 +30,11 @@ class ImportPlaylistDialog : DialogFragment() {
|
||||||
return materialDialog(R.string.import_playlist)
|
return materialDialog(R.string.import_playlist)
|
||||||
.setMessage(R.string.import_playlist_message)
|
.setMessage(R.string.import_playlist_message)
|
||||||
.setPositiveButton(R.string.import_label) { _, _ ->
|
.setPositiveButton(R.string.import_label) { _, _ ->
|
||||||
libraryViewModel.importPlaylists()
|
try {
|
||||||
|
libraryViewModel.importPlaylists()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.create()
|
.create()
|
||||||
.colorButtons()
|
.colorButtons()
|
||||||
|
|
|
@ -14,14 +14,16 @@
|
||||||
*/
|
*/
|
||||||
package code.name.monkey.retromusic.extensions
|
package code.name.monkey.retromusic.extensions
|
||||||
|
|
||||||
|
import android.R
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.DimenRes
|
import androidx.annotation.DimenRes
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
|
|
||||||
fun AppCompatActivity.applyToolbar(toolbar: MaterialToolbar) {
|
fun AppCompatActivity.applyToolbar(toolbar: MaterialToolbar) {
|
||||||
//toolbar.setBackgroundColor(surfaceColor())
|
|
||||||
ToolbarContentTintHelper.colorBackButton(toolbar)
|
ToolbarContentTintHelper.colorBackButton(toolbar)
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
}
|
}
|
||||||
|
@ -38,4 +40,6 @@ inline fun <reified T : Any> Activity.extraNotNull(key: String, default: T? = nu
|
||||||
|
|
||||||
fun Activity.dip(@DimenRes id: Int): Int {
|
fun Activity.dip(@DimenRes id: Int): Int {
|
||||||
return resources.getDimensionPixelSize(id)
|
return resources.getDimensionPixelSize(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline val Activity.rootView: View get() = findViewById<ViewGroup>(R.id.content).getChildAt(0)
|
|
@ -9,6 +9,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
|
import androidx.core.view.isGone
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import code.name.monkey.appthemehelper.ATH
|
import code.name.monkey.appthemehelper.ATH
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
|
@ -46,7 +47,6 @@ fun AppCompatActivity.exitFullscreen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun AppCompatActivity.hideStatusBar() {
|
fun AppCompatActivity.hideStatusBar() {
|
||||||
hideStatusBar(PreferenceUtil.isFullScreenMode)
|
hideStatusBar(PreferenceUtil.isFullScreenMode)
|
||||||
}
|
}
|
||||||
|
@ -54,16 +54,25 @@ fun AppCompatActivity.hideStatusBar() {
|
||||||
private fun AppCompatActivity.hideStatusBar(fullscreen: Boolean) {
|
private fun AppCompatActivity.hideStatusBar(fullscreen: Boolean) {
|
||||||
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
|
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
|
||||||
if (statusBar != null) {
|
if (statusBar != null) {
|
||||||
statusBar.visibility = if (fullscreen) View.GONE else View.VISIBLE
|
statusBar.isGone = fullscreen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AppCompatActivity.setDrawBehindSystemBars() {
|
fun AppCompatActivity.setDrawBehindSystemBars() {
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
window.statusBarColor = Color.TRANSPARENT
|
if (VersionUtils.hasOreo()) {
|
||||||
window.navigationBarColor = Color.TRANSPARENT
|
if (VersionUtils.hasQ()) {
|
||||||
if (VersionUtils.hasQ()) {
|
window.isNavigationBarContrastEnforced = false
|
||||||
window.isNavigationBarContrastEnforced = false
|
}
|
||||||
|
setNavigationBarColor(Color.TRANSPARENT)
|
||||||
|
setStatusBarColor(Color.TRANSPARENT)
|
||||||
|
} else {
|
||||||
|
setNavigationBarColorPreOreo(surfaceColor())
|
||||||
|
if (VersionUtils.hasMarshmallow()) {
|
||||||
|
setStatusBarColor(Color.TRANSPARENT)
|
||||||
|
} else {
|
||||||
|
setStatusBarColor(surfaceColor())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +111,11 @@ fun AppCompatActivity.setLightStatusBarAuto(bgColor: Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AppCompatActivity.setLightNavigationBar(enabled: Boolean) {
|
fun AppCompatActivity.setLightNavigationBar(enabled: Boolean) {
|
||||||
ATH.setLightNavigationBar(this, enabled)
|
ATH.setLightNavigationBar(this, enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun AppCompatActivity.setLightNavigationBarAuto(bgColor: Int) {
|
||||||
|
setLightNavigationBar(ColorUtil.isColorLight(bgColor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -136,4 +149,32 @@ fun AppCompatActivity.setStatusBarColorAuto() {
|
||||||
// we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat
|
// we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat
|
||||||
setStatusBarColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
|
setStatusBarColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
|
||||||
setLightStatusBarAuto(ATHUtil.resolveColor(this, R.attr.colorSurface))
|
setLightStatusBarAuto(ATHUtil.resolveColor(this, R.attr.colorSurface))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun AppCompatActivity.setNavigationBarColor(color: Int) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
window.navigationBarColor = color
|
||||||
|
} else {
|
||||||
|
window.navigationBarColor = ColorUtil.darkenColor(color)
|
||||||
|
}
|
||||||
|
setLightNavigationBarAuto(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun AppCompatActivity.setNavigationBarColorPreOreo(color: Int) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
|
window.navigationBarColor = ColorUtil.darkenColor(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun AppCompatActivity.setStatusBarColorPreMarshmallow(color: Int) {
|
||||||
|
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
|
||||||
|
if (statusBar != null) {
|
||||||
|
statusBar.setBackgroundColor(
|
||||||
|
ColorUtil.darkenColor(
|
||||||
|
color
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
window.statusBarColor = ColorUtil.darkenColor(color)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -20,7 +20,7 @@ import android.database.Cursor
|
||||||
|
|
||||||
internal fun Cursor.getInt(columnName: String): Int {
|
internal fun Cursor.getInt(columnName: String): Int {
|
||||||
try {
|
try {
|
||||||
return this.getInt(this.getColumnIndex(columnName))
|
return getInt(getColumnIndexOrThrow(columnName))
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
throw IllegalStateException("invalid column $columnName", ex)
|
throw IllegalStateException("invalid column $columnName", ex)
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ internal fun Cursor.getInt(columnName: String): Int {
|
||||||
|
|
||||||
internal fun Cursor.getLong(columnName: String): Long {
|
internal fun Cursor.getLong(columnName: String): Long {
|
||||||
try {
|
try {
|
||||||
return this.getLong(this.getColumnIndex(columnName))
|
return getLong(getColumnIndexOrThrow(columnName))
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
throw IllegalStateException("invalid column $columnName", ex)
|
throw IllegalStateException("invalid column $columnName", ex)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ internal fun Cursor.getLong(columnName: String): Long {
|
||||||
|
|
||||||
internal fun Cursor.getString(columnName: String): String {
|
internal fun Cursor.getString(columnName: String): String {
|
||||||
try {
|
try {
|
||||||
return this.getString(this.getColumnIndex(columnName))
|
return getString(getColumnIndexOrThrow(columnName))
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
throw IllegalStateException("invalid column $columnName", ex)
|
throw IllegalStateException("invalid column $columnName", ex)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ internal fun Cursor.getString(columnName: String): String {
|
||||||
|
|
||||||
internal fun Cursor.getStringOrNull(columnName: String): String? {
|
internal fun Cursor.getStringOrNull(columnName: String): String? {
|
||||||
try {
|
try {
|
||||||
return this.getString(this.getColumnIndex(columnName))
|
return getString(getColumnIndexOrThrow(columnName))
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
throw IllegalStateException("invalid column $columnName", ex)
|
throw IllegalStateException("invalid column $columnName", ex)
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,6 @@ val FragmentManager.currentNavigationFragment: Fragment?
|
||||||
fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
|
fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
|
||||||
val navHostFragment: NavHostFragment =
|
val navHostFragment: NavHostFragment =
|
||||||
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
||||||
navHostFragment.targetFragment
|
|
||||||
return navHostFragment.childFragmentManager.fragments.firstOrNull()
|
return navHostFragment.childFragmentManager.fragments.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package code.name.monkey.retromusic.extensions
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.webkit.MimeTypeMap
|
import android.webkit.MimeTypeMap
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
import org.jaudiotagger.audio.AudioFileIO
|
import org.jaudiotagger.audio.AudioFileIO
|
||||||
|
|
|
@ -24,7 +24,6 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
|
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
|
||||||
import code.name.monkey.retromusic.extensions.navigate
|
|
||||||
import code.name.monkey.retromusic.extensions.surfaceColor
|
import code.name.monkey.retromusic.extensions.surfaceColor
|
||||||
import code.name.monkey.retromusic.fragments.GridStyle
|
import code.name.monkey.retromusic.fragments.GridStyle
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
|
|
|
@ -7,7 +7,7 @@ import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.core.net.toUri
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
@ -49,7 +49,9 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
||||||
val openFilePicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
val openFilePicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
it?.let {
|
it?.let {
|
||||||
backupViewModel.restoreBackup(requireActivity(), requireContext().contentResolver.openInputStream(it))
|
startActivity(Intent(context, RestoreActivity::class.java).apply {
|
||||||
|
data = it
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,17 +105,11 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackupClicked(file: File) {
|
override fun onBackupClicked(file: File) {
|
||||||
AlertDialog.Builder(requireContext())
|
lifecycleScope.launch {
|
||||||
.setTitle(R.string.restore)
|
startActivity(Intent(context, RestoreActivity::class.java).apply {
|
||||||
.setMessage(R.string.restore_message)
|
data = file.toUri()
|
||||||
.setPositiveButton(R.string.restore) { _, _ ->
|
})
|
||||||
lifecycleScope.launch {
|
}
|
||||||
backupViewModel.restoreBackup(requireActivity(), file.inputStream())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.create()
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
|
|
|
@ -5,6 +5,8 @@ import android.content.Intent
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import code.name.monkey.retromusic.activities.MainActivity
|
||||||
|
import code.name.monkey.retromusic.helper.BackupContent
|
||||||
import code.name.monkey.retromusic.helper.BackupHelper
|
import code.name.monkey.retromusic.helper.BackupHelper
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
@ -25,12 +27,12 @@ class BackupViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun restoreBackup(activity: Activity, inputStream: InputStream?) {
|
suspend fun restoreBackup(activity: Activity, inputStream: InputStream?, contents: List<BackupContent>) {
|
||||||
BackupHelper.restoreBackup(activity, inputStream)
|
BackupHelper.restoreBackup(activity, inputStream, contents)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val intent = Intent(
|
val intent = Intent(
|
||||||
activity,
|
activity,
|
||||||
activity::class.java
|
MainActivity::class.java
|
||||||
)
|
)
|
||||||
activity.startActivity(intent)
|
activity.startActivity(intent)
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
|
|
|
@ -1,12 +1,89 @@
|
||||||
package code.name.monkey.retromusic.fragments.backup
|
package code.name.monkey.retromusic.fragments.backup
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.provider.MediaStore
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import code.name.monkey.retromusic.R
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import code.name.monkey.retromusic.databinding.ActivityRestoreBinding
|
||||||
|
import code.name.monkey.retromusic.helper.BackupContent
|
||||||
|
import code.name.monkey.retromusic.helper.BackupContent.*
|
||||||
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import code.name.monkey.retromusic.util.theme.ThemeManager
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
class RestoreActivity : AppCompatActivity() {
|
class RestoreActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
lateinit var binding: ActivityRestoreBinding
|
||||||
|
private val backupViewModel: BackupViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
updateTheme()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_restore)
|
binding = ActivityRestoreBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
val backupUri = intent?.data
|
||||||
|
binding.backupName.setText(getFileName(backupUri))
|
||||||
|
binding.cancelButton.setOnClickListener {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
binding.restoreButton.setOnClickListener {
|
||||||
|
val backupContents = mutableListOf<BackupContent>()
|
||||||
|
if (binding.checkSettings.isChecked) backupContents.add(SETTINGS)
|
||||||
|
if (binding.checkQueue.isChecked) backupContents.add(QUEUE)
|
||||||
|
if (binding.checkDatabases.isChecked) backupContents.add(PLAYLISTS)
|
||||||
|
if (binding.checkArtistImages.isChecked) backupContents.add(CUSTOM_ARTIST_IMAGES)
|
||||||
|
if (binding.checkUserImages.isChecked) backupContents.add(USER_IMAGES)
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
if (backupUri != null) {
|
||||||
|
contentResolver.openInputStream(backupUri)?.use {
|
||||||
|
backupViewModel.restoreBackup(this@RestoreActivity, it, backupContents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateTheme() {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(ThemeManager.getNightMode(this))
|
||||||
|
|
||||||
|
// Apply dynamic colors to activity if enabled
|
||||||
|
if (PreferenceUtil.materialYou) {
|
||||||
|
DynamicColors.applyIfAvailable(
|
||||||
|
this,
|
||||||
|
com.google.android.material.R.style.ThemeOverlay_Material3_DynamicColors_DayNight
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFileName(uri: Uri?): String? {
|
||||||
|
when (uri?.scheme) {
|
||||||
|
"file" -> {
|
||||||
|
return uri.lastPathSegment
|
||||||
|
}
|
||||||
|
"content" -> {
|
||||||
|
val proj = arrayOf(MediaStore.Images.Media.TITLE)
|
||||||
|
contentResolver.query(
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
|
||||||
|
MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
|
||||||
|
} else {
|
||||||
|
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
||||||
|
}, proj, null, null, null
|
||||||
|
)?.use { cursor ->
|
||||||
|
if (cursor.count != 0) {
|
||||||
|
val columnIndex: Int =
|
||||||
|
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.TITLE)
|
||||||
|
cursor.moveToFirst()
|
||||||
|
return cursor.getString(columnIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "Backup"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,9 +21,9 @@ import android.os.Environment
|
||||||
import android.text.Html
|
import android.text.Html
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.webkit.MimeTypeMap
|
import android.webkit.MimeTypeMap
|
||||||
import androidx.appcompat.widget.PopupMenu
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.loader.app.LoaderManager
|
import androidx.loader.app.LoaderManager
|
||||||
import androidx.loader.content.Loader
|
import androidx.loader.content.Loader
|
||||||
import androidx.navigation.Navigation.findNavController
|
import androidx.navigation.Navigation.findNavController
|
||||||
|
|
|
@ -27,12 +27,10 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import code.name.monkey.retromusic.EXTRA_GENRE
|
import code.name.monkey.retromusic.EXTRA_GENRE
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.GenreAdapter
|
import code.name.monkey.retromusic.adapter.GenreAdapter
|
||||||
import code.name.monkey.retromusic.extensions.navigate
|
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||||
import code.name.monkey.retromusic.interfaces.IGenreClickListener
|
import code.name.monkey.retromusic.interfaces.IGenreClickListener
|
||||||
import code.name.monkey.retromusic.model.Genre
|
import code.name.monkey.retromusic.model.Genre
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
|
|
@ -23,6 +23,7 @@ import android.view.View
|
||||||
import androidx.activity.addCallback
|
import androidx.activity.addCallback
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
|
import androidx.core.view.doOnLayout
|
||||||
import androidx.core.view.doOnPreDraw
|
import androidx.core.view.doOnPreDraw
|
||||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
|
@ -87,6 +88,21 @@ class HomeFragment :
|
||||||
remove()
|
remove()
|
||||||
mainActivity.finish()
|
mainActivity.finish()
|
||||||
}
|
}
|
||||||
|
view.doOnLayout {
|
||||||
|
adjustPlaylistButtons()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun adjustPlaylistButtons() {
|
||||||
|
val buttons =
|
||||||
|
listOf(binding.history, binding.lastAdded, binding.topPlayed, binding.actionShuffle)
|
||||||
|
buttons.maxOf { it.lineCount }.let { maxLineCount->
|
||||||
|
buttons.forEach { button ->
|
||||||
|
// Set the highest line count to every button for consistency
|
||||||
|
button.setLines(maxLineCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListeners() {
|
private fun setupListeners() {
|
||||||
|
|
|
@ -64,14 +64,6 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
||||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
|
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.appBarLayout.statusBarForeground =
|
|
||||||
MaterialShapeDrawable.createWithElevationOverlay(requireContext())
|
|
||||||
postponeEnterTransition()
|
|
||||||
view.doOnPreDraw { startPostponedEnterTransition() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
mainActivity.setSupportActionBar(binding.toolbar)
|
mainActivity.setSupportActionBar(binding.toolbar)
|
||||||
binding.progressIndicator.hide()
|
binding.progressIndicator.hide()
|
||||||
when (args.type) {
|
when (args.type) {
|
||||||
|
@ -92,6 +84,10 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
||||||
binding.recyclerView.updatePadding(bottom = height.toInt())
|
binding.recyclerView.updatePadding(bottom = height.toInt())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
binding.appBarLayout.statusBarForeground =
|
||||||
|
MaterialShapeDrawable.createWithElevationOverlay(requireContext())
|
||||||
|
postponeEnterTransition()
|
||||||
|
view.doOnPreDraw { startPostponedEnterTransition() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun lastAddedSongs() {
|
private fun lastAddedSongs() {
|
||||||
|
@ -104,6 +100,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
||||||
binding.recyclerView.apply {
|
binding.recyclerView.apply {
|
||||||
adapter = songAdapter
|
adapter = songAdapter
|
||||||
layoutManager = linearLayoutManager()
|
layoutManager = linearLayoutManager()
|
||||||
|
scheduleLayoutAnimation()
|
||||||
}
|
}
|
||||||
libraryViewModel.recentSongs().observe(viewLifecycleOwner, { songs ->
|
libraryViewModel.recentSongs().observe(viewLifecycleOwner, { songs ->
|
||||||
songAdapter.swapDataSet(songs)
|
songAdapter.swapDataSet(songs)
|
||||||
|
|
|
@ -134,12 +134,11 @@ class UserInfoFragment : Fragment() {
|
||||||
private fun loadProfile() {
|
private fun loadProfile() {
|
||||||
binding.bannerImage.let {
|
binding.bannerImage.let {
|
||||||
GlideApp.with(this)
|
GlideApp.with(this)
|
||||||
.asBitmap()
|
|
||||||
.load(RetroGlideExtension.getBannerModel())
|
.load(RetroGlideExtension.getBannerModel())
|
||||||
.profileBannerOptions(RetroGlideExtension.getBannerModel())
|
.profileBannerOptions(RetroGlideExtension.getBannerModel())
|
||||||
.into(it)
|
.into(it)
|
||||||
}
|
}
|
||||||
GlideApp.with(this).asBitmap()
|
GlideApp.with(this)
|
||||||
.load(RetroGlideExtension.getUserModel())
|
.load(RetroGlideExtension.getUserModel())
|
||||||
.userProfileOptions(RetroGlideExtension.getUserModel())
|
.userProfileOptions(RetroGlideExtension.getUserModel())
|
||||||
.into(binding.userImage)
|
.into(binding.userImage)
|
||||||
|
|
|
@ -14,42 +14,36 @@
|
||||||
*/
|
*/
|
||||||
package code.name.monkey.retromusic.fragments.player
|
package code.name.monkey.retromusic.fragments.player
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.TextUtils
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.FrameLayout
|
import androidx.core.view.isInvisible
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.SHOW_LYRICS
|
import code.name.monkey.retromusic.SHOW_LYRICS
|
||||||
import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter
|
import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter
|
||||||
import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter.AlbumCoverFragment
|
import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter.AlbumCoverFragment
|
||||||
import code.name.monkey.retromusic.databinding.FragmentPlayerAlbumCoverBinding
|
import code.name.monkey.retromusic.databinding.FragmentPlayerAlbumCoverBinding
|
||||||
|
import code.name.monkey.retromusic.extensions.isColorLight
|
||||||
|
import code.name.monkey.retromusic.extensions.surfaceColor
|
||||||
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||||
import code.name.monkey.retromusic.fragments.base.goToLyrics
|
import code.name.monkey.retromusic.fragments.base.goToLyrics
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
||||||
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics
|
import code.name.monkey.retromusic.lyrics.CoverLrcView
|
||||||
import code.name.monkey.retromusic.model.lyrics.Lyrics
|
import code.name.monkey.retromusic.model.lyrics.Lyrics
|
||||||
import code.name.monkey.retromusic.transform.CarousalPagerTransformer
|
import code.name.monkey.retromusic.transform.CarousalPagerTransformer
|
||||||
import code.name.monkey.retromusic.transform.ParallaxPagerTransformer
|
import code.name.monkey.retromusic.transform.ParallaxPagerTransformer
|
||||||
import code.name.monkey.retromusic.util.LyricUtil
|
import code.name.monkey.retromusic.util.LyricUtil
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.jaudiotagger.audio.AudioFileIO
|
|
||||||
import org.jaudiotagger.audio.exceptions.CannotReadException
|
|
||||||
import org.jaudiotagger.tag.FieldKey
|
|
||||||
import java.io.File
|
|
||||||
import java.io.FileNotFoundException
|
|
||||||
|
|
||||||
class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_player_album_cover),
|
class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_player_album_cover),
|
||||||
ViewPager.OnPageChangeListener, MusicProgressViewUpdateHelper.Callback,
|
ViewPager.OnPageChangeListener, MusicProgressViewUpdateHelper.Callback,
|
||||||
|
@ -70,9 +64,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
}
|
}
|
||||||
private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null
|
private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null
|
||||||
|
|
||||||
private val lyricsLayout: FrameLayout get() = binding.playerLyrics
|
private val lrcView: CoverLrcView get() = binding.lyricsView
|
||||||
private val lyricsLine1: TextView get() = binding.playerLyricsLine1
|
|
||||||
private val lyricsLine2: TextView get() = binding.playerLyricsLine2
|
|
||||||
|
|
||||||
var lyrics: Lyrics? = null
|
var lyrics: Lyrics? = null
|
||||||
|
|
||||||
|
@ -82,102 +74,28 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateLyrics() {
|
private fun updateLyrics() {
|
||||||
lyrics = null
|
binding.lyricsView.setLabel("Empty")
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
val song = MusicPlayerRemote.currentSong
|
||||||
val song = MusicPlayerRemote.currentSong
|
when {
|
||||||
val lyrics = try {
|
LyricUtil.isLrcOriginalFileExist(song.data) -> {
|
||||||
var lrcFile: File? = null
|
LyricUtil.getLocalLyricOriginalFile(song.data)
|
||||||
if (LyricUtil.isLrcOriginalFileExist(song.data)) {
|
?.let { binding.lyricsView.loadLrc(it) }
|
||||||
lrcFile = LyricUtil.getLocalLyricOriginalFile(song.data)
|
|
||||||
} else if (LyricUtil.isLrcFileExist(song.title, song.artistName)) {
|
|
||||||
lrcFile = LyricUtil.getLocalLyricFile(song.title, song.artistName)
|
|
||||||
}
|
|
||||||
val data: String = LyricUtil.getStringFromLrc(lrcFile)
|
|
||||||
if (!TextUtils.isEmpty(data)) {
|
|
||||||
Lyrics.parse(song, data)
|
|
||||||
} else {
|
|
||||||
// Get Embedded Lyrics and check if they are Synchronized
|
|
||||||
val embeddedLyrics = try{
|
|
||||||
AudioFileIO.read(File(song.data)).tagOrCreateDefault.getFirst(FieldKey.LYRICS)
|
|
||||||
} catch(e: Exception){
|
|
||||||
null
|
|
||||||
}
|
|
||||||
if (AbsSynchronizedLyrics.isSynchronized(embeddedLyrics)) {
|
|
||||||
Lyrics.parse(song, embeddedLyrics)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err: FileNotFoundException) {
|
|
||||||
null
|
|
||||||
} catch (e: CannotReadException){
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
withContext(Dispatchers.Main) {
|
LyricUtil.isLrcFileExist(song.title, song.artistName) -> {
|
||||||
this@PlayerAlbumCoverFragment.lyrics = lyrics
|
LyricUtil.getLocalLyricFile(song.title, song.artistName)
|
||||||
|
?.let { binding.lyricsView.loadLrc(it) }
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
binding.lyricsView.reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUpdateProgressViews(progress: Int, total: Int) {
|
override fun onUpdateProgressViews(progress: Int, total: Int) {
|
||||||
if (_binding == null) return
|
binding.lyricsView.updateTime(progress.toLong())
|
||||||
|
|
||||||
if (!isLyricsLayoutVisible()) {
|
|
||||||
hideLyricsLayout()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lyrics !is AbsSynchronizedLyrics) return
|
|
||||||
val synchronizedLyrics = lyrics as AbsSynchronizedLyrics
|
|
||||||
|
|
||||||
lyricsLayout.visibility = View.VISIBLE
|
|
||||||
lyricsLayout.alpha = 1f
|
|
||||||
|
|
||||||
val oldLine = lyricsLine2.text.toString()
|
|
||||||
val line = synchronizedLyrics.getLine(progress)
|
|
||||||
|
|
||||||
if (oldLine != line || oldLine.isEmpty()) {
|
|
||||||
lyricsLine1.text = oldLine
|
|
||||||
lyricsLine2.text = line
|
|
||||||
|
|
||||||
lyricsLine1.visibility = View.VISIBLE
|
|
||||||
lyricsLine2.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
lyricsLine2.measure(
|
|
||||||
View.MeasureSpec.makeMeasureSpec(
|
|
||||||
lyricsLine2.measuredWidth,
|
|
||||||
View.MeasureSpec.EXACTLY
|
|
||||||
),
|
|
||||||
View.MeasureSpec.UNSPECIFIED
|
|
||||||
)
|
|
||||||
val h: Float = lyricsLine2.measuredHeight.toFloat()
|
|
||||||
|
|
||||||
lyricsLine1.alpha = 1f
|
|
||||||
lyricsLine1.translationY = 0f
|
|
||||||
lyricsLine1.animate().alpha(0f).translationY(-h).duration =
|
|
||||||
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
|
|
||||||
|
|
||||||
lyricsLine2.alpha = 0f
|
|
||||||
lyricsLine2.translationY = h
|
|
||||||
lyricsLine2.animate().alpha(1f).translationY(0f).duration =
|
|
||||||
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isLyricsLayoutVisible(): Boolean {
|
|
||||||
return lyrics != null && lyrics!!.isSynchronized && lyrics!!.isValid
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hideLyricsLayout() {
|
|
||||||
lyricsLayout.animate().alpha(0f).setDuration(AbsPlayerFragment.VISIBILITY_ANIM_DURATION)
|
|
||||||
.withEndAction {
|
|
||||||
if (_binding == null) return@withEndAction
|
|
||||||
lyricsLayout.visibility = View.GONE
|
|
||||||
lyricsLine1.text = null
|
|
||||||
lyricsLine2.text = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
_binding = FragmentPlayerAlbumCoverBinding.bind(view)
|
_binding = FragmentPlayerAlbumCoverBinding.bind(view)
|
||||||
|
@ -210,14 +128,25 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
|
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
|
||||||
// Don't show lyrics container for below conditions
|
// Don't show lyrics container for below conditions
|
||||||
if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) {
|
if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) {
|
||||||
lyricsLayout.isVisible = false
|
lrcView.isVisible = false
|
||||||
|
viewPager.isInvisible = false
|
||||||
progressViewUpdateHelper?.stop()
|
progressViewUpdateHelper?.stop()
|
||||||
} else {
|
} else {
|
||||||
lyricsLayout.isVisible = true
|
lrcView.isVisible = true
|
||||||
|
viewPager.isInvisible = true
|
||||||
progressViewUpdateHelper?.start()
|
progressViewUpdateHelper?.start()
|
||||||
}
|
}
|
||||||
|
lrcView.apply {
|
||||||
|
setDraggable(true, object : CoverLrcView.OnPlayClickListener {
|
||||||
|
override fun onPlayClick(time: Long): Boolean {
|
||||||
|
MusicPlayerRemote.seekTo(time.toInt())
|
||||||
|
MusicPlayerRemote.resumePlaying()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
// Go to lyrics activity when clicked lyrics
|
// Go to lyrics activity when clicked lyrics
|
||||||
binding.playerLyricsLine2.setOnClickListener {
|
lrcView.setOnClickListener {
|
||||||
goToLyrics(requireActivity())
|
goToLyrics(requireActivity())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,10 +156,12 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
val nps = PreferenceUtil.nowPlayingScreen
|
val nps = PreferenceUtil.nowPlayingScreen
|
||||||
// Don't show lyrics container for below conditions
|
// Don't show lyrics container for below conditions
|
||||||
if (nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics) {
|
if (nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics) {
|
||||||
lyricsLayout.isVisible = false
|
lrcView.isVisible = false
|
||||||
|
viewPager.isInvisible = false
|
||||||
progressViewUpdateHelper?.stop()
|
progressViewUpdateHelper?.stop()
|
||||||
} else {
|
} else {
|
||||||
lyricsLayout.isVisible = true
|
lrcView.isVisible = true
|
||||||
|
viewPager.isInvisible = true
|
||||||
progressViewUpdateHelper?.start()
|
progressViewUpdateHelper?.start()
|
||||||
}
|
}
|
||||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
@ -266,30 +197,42 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
val nps = PreferenceUtil.nowPlayingScreen
|
val nps = PreferenceUtil.nowPlayingScreen
|
||||||
// Don't show lyrics container for below conditions
|
// Don't show lyrics container for below conditions
|
||||||
if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) {
|
if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) {
|
||||||
lyricsLayout.isVisible = false
|
lrcView.isVisible = true
|
||||||
progressViewUpdateHelper?.stop()
|
viewPager.isInvisible = true
|
||||||
} else {
|
|
||||||
lyricsLayout.isVisible = true
|
|
||||||
progressViewUpdateHelper?.start()
|
progressViewUpdateHelper?.start()
|
||||||
lyricsLayout.animate().alpha(1f).duration =
|
lrcView.animate().alpha(1f).duration =
|
||||||
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
|
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
|
||||||
binding.playerLyrics.isVisible = true
|
} else {
|
||||||
|
lrcView.isVisible = false
|
||||||
|
viewPager.isInvisible = false
|
||||||
|
progressViewUpdateHelper?.stop()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
lrcView.isVisible = false
|
||||||
|
viewPager.isInvisible = false
|
||||||
progressViewUpdateHelper?.stop()
|
progressViewUpdateHelper?.stop()
|
||||||
lyricsLayout.animate().alpha(0f)
|
|
||||||
.setDuration(AbsPlayerFragment.VISIBILITY_ANIM_DURATION)
|
|
||||||
.withEndAction {
|
|
||||||
if (_binding != null) {
|
|
||||||
binding.playerLyrics.isVisible = false
|
|
||||||
lyricsLine1.text = null
|
|
||||||
lyricsLine2.text = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setLRCViewColors(backgroundColor: Int) {
|
||||||
|
val primaryColor = MaterialValueHelper.getPrimaryTextColor(
|
||||||
|
requireContext(),
|
||||||
|
backgroundColor.isColorLight
|
||||||
|
)
|
||||||
|
val secondaryColor = MaterialValueHelper.getSecondaryDisabledTextColor(
|
||||||
|
requireContext(),
|
||||||
|
backgroundColor.isColorLight
|
||||||
|
)
|
||||||
|
lrcView.apply {
|
||||||
|
setCurrentColor(primaryColor)
|
||||||
|
setTimeTextColor(primaryColor)
|
||||||
|
setTimelineColor(primaryColor)
|
||||||
|
setNormalColor(secondaryColor)
|
||||||
|
setTimelineTextColor(primaryColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updatePlayingQueue() {
|
private fun updatePlayingQueue() {
|
||||||
binding.viewPager.apply {
|
binding.viewPager.apply {
|
||||||
adapter = AlbumCoverPagerAdapter(childFragmentManager, MusicPlayerRemote.playingQueue)
|
adapter = AlbumCoverPagerAdapter(childFragmentManager, MusicPlayerRemote.playingQueue)
|
||||||
|
@ -321,6 +264,18 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
|
|
||||||
private fun notifyColorChange(color: MediaNotificationProcessor) {
|
private fun notifyColorChange(color: MediaNotificationProcessor) {
|
||||||
callbacks?.onColorChanged(color)
|
callbacks?.onColorChanged(color)
|
||||||
|
setLRCViewColors(
|
||||||
|
when (PreferenceUtil.nowPlayingScreen) {
|
||||||
|
Adaptive, Fit, Plain, Simple -> surfaceColor()
|
||||||
|
Flat, Normal -> if (PreferenceUtil.isAdaptiveColor) {
|
||||||
|
color.backgroundColor
|
||||||
|
} else {
|
||||||
|
surfaceColor()
|
||||||
|
}
|
||||||
|
Color ->color.backgroundColor
|
||||||
|
Blur -> Color.BLACK
|
||||||
|
else -> color.backgroundColor
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setCallbacks(listener: Callbacks) {
|
fun setCallbacks(listener: Callbacks) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ class AdaptiveFragment : AbsPlayerFragment(R.layout.fragment_adaptive_player) {
|
||||||
_binding = FragmentAdaptivePlayerBinding.bind(view)
|
_binding = FragmentAdaptivePlayerBinding.bind(view)
|
||||||
setUpSubFragments()
|
setUpSubFragments()
|
||||||
setUpPlayerToolbar()
|
setUpPlayerToolbar()
|
||||||
binding.root.drawAboveSystemBars()
|
binding.playbackControlsFragment.drawAboveSystemBars()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpSubFragments() {
|
private fun setUpSubFragments() {
|
||||||
|
|
|
@ -16,6 +16,8 @@ package code.name.monkey.retromusic.fragments.player.blur
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
@ -27,18 +29,18 @@ import code.name.monkey.retromusic.databinding.FragmentBlurBinding
|
||||||
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||||
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
||||||
import code.name.monkey.retromusic.glide.BlurTransformation
|
import code.name.monkey.retromusic.glide.*
|
||||||
import code.name.monkey.retromusic.glide.GlideApp
|
|
||||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
|
||||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil.blurAmount
|
import code.name.monkey.retromusic.util.PreferenceUtil.blurAmount
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||||
|
|
||||||
|
|
||||||
class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
|
class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
|
private var lastRequest: GlideRequest<Drawable>? = null
|
||||||
|
|
||||||
override fun playerToolbar(): Toolbar {
|
override fun playerToolbar(): Toolbar {
|
||||||
return binding.playerToolbar
|
return binding.playerToolbar
|
||||||
}
|
}
|
||||||
|
@ -111,23 +113,20 @@ class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
|
||||||
get() = lastColor
|
get() = lastColor
|
||||||
|
|
||||||
private fun updateBlur() {
|
private fun updateBlur() {
|
||||||
binding.colorBackground.clearColorFilter()
|
// https://github.com/bumptech/glide/issues/527#issuecomment-148840717
|
||||||
GlideApp.with(requireActivity()).asBitmapPalette()
|
GlideApp.with(this)
|
||||||
.songCoverOptions(MusicPlayerRemote.currentSong)
|
|
||||||
.load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong))
|
.load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong))
|
||||||
.dontAnimate()
|
.simpleSongCoverOptions(MusicPlayerRemote.currentSong)
|
||||||
.transform(
|
.transform(
|
||||||
BlurTransformation.Builder(requireContext())
|
BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat())
|
||||||
.blurRadius(blurAmount.toFloat())
|
|
||||||
.build()
|
.build()
|
||||||
)
|
).thumbnail(lastRequest)
|
||||||
.into(object : RetroMusicColoredTarget(binding.colorBackground) {
|
.error(GlideApp.with(this).load(ColorDrawable(Color.DKGRAY)).fitCenter())
|
||||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
.also {
|
||||||
if (colors.backgroundColor == defaultFooterColor) {
|
lastRequest = it.clone()
|
||||||
binding.colorBackground.setColorFilter(colors.backgroundColor)
|
it.crossfadeListener()
|
||||||
}
|
.into(binding.colorBackground)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceConnected() {
|
override fun onServiceConnected() {
|
||||||
|
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.fragments.player.cardblur
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
@ -28,10 +29,7 @@ import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||||
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
||||||
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
|
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
|
||||||
import code.name.monkey.retromusic.glide.BlurTransformation
|
import code.name.monkey.retromusic.glide.*
|
||||||
import code.name.monkey.retromusic.glide.GlideApp
|
|
||||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
|
||||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil.blurAmount
|
import code.name.monkey.retromusic.util.PreferenceUtil.blurAmount
|
||||||
|
@ -50,6 +48,7 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
|
||||||
|
|
||||||
private var _binding: FragmentCardBlurPlayerBinding? = null
|
private var _binding: FragmentCardBlurPlayerBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
private var lastRequest: GlideRequest<Drawable>? = null
|
||||||
|
|
||||||
override fun onShow() {
|
override fun onShow() {
|
||||||
playbackControlsFragment.show()
|
playbackControlsFragment.show()
|
||||||
|
@ -136,22 +135,19 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateBlur() {
|
private fun updateBlur() {
|
||||||
binding.colorBackground.clearColorFilter()
|
// https://github.com/bumptech/glide/issues/527#issuecomment-148840717
|
||||||
GlideApp.with(requireActivity()).asBitmapPalette()
|
GlideApp.with(this)
|
||||||
.songCoverOptions(MusicPlayerRemote.currentSong)
|
|
||||||
.load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong))
|
.load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong))
|
||||||
.dontAnimate()
|
.simpleSongCoverOptions(MusicPlayerRemote.currentSong)
|
||||||
.transform(
|
.transform(
|
||||||
BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat())
|
BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat())
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.into(object : RetroMusicColoredTarget(binding.colorBackground) {
|
.thumbnail(lastRequest).also {
|
||||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
lastRequest = it.clone()
|
||||||
if (colors.backgroundColor == defaultFooterColor) {
|
it.crossfadeListener()
|
||||||
binding.colorBackground.setColorFilter(colors.backgroundColor)
|
.into(binding.colorBackground)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
|
|
@ -18,19 +18,19 @@ import android.animation.ObjectAnimator
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
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.view.animation.Animation
|
||||||
import android.view.animation.LinearInterpolator
|
import android.view.animation.LinearInterpolator
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.*
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
|
||||||
import code.name.monkey.appthemehelper.util.TintHelper
|
|
||||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.databinding.FragmentCirclePlayerBinding
|
import code.name.monkey.retromusic.databinding.FragmentCirclePlayerBinding
|
||||||
import code.name.monkey.retromusic.extensions.*
|
import code.name.monkey.retromusic.extensions.*
|
||||||
|
@ -38,6 +38,7 @@ import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||||
import code.name.monkey.retromusic.fragments.base.goToAlbum
|
import code.name.monkey.retromusic.fragments.base.goToAlbum
|
||||||
import code.name.monkey.retromusic.fragments.base.goToArtist
|
import code.name.monkey.retromusic.fragments.base.goToArtist
|
||||||
|
import code.name.monkey.retromusic.glide.*
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
||||||
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback
|
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback
|
||||||
|
@ -47,10 +48,9 @@ import code.name.monkey.retromusic.util.MusicUtil
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.ViewUtil
|
import code.name.monkey.retromusic.util.ViewUtil
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||||
import code.name.monkey.retromusic.views.SeekArc
|
|
||||||
import code.name.monkey.retromusic.views.SeekArc.OnSeekArcChangeListener
|
|
||||||
import code.name.monkey.retromusic.volume.AudioVolumeObserver
|
import code.name.monkey.retromusic.volume.AudioVolumeObserver
|
||||||
import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener
|
import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener
|
||||||
|
import me.tankery.lib.circularseekbar.CircularSeekBar
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by hemanths on 2020-01-06.
|
* Created by hemanths on 2020-01-06.
|
||||||
|
@ -58,7 +58,7 @@ import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener
|
||||||
|
|
||||||
class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player), Callback,
|
class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player), Callback,
|
||||||
OnAudioVolumeChangedListener,
|
OnAudioVolumeChangedListener,
|
||||||
OnSeekArcChangeListener {
|
CircularSeekBar.OnCircularSeekBarChangeListener {
|
||||||
|
|
||||||
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
|
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
|
||||||
private var audioVolumeObserver: AudioVolumeObserver? = null
|
private var audioVolumeObserver: AudioVolumeObserver? = null
|
||||||
|
@ -69,6 +69,9 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
private var _binding: FragmentCirclePlayerBinding? = null
|
private var _binding: FragmentCirclePlayerBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
private var rotateAnimator: ObjectAnimator? = null
|
||||||
|
private var lastRequest: GlideRequest<Drawable>? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
|
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
|
||||||
|
@ -116,11 +119,17 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
ThemeStore.accentColor(requireContext()),
|
ThemeStore.accentColor(requireContext()),
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
binding.volumeSeekBar.progressColor = accentColor()
|
binding.volumeSeekBar.circleProgressColor = accentColor()
|
||||||
binding.volumeSeekBar.arcColor = ColorUtil.withAlpha(accentColor(), 0.25f)
|
binding.volumeSeekBar.circleColor = ColorUtil.withAlpha(accentColor(), 0.25f)
|
||||||
setUpPlayPauseFab()
|
setUpPlayPauseFab()
|
||||||
setUpPrevNext()
|
setUpPrevNext()
|
||||||
setUpPlayerToolbar()
|
setUpPlayerToolbar()
|
||||||
|
binding.albumCoverOverlay.background = ColorDrawable(
|
||||||
|
MaterialValueHelper.getPrimaryTextColor(
|
||||||
|
requireContext(),
|
||||||
|
accentColor().isColorLight
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpPrevNext() {
|
private fun setUpPrevNext() {
|
||||||
|
@ -144,6 +153,17 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
|
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupRotateAnimation() {
|
||||||
|
rotateAnimator = ObjectAnimator.ofFloat(binding.albumCover, View.ROTATION, 360F).apply {
|
||||||
|
interpolator = LinearInterpolator()
|
||||||
|
repeatCount = Animation.INFINITE
|
||||||
|
duration = 10000
|
||||||
|
if (MusicPlayerRemote.isPlaying) {
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
progressViewUpdateHelper.start()
|
progressViewUpdateHelper.start()
|
||||||
|
@ -153,11 +173,11 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
audioVolumeObserver?.register(AudioManager.STREAM_MUSIC, this)
|
audioVolumeObserver?.register(AudioManager.STREAM_MUSIC, this)
|
||||||
|
|
||||||
val audioManager = audioManager
|
val audioManager = audioManager
|
||||||
if (audioManager != null) {
|
binding.volumeSeekBar.max =
|
||||||
binding.volumeSeekBar.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
|
audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC).toFloat()
|
||||||
binding.volumeSeekBar.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
binding.volumeSeekBar.progress =
|
||||||
}
|
audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat()
|
||||||
binding.volumeSeekBar.setOnSeekArcChangeListener(this)
|
binding.volumeSeekBar.setOnSeekBarChangeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
|
@ -191,6 +211,11 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
|
|
||||||
override fun onPlayStateChanged() {
|
override fun onPlayStateChanged() {
|
||||||
updatePlayPauseDrawableState()
|
updatePlayPauseDrawableState()
|
||||||
|
if (MusicPlayerRemote.isPlaying) {
|
||||||
|
if (rotateAnimator?.isStarted == true) rotateAnimator?.resume() else rotateAnimator?.start()
|
||||||
|
} else {
|
||||||
|
rotateAnimator?.pause()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPlayingMetaChanged() {
|
override fun onPlayingMetaChanged() {
|
||||||
|
@ -202,6 +227,7 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
super.onServiceConnected()
|
super.onServiceConnected()
|
||||||
updateSong()
|
updateSong()
|
||||||
updatePlayPauseDrawableState()
|
updatePlayPauseDrawableState()
|
||||||
|
setupRotateAnimation()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSong() {
|
private fun updateSong() {
|
||||||
|
@ -215,6 +241,16 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
} else {
|
} else {
|
||||||
binding.songInfo.hide()
|
binding.songInfo.hide()
|
||||||
}
|
}
|
||||||
|
GlideApp.with(this)
|
||||||
|
.load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong))
|
||||||
|
.simpleSongCoverOptions(MusicPlayerRemote.currentSong)
|
||||||
|
.thumbnail(lastRequest)
|
||||||
|
.error(GlideApp.with(this).load(R.drawable.default_audio_art).fitCenter())
|
||||||
|
.fitCenter().also {
|
||||||
|
lastRequest = it.clone()
|
||||||
|
it.crossfadeListener()
|
||||||
|
.into(binding.albumCover)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePlayPauseDrawableState() {
|
private fun updatePlayPauseDrawableState() {
|
||||||
|
@ -225,8 +261,8 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAudioVolumeChanged(currentVolume: Int, maxVolume: Int) {
|
override fun onAudioVolumeChanged(currentVolume: Int, maxVolume: Int) {
|
||||||
_binding?.volumeSeekBar?.max = maxVolume
|
_binding?.volumeSeekBar?.max = maxVolume.toFloat()
|
||||||
_binding?.volumeSeekBar?.progress = currentVolume
|
_binding?.volumeSeekBar?.progress = currentVolume.toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
@ -237,15 +273,16 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onProgressChanged(seekArc: SeekArc?, progress: Int, fromUser: Boolean) {
|
|
||||||
|
override fun onProgressChanged(seekBar: CircularSeekBar?, progress: Float, fromUser: Boolean) {
|
||||||
val audioManager = audioManager
|
val audioManager = audioManager
|
||||||
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0)
|
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress.toInt(), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartTrackingTouch(seekArc: SeekArc?) {
|
override fun onStartTrackingTouch(seekBar: CircularSeekBar?) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStopTrackingTouch(seekArc: SeekArc?) {
|
override fun onStopTrackingTouch(seekBar: CircularSeekBar?) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setUpProgressSlider() {
|
fun setUpProgressSlider() {
|
||||||
|
|
|
@ -26,14 +26,13 @@ import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.animation.DecelerateInterpolator
|
import android.view.animation.DecelerateInterpolator
|
||||||
import android.view.animation.LinearInterpolator
|
import android.view.animation.LinearInterpolator
|
||||||
import androidx.appcompat.widget.PopupMenu
|
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.databinding.FragmentFullPlayerControlsBinding
|
import code.name.monkey.retromusic.databinding.FragmentFullPlayerControlsBinding
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
import code.name.monkey.retromusic.db.SongEntity
|
|
||||||
import code.name.monkey.retromusic.db.toSongEntity
|
import code.name.monkey.retromusic.db.toSongEntity
|
||||||
import code.name.monkey.retromusic.extensions.applyColor
|
import code.name.monkey.retromusic.extensions.applyColor
|
||||||
import code.name.monkey.retromusic.extensions.getSongInfo
|
import code.name.monkey.retromusic.extensions.getSongInfo
|
||||||
|
|
|
@ -23,9 +23,9 @@ import android.graphics.drawable.AnimatedVectorDrawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.animation.LinearInterpolator
|
import android.view.animation.LinearInterpolator
|
||||||
import androidx.appcompat.widget.PopupMenu
|
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
|
@ -39,9 +39,6 @@ import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
||||||
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
||||||
import code.name.monkey.retromusic.databinding.FragmentGradientPlayerBinding
|
import code.name.monkey.retromusic.databinding.FragmentGradientPlayerBinding
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
|
||||||
import code.name.monkey.retromusic.db.SongEntity
|
|
||||||
import code.name.monkey.retromusic.db.toSongEntity
|
|
||||||
import code.name.monkey.retromusic.extensions.*
|
import code.name.monkey.retromusic.extensions.*
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
|
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||||
|
|
|
@ -281,12 +281,13 @@ class TinyPlayerFragment : AbsPlayerFragment(R.layout.fragment_tiny_player),
|
||||||
return gestureDetector.onTouchEvent(event)
|
return gestureDetector.onTouchEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("Deprecation")
|
||||||
private fun vibrate() {
|
private fun vibrate() {
|
||||||
val v = requireContext().getSystemService(Context.VIBRATOR_SERVICE) as Vibrator?
|
val v = requireContext().getSystemService(Context.VIBRATOR_SERVICE) as Vibrator?
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
v!!.vibrate(VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE))
|
v?.vibrate(VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||||
} else {
|
} else {
|
||||||
v!!.vibrate(10)
|
v?.vibrate(10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,10 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
|
|
||||||
binding.voiceSearch.setOnClickListener { startMicSearch() }
|
binding.voiceSearch.setOnClickListener { startMicSearch() }
|
||||||
binding.clearText.setOnClickListener { binding.searchView.clearText() }
|
binding.clearText.setOnClickListener {
|
||||||
|
binding.searchView.clearText()
|
||||||
|
searchAdapter.swapDataSet(listOf())
|
||||||
|
}
|
||||||
binding.searchView.apply {
|
binding.searchView.apply {
|
||||||
addTextChangedListener(this@SearchFragment)
|
addTextChangedListener(this@SearchFragment)
|
||||||
focusAndShowKeyboard()
|
focusAndShowKeyboard()
|
||||||
|
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.fragments.settings
|
||||||
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
@ -26,6 +27,7 @@ import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat
|
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat
|
||||||
import code.name.monkey.retromusic.activities.OnThemeChangedListener
|
import code.name.monkey.retromusic.activities.OnThemeChangedListener
|
||||||
|
import code.name.monkey.retromusic.extensions.rootView
|
||||||
import code.name.monkey.retromusic.extensions.safeGetBottomInsets
|
import code.name.monkey.retromusic.extensions.safeGetBottomInsets
|
||||||
import code.name.monkey.retromusic.preferences.*
|
import code.name.monkey.retromusic.preferences.*
|
||||||
import code.name.monkey.retromusic.util.NavigationUtil
|
import code.name.monkey.retromusic.util.NavigationUtil
|
||||||
|
@ -67,11 +69,15 @@ abstract class AbsSettingsFragment : ATEPreferenceFragmentCompat() {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setDivider(ColorDrawable(Color.TRANSPARENT))
|
setDivider(ColorDrawable(Color.TRANSPARENT))
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||||
|
listView.overScrollMode = View.OVER_SCROLL_NEVER
|
||||||
|
}
|
||||||
|
|
||||||
// CollapsingToolbarLayout consumes insets and insets are not passed to child views
|
// CollapsingToolbarLayout consumes insets and insets are not passed to child views
|
||||||
// So we get insets from decor view
|
// So we get insets from decor view
|
||||||
// https://github.com/material-components/material-components-android/issues/1310
|
// https://github.com/material-components/material-components-android/issues/1310
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(
|
ViewCompat.setOnApplyWindowInsetsListener(
|
||||||
requireActivity().window.decorView
|
requireActivity().rootView
|
||||||
) { _, insets ->
|
) { _, insets ->
|
||||||
listView.updatePadding(bottom = insets.safeGetBottomInsets())
|
listView.updatePadding(bottom = insets.safeGetBottomInsets())
|
||||||
insets
|
insets
|
||||||
|
|
|
@ -28,6 +28,7 @@ import code.name.monkey.retromusic.App
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.databinding.FragmentMainSettingsBinding
|
import code.name.monkey.retromusic.databinding.FragmentMainSettingsBinding
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
|
import code.name.monkey.retromusic.extensions.rootView
|
||||||
import code.name.monkey.retromusic.extensions.safeGetBottomInsets
|
import code.name.monkey.retromusic.extensions.safeGetBottomInsets
|
||||||
import code.name.monkey.retromusic.extensions.show
|
import code.name.monkey.retromusic.extensions.show
|
||||||
import code.name.monkey.retromusic.util.NavigationUtil
|
import code.name.monkey.retromusic.util.NavigationUtil
|
||||||
|
@ -89,9 +90,9 @@ class MainSettingsFragment : Fragment(), View.OnClickListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(
|
ViewCompat.setOnApplyWindowInsetsListener(
|
||||||
requireActivity().window.decorView
|
requireActivity().rootView
|
||||||
) { _, insets ->
|
) { _, insets ->
|
||||||
binding.container.updatePadding(bottom = insets.safeGetBottomInsets())
|
_binding?.container?.updatePadding(bottom = insets.safeGetBottomInsets())
|
||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,15 @@ import com.bumptech.glide.RequestBuilder
|
||||||
import com.bumptech.glide.annotation.GlideExtension
|
import com.bumptech.glide.annotation.GlideExtension
|
||||||
import com.bumptech.glide.annotation.GlideOption
|
import com.bumptech.glide.annotation.GlideOption
|
||||||
import com.bumptech.glide.annotation.GlideType
|
import com.bumptech.glide.annotation.GlideType
|
||||||
|
import com.bumptech.glide.load.DataSource
|
||||||
import com.bumptech.glide.load.Key
|
import com.bumptech.glide.load.Key
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
|
import com.bumptech.glide.load.engine.GlideException
|
||||||
import com.bumptech.glide.request.BaseRequestOptions
|
import com.bumptech.glide.request.BaseRequestOptions
|
||||||
|
import com.bumptech.glide.request.RequestListener
|
||||||
|
import com.bumptech.glide.request.target.Target
|
||||||
|
import com.bumptech.glide.request.transition.DrawableCrossFadeFactory
|
||||||
|
import com.bumptech.glide.request.transition.Transition
|
||||||
import com.bumptech.glide.signature.MediaStoreSignature
|
import com.bumptech.glide.signature.MediaStoreSignature
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
@ -116,6 +122,16 @@ object RetroGlideExtension {
|
||||||
.signature(createSignature(song))
|
.signature(createSignature(song))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@GlideOption
|
||||||
|
fun simpleSongCoverOptions(
|
||||||
|
baseRequestOptions: BaseRequestOptions<*>,
|
||||||
|
song: Song
|
||||||
|
): BaseRequestOptions<*> {
|
||||||
|
return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
|
||||||
|
.signature(createSignature(song))
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@GlideOption
|
@GlideOption
|
||||||
fun albumCoverOptions(
|
fun albumCoverOptions(
|
||||||
|
@ -194,4 +210,33 @@ object RetroGlideExtension {
|
||||||
fun <TranscodeType> getDefaultTransition(): GenericTransitionOptions<TranscodeType> {
|
fun <TranscodeType> getDefaultTransition(): GenericTransitionOptions<TranscodeType> {
|
||||||
return GenericTransitionOptions<TranscodeType>().transition(DEFAULT_ANIMATION)
|
return GenericTransitionOptions<TranscodeType>().transition(DEFAULT_ANIMATION)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/bumptech/glide/issues/527#issuecomment-148840717
|
||||||
|
fun GlideRequest<Drawable>.crossfadeListener(): GlideRequest<Drawable> {
|
||||||
|
return listener(object : RequestListener<Drawable> {
|
||||||
|
override fun onLoadFailed(
|
||||||
|
e: GlideException?,
|
||||||
|
model: Any?,
|
||||||
|
target: Target<Drawable>?,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(
|
||||||
|
resource: Drawable?,
|
||||||
|
model: Any?,
|
||||||
|
target: Target<Drawable>?,
|
||||||
|
dataSource: DataSource?,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
return if (isFirstResource) {
|
||||||
|
false // thumbnail was not shown, do as usual
|
||||||
|
} else DrawableCrossFadeFactory.Builder()
|
||||||
|
.setCrossFadeEnabled(true).build()
|
||||||
|
.build(dataSource, isFirstResource)
|
||||||
|
.transition(resource, target as Transition.ViewAdapter)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
package code.name.monkey.retromusic.glide.audiocover;
|
package code.name.monkey.retromusic.glide.audiocover;
|
||||||
|
|
||||||
|
import org.jaudiotagger.audio.exceptions.CannotReadException;
|
||||||
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
|
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
|
||||||
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
|
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
|
||||||
import org.jaudiotagger.audio.mp3.MP3File;
|
import org.jaudiotagger.audio.mp3.MP3File;
|
||||||
|
@ -45,7 +46,7 @@ public class AudioFileCoverUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If there are any exceptions, we ignore them and continue to the other fallback method
|
// If there are any exceptions, we ignore them and continue to the other fallback method
|
||||||
} catch (ReadOnlyFileException | InvalidAudioFrameException | TagException | IOException ignored) {
|
} catch (ReadOnlyFileException | InvalidAudioFrameException | TagException | IOException | CannotReadException ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method 2: look for album art in external files
|
// Method 2: look for album art in external files
|
||||||
|
|
|
@ -2,9 +2,13 @@ package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import code.name.monkey.retromusic.App
|
import code.name.monkey.retromusic.App
|
||||||
import code.name.monkey.retromusic.BuildConfig
|
import code.name.monkey.retromusic.BuildConfig
|
||||||
|
import code.name.monkey.retromusic.helper.BackupContent.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
@ -24,10 +28,11 @@ object BackupHelper {
|
||||||
zipItems.addAll(getSettingsZipItems(context))
|
zipItems.addAll(getSettingsZipItems(context))
|
||||||
getUserImageZipItems(context)?.let { zipItems.addAll(it) }
|
getUserImageZipItems(context)?.let { zipItems.addAll(it) }
|
||||||
zipItems.addAll(getCustomArtistZipItems(context))
|
zipItems.addAll(getCustomArtistZipItems(context))
|
||||||
|
zipItems.addAll(getQueueZipItems(context))
|
||||||
zipAll(zipItems, backupFile)
|
zipAll(zipItems, backupFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun zipAll(zipItems: List<ZipItem>, backupFile: File) {
|
private suspend fun zipAll(zipItems: List<ZipItem>, backupFile: File) =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
ZipOutputStream(BufferedOutputStream(FileOutputStream(backupFile))).use { out ->
|
ZipOutputStream(BufferedOutputStream(FileOutputStream(backupFile))).use { out ->
|
||||||
|
@ -42,27 +47,42 @@ object BackupHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
it.printStackTrace()
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
Toast.makeText(App.getContext(), "Couldn't create backup", Toast.LENGTH_SHORT)
|
Toast.makeText(App.getContext(), "Couldn't create backup", Toast.LENGTH_SHORT)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
throw Exception(it)
|
||||||
|
}.onSuccess {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
Toast.makeText(
|
||||||
|
App.getContext(),
|
||||||
|
"Backup created successfully",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
Toast.makeText(App.getContext(), "Backup created successfully", Toast.LENGTH_SHORT)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun getDatabaseZipItems(context: Context): List<ZipItem> {
|
private fun getDatabaseZipItems(context: Context): List<ZipItem> {
|
||||||
return context.databaseList().filter {
|
return context.databaseList().filter {
|
||||||
it.endsWith(".db")
|
it.endsWith(".db") && it != queueDatabase
|
||||||
}.map {
|
}.map {
|
||||||
ZipItem(context.getDatabasePath(it).absolutePath, "$DATABASES_PATH${File.separator}$it")
|
ZipItem(context.getDatabasePath(it).absolutePath, "$DATABASES_PATH${File.separator}$it")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getQueueZipItems(context: Context): List<ZipItem> {
|
||||||
|
Log.d("RetroMusic", context.getDatabasePath(queueDatabase).absolutePath)
|
||||||
|
return listOf(
|
||||||
|
ZipItem(
|
||||||
|
context.getDatabasePath(queueDatabase).absolutePath,
|
||||||
|
"$QUEUE_PATH${File.separator}$queueDatabase"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getSettingsZipItems(context: Context): List<ZipItem> {
|
private fun getSettingsZipItems(context: Context): List<ZipItem> {
|
||||||
val sharedPrefPath = context.filesDir.parentFile?.absolutePath + "/shared_prefs/"
|
val sharedPrefPath = context.filesDir.parentFile?.absolutePath + "/shared_prefs/"
|
||||||
return listOf(
|
return listOf(
|
||||||
|
@ -94,33 +114,47 @@ object BackupHelper {
|
||||||
)
|
)
|
||||||
}?.toList() ?: listOf()
|
}?.toList() ?: listOf()
|
||||||
)
|
)
|
||||||
zipItemList.add(
|
File(sharedPrefPath + File.separator + "custom_artist_image.xml").let {
|
||||||
ZipItem(
|
if (it.exists()) {
|
||||||
sharedPrefPath + File.separator + "custom_artist_image.xml",
|
zipItemList.add(
|
||||||
"$CUSTOM_ARTISTS_PATH${File.separator}prefs${File.separator}custom_artist_image.xml"
|
ZipItem(
|
||||||
)
|
it.absolutePath,
|
||||||
)
|
"$CUSTOM_ARTISTS_PATH${File.separator}prefs${File.separator}custom_artist_image.xml"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return zipItemList
|
return zipItemList
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun restoreBackup(context: Context, inputStream: InputStream?) {
|
suspend fun restoreBackup(
|
||||||
|
context: Context,
|
||||||
|
inputStream: InputStream?,
|
||||||
|
contents: List<BackupContent>
|
||||||
|
) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
ZipInputStream(inputStream).use {
|
ZipInputStream(inputStream).use {
|
||||||
var entry = it.nextEntry
|
var entry = it.nextEntry
|
||||||
while (entry != null) {
|
while (entry != null) {
|
||||||
if (entry.isDatabaseEntry()) restoreDatabase(context, it, entry)
|
if (entry.isDatabaseEntry() && contents.contains(PLAYLISTS)) {
|
||||||
if (entry.isPreferenceEntry()) restorePreferences(context, it, entry)
|
restoreDatabase(context, it, entry)
|
||||||
if (entry.isImageEntry()) restoreImages(context, it, entry)
|
} else if (entry.isPreferenceEntry() && contents.contains(SETTINGS)) {
|
||||||
if (entry.isCustomArtistImageEntry()) restoreCustomArtistImages(
|
restorePreferences(context, it, entry)
|
||||||
context,
|
} else if (entry.isImageEntry() && contents.contains(USER_IMAGES)) {
|
||||||
it,
|
restoreImages(context, it, entry)
|
||||||
entry
|
|
||||||
)
|
} else if (entry.isCustomArtistImageEntry() && contents.contains(
|
||||||
if (entry.isCustomArtistPrefEntry()) restoreCustomArtistPrefs(
|
CUSTOM_ARTIST_IMAGES
|
||||||
context,
|
)
|
||||||
it,
|
) {
|
||||||
entry
|
restoreCustomArtistImages(context, it, entry)
|
||||||
)
|
restoreCustomArtistPrefs(context, it, entry)
|
||||||
|
} else if (entry.isQueueEntry() && contents.contains(QUEUE)) {
|
||||||
|
restoreQueueDatabase(context, it, entry)
|
||||||
|
}
|
||||||
|
|
||||||
entry = it.nextEntry
|
entry = it.nextEntry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,6 +204,21 @@ object BackupHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun restoreQueueDatabase(context: Context, zipIn: ZipInputStream, zipEntry: ZipEntry) {
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context).edit(commit = true) {
|
||||||
|
putInt("POSITION", 0)
|
||||||
|
}
|
||||||
|
val filePath =
|
||||||
|
context.filesDir.parent!! + File.separator + DATABASES_PATH + File.separator + zipEntry.getFileName()
|
||||||
|
BufferedOutputStream(FileOutputStream(filePath)).use { bos ->
|
||||||
|
val bytesIn = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||||
|
var read: Int
|
||||||
|
while (zipIn.read(bytesIn).also { read = it } != -1) {
|
||||||
|
bos.write(bytesIn, 0, read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun restoreCustomArtistImages(
|
private fun restoreCustomArtistImages(
|
||||||
context: Context,
|
context: Context,
|
||||||
zipIn: ZipInputStream,
|
zipIn: ZipInputStream,
|
||||||
|
@ -218,10 +267,12 @@ object BackupHelper {
|
||||||
const val BACKUP_EXTENSION = "rmbak"
|
const val BACKUP_EXTENSION = "rmbak"
|
||||||
const val APPEND_EXTENSION = ".$BACKUP_EXTENSION"
|
const val APPEND_EXTENSION = ".$BACKUP_EXTENSION"
|
||||||
private const val DATABASES_PATH = "databases"
|
private const val DATABASES_PATH = "databases"
|
||||||
|
private const val QUEUE_PATH = "queue"
|
||||||
private const val SETTINGS_PATH = "prefs"
|
private const val SETTINGS_PATH = "prefs"
|
||||||
private const val IMAGES_PATH = "userImages"
|
private const val IMAGES_PATH = "userImages"
|
||||||
private const val CUSTOM_ARTISTS_PATH = "artistImages"
|
private const val CUSTOM_ARTISTS_PATH = "artistImages"
|
||||||
private const val THEME_PREFS_KEY_DEFAULT = "[[kabouzeid_app-theme-helper]]"
|
private const val THEME_PREFS_KEY_DEFAULT = "[[kabouzeid_app-theme-helper]]"
|
||||||
|
private const val queueDatabase = "music_playback_state.db"
|
||||||
|
|
||||||
private fun ZipEntry.isDatabaseEntry(): Boolean {
|
private fun ZipEntry.isDatabaseEntry(): Boolean {
|
||||||
return name.startsWith(DATABASES_PATH)
|
return name.startsWith(DATABASES_PATH)
|
||||||
|
@ -243,6 +294,10 @@ object BackupHelper {
|
||||||
return name.startsWith(CUSTOM_ARTISTS_PATH) && name.contains("prefs")
|
return name.startsWith(CUSTOM_ARTISTS_PATH) && name.contains("prefs")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun ZipEntry.isQueueEntry(): Boolean {
|
||||||
|
return name.startsWith(QUEUE_PATH)
|
||||||
|
}
|
||||||
|
|
||||||
private fun ZipEntry.getFileName(): String {
|
private fun ZipEntry.getFileName(): String {
|
||||||
return name.substring(name.lastIndexOf(File.separator))
|
return name.substring(name.lastIndexOf(File.separator))
|
||||||
}
|
}
|
||||||
|
@ -261,4 +316,12 @@ fun CharSequence.sanitize(): String {
|
||||||
.replace("|", "_")
|
.replace("|", "_")
|
||||||
.replace("\\", "_")
|
.replace("\\", "_")
|
||||||
.replace("&", "_")
|
.replace("&", "_")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class BackupContent {
|
||||||
|
SETTINGS,
|
||||||
|
USER_IMAGES,
|
||||||
|
CUSTOM_ARTIST_IMAGES,
|
||||||
|
PLAYLISTS,
|
||||||
|
QUEUE
|
||||||
}
|
}
|
|
@ -31,15 +31,15 @@ object M3UWriter : M3UConstants {
|
||||||
val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION)
|
val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION)
|
||||||
val songs = playlist.getSongs()
|
val songs = playlist.getSongs()
|
||||||
if (songs.isNotEmpty()) {
|
if (songs.isNotEmpty()) {
|
||||||
val bw = BufferedWriter(FileWriter(file))
|
BufferedWriter(FileWriter(file)).use { bw ->
|
||||||
bw.write(M3UConstants.HEADER)
|
bw.write(M3UConstants.HEADER)
|
||||||
for (song in songs) {
|
for (song in songs) {
|
||||||
bw.newLine()
|
bw.newLine()
|
||||||
bw.write(M3UConstants.ENTRY + song.duration + M3UConstants.DURATION_SEPARATOR + song.artistName + " - " + song.title)
|
bw.write(M3UConstants.ENTRY + song.duration + M3UConstants.DURATION_SEPARATOR + song.artistName + " - " + song.title)
|
||||||
bw.newLine()
|
bw.newLine()
|
||||||
bw.write(song.data)
|
bw.write(song.data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bw.close()
|
|
||||||
}
|
}
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
@ -54,15 +54,15 @@ object M3UWriter : M3UConstants {
|
||||||
it.songPrimaryKey
|
it.songPrimaryKey
|
||||||
}.toSongs()
|
}.toSongs()
|
||||||
if (songs.isNotEmpty()) {
|
if (songs.isNotEmpty()) {
|
||||||
val bufferedWriter = BufferedWriter(FileWriter(file))
|
BufferedWriter(FileWriter(file)).use { bw->
|
||||||
bufferedWriter.write(M3UConstants.HEADER)
|
bw.write(M3UConstants.HEADER)
|
||||||
songs.forEach {
|
songs.forEach {
|
||||||
bufferedWriter.newLine()
|
bw.newLine()
|
||||||
bufferedWriter.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title)
|
bw.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title)
|
||||||
bufferedWriter.newLine()
|
bw.newLine()
|
||||||
bufferedWriter.write(it.data)
|
bw.write(it.data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bufferedWriter.close()
|
|
||||||
}
|
}
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
@ -72,15 +72,15 @@ object M3UWriter : M3UConstants {
|
||||||
it.songPrimaryKey
|
it.songPrimaryKey
|
||||||
}.toSongs()
|
}.toSongs()
|
||||||
if (songs.isNotEmpty()) {
|
if (songs.isNotEmpty()) {
|
||||||
val bufferedWriter = outputStream.bufferedWriter()
|
outputStream.bufferedWriter().use{ bw->
|
||||||
bufferedWriter.write(M3UConstants.HEADER)
|
bw.write(M3UConstants.HEADER)
|
||||||
songs.forEach {
|
songs.forEach {
|
||||||
bufferedWriter.newLine()
|
bw.newLine()
|
||||||
bufferedWriter.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title)
|
bw.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title)
|
||||||
bufferedWriter.newLine()
|
bw.newLine()
|
||||||
bufferedWriter.write(it.data)
|
bw.write(it.data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bufferedWriter.close()
|
|
||||||
}
|
}
|
||||||
outputStream.flush()
|
outputStream.flush()
|
||||||
outputStream.close()
|
outputStream.close()
|
||||||
|
|
|
@ -0,0 +1,711 @@
|
||||||
|
/*
|
||||||
|
* 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.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.GestureDetector.SimpleOnGestureListener
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
|
import android.view.animation.LinearInterpolator
|
||||||
|
import android.widget.Scroller
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 歌词 Created by wcy on 2015/11/9.
|
||||||
|
*/
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
class CoverLrcView @JvmOverloads constructor(
|
||||||
|
context: Context?,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : View(context, attrs, defStyleAttr) {
|
||||||
|
private val mLrcEntryList: MutableList<LrcEntry> = ArrayList()
|
||||||
|
private val mLrcPaint = TextPaint()
|
||||||
|
private val mTimePaint = TextPaint()
|
||||||
|
private var mTimeFontMetrics: Paint.FontMetrics? = null
|
||||||
|
private var mPlayDrawable: Drawable? = null
|
||||||
|
private var mDividerHeight = 0f
|
||||||
|
private var mAnimationDuration: Long = 0
|
||||||
|
private var mNormalTextColor = 0
|
||||||
|
private var mNormalTextSize = 0f
|
||||||
|
private var mCurrentTextColor = 0
|
||||||
|
private var mCurrentTextSize = 0f
|
||||||
|
private var mTimelineTextColor = 0
|
||||||
|
private var mTimelineColor = 0
|
||||||
|
private var mTimeTextColor = 0
|
||||||
|
private var mDrawableWidth = 0
|
||||||
|
private var mTimeTextWidth = 0
|
||||||
|
private var mDefaultLabel: String? = null
|
||||||
|
private var mLrcPadding = 0f
|
||||||
|
private var mOnPlayClickListener: OnPlayClickListener? = null
|
||||||
|
private var mAnimator: ValueAnimator? = null
|
||||||
|
private var mGestureDetector: GestureDetector? = null
|
||||||
|
private var mScroller: Scroller? = null
|
||||||
|
private var mOffset = 0f
|
||||||
|
private var mCurrentLine = 0
|
||||||
|
private var flag: Any? = null
|
||||||
|
private var isShowTimeline = false
|
||||||
|
private var isTouching = false
|
||||||
|
private var isFling = false
|
||||||
|
private var mTextGravity // 歌词显示位置,靠左/居中/靠右
|
||||||
|
= 0
|
||||||
|
private val hideTimelineRunnable = Runnable {
|
||||||
|
if (hasLrc() && isShowTimeline) {
|
||||||
|
isShowTimeline = false
|
||||||
|
smoothScrollTo(mCurrentLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手势监听器
|
||||||
|
*/
|
||||||
|
private val mSimpleOnGestureListener: SimpleOnGestureListener =
|
||||||
|
object : SimpleOnGestureListener() {
|
||||||
|
override fun onDown(e: MotionEvent): Boolean {
|
||||||
|
if (mOffset != getOffset(0)) {
|
||||||
|
parent.requestDisallowInterceptTouchEvent(true)
|
||||||
|
}
|
||||||
|
if (hasLrc() && mOnPlayClickListener != null) {
|
||||||
|
mScroller!!.forceFinished(true)
|
||||||
|
removeCallbacks(hideTimelineRunnable)
|
||||||
|
isTouching = true
|
||||||
|
isShowTimeline = true
|
||||||
|
invalidate()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onDown(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onScroll(
|
||||||
|
e1: MotionEvent,
|
||||||
|
e2: MotionEvent,
|
||||||
|
distanceX: Float,
|
||||||
|
distanceY: Float
|
||||||
|
): Boolean {
|
||||||
|
if (mOffset == getOffset(0) && distanceY < 0F) {
|
||||||
|
return super.onScroll(e1, e2, distanceX, distanceY)
|
||||||
|
}
|
||||||
|
if (hasLrc()) {
|
||||||
|
mOffset += -distanceY
|
||||||
|
mOffset = mOffset.coerceAtMost(getOffset(0))
|
||||||
|
mOffset = mOffset.coerceAtLeast(getOffset(mLrcEntryList.size - 1))
|
||||||
|
invalidate()
|
||||||
|
parent.requestDisallowInterceptTouchEvent(true)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onScroll(e1, e2, distanceX, distanceY)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFling(
|
||||||
|
e1: MotionEvent,
|
||||||
|
e2: MotionEvent,
|
||||||
|
velocityX: Float,
|
||||||
|
velocityY: Float
|
||||||
|
): Boolean {
|
||||||
|
if (hasLrc()) {
|
||||||
|
mScroller!!.fling(
|
||||||
|
0,
|
||||||
|
mOffset.toInt(),
|
||||||
|
0,
|
||||||
|
velocityY.toInt(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
getOffset(mLrcEntryList.size - 1).toInt(),
|
||||||
|
getOffset(0).toInt()
|
||||||
|
)
|
||||||
|
isFling = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onFling(e1, e2, velocityX, velocityY)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
||||||
|
if (hasLrc()
|
||||||
|
&& isShowTimeline
|
||||||
|
&& mPlayDrawable!!.bounds.contains(e.x.toInt(), e.y.toInt())
|
||||||
|
) {
|
||||||
|
val centerLine = centerLine
|
||||||
|
val centerLineTime = mLrcEntryList[centerLine].time
|
||||||
|
// onPlayClick 消费了才更新 UI
|
||||||
|
if (mOnPlayClickListener != null && mOnPlayClickListener!!.onPlayClick(
|
||||||
|
centerLineTime
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
isShowTimeline = false
|
||||||
|
removeCallbacks(hideTimelineRunnable)
|
||||||
|
mCurrentLine = centerLine
|
||||||
|
invalidate()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onSingleTapConfirmed(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(attrs: AttributeSet?) {
|
||||||
|
val ta = context.obtainStyledAttributes(attrs, R.styleable.LrcView)
|
||||||
|
mCurrentTextSize = ta.getDimension(
|
||||||
|
R.styleable.LrcView_lrcTextSize, resources.getDimension(R.dimen.lrc_text_size)
|
||||||
|
)
|
||||||
|
mNormalTextSize = ta.getDimension(
|
||||||
|
R.styleable.LrcView_lrcNormalTextSize,
|
||||||
|
resources.getDimension(R.dimen.lrc_text_size)
|
||||||
|
)
|
||||||
|
if (mNormalTextSize == 0f) {
|
||||||
|
mNormalTextSize = mCurrentTextSize
|
||||||
|
}
|
||||||
|
mDividerHeight = ta.getDimension(
|
||||||
|
R.styleable.LrcView_lrcDividerHeight,
|
||||||
|
resources.getDimension(R.dimen.lrc_divider_height)
|
||||||
|
)
|
||||||
|
val defDuration = resources.getInteger(R.integer.lrc_animation_duration)
|
||||||
|
mAnimationDuration =
|
||||||
|
ta.getInt(R.styleable.LrcView_lrcAnimationDuration, defDuration).toLong()
|
||||||
|
mAnimationDuration =
|
||||||
|
if (mAnimationDuration < 0) defDuration.toLong() else mAnimationDuration
|
||||||
|
mNormalTextColor = ta.getColor(
|
||||||
|
R.styleable.LrcView_lrcNormalTextColor,
|
||||||
|
ContextCompat.getColor(context, R.color.lrc_normal_text_color)
|
||||||
|
)
|
||||||
|
mCurrentTextColor = ta.getColor(
|
||||||
|
R.styleable.LrcView_lrcCurrentTextColor,
|
||||||
|
ContextCompat.getColor(context, R.color.lrc_current_text_color)
|
||||||
|
)
|
||||||
|
mTimelineTextColor = ta.getColor(
|
||||||
|
R.styleable.LrcView_lrcTimelineTextColor,
|
||||||
|
ContextCompat.getColor(context, R.color.lrc_timeline_text_color)
|
||||||
|
)
|
||||||
|
mDefaultLabel = ta.getString(R.styleable.LrcView_lrcLabel)
|
||||||
|
mDefaultLabel =
|
||||||
|
if (TextUtils.isEmpty(mDefaultLabel)) context.getString(R.string.empty) else mDefaultLabel
|
||||||
|
mLrcPadding = ta.getDimension(R.styleable.LrcView_lrcPadding, 0f)
|
||||||
|
mTimelineColor = ta.getColor(
|
||||||
|
R.styleable.LrcView_lrcTimelineColor,
|
||||||
|
ContextCompat.getColor(context, R.color.lrc_timeline_color)
|
||||||
|
)
|
||||||
|
val timelineHeight = ta.getDimension(
|
||||||
|
R.styleable.LrcView_lrcTimelineHeight,
|
||||||
|
resources.getDimension(R.dimen.lrc_timeline_height)
|
||||||
|
)
|
||||||
|
mPlayDrawable = ta.getDrawable(R.styleable.LrcView_lrcPlayDrawable)
|
||||||
|
mPlayDrawable =
|
||||||
|
if (mPlayDrawable == null) ContextCompat.getDrawable(
|
||||||
|
context,
|
||||||
|
R.drawable.ic_play_arrow
|
||||||
|
) else mPlayDrawable
|
||||||
|
mTimeTextColor = ta.getColor(
|
||||||
|
R.styleable.LrcView_lrcTimeTextColor,
|
||||||
|
ContextCompat.getColor(context, R.color.lrc_time_text_color)
|
||||||
|
)
|
||||||
|
val timeTextSize = ta.getDimension(
|
||||||
|
R.styleable.LrcView_lrcTimeTextSize,
|
||||||
|
resources.getDimension(R.dimen.lrc_time_text_size)
|
||||||
|
)
|
||||||
|
mTextGravity = ta.getInteger(R.styleable.LrcView_lrcTextGravity, LrcEntry.GRAVITY_CENTER)
|
||||||
|
ta.recycle()
|
||||||
|
mDrawableWidth = resources.getDimension(R.dimen.lrc_drawable_width).toInt()
|
||||||
|
mTimeTextWidth = resources.getDimension(R.dimen.lrc_time_width).toInt()
|
||||||
|
mLrcPaint.isAntiAlias = true
|
||||||
|
mLrcPaint.textSize = mCurrentTextSize
|
||||||
|
mLrcPaint.textAlign = Paint.Align.LEFT
|
||||||
|
mTimePaint.isAntiAlias = true
|
||||||
|
mTimePaint.textSize = timeTextSize
|
||||||
|
mTimePaint.textAlign = Paint.Align.CENTER
|
||||||
|
mTimePaint.strokeWidth = timelineHeight
|
||||||
|
mTimePaint.strokeCap = Paint.Cap.ROUND
|
||||||
|
mTimeFontMetrics = mTimePaint.fontMetrics
|
||||||
|
mGestureDetector = GestureDetector(context, mSimpleOnGestureListener)
|
||||||
|
mGestureDetector!!.setIsLongpressEnabled(false)
|
||||||
|
mScroller = Scroller(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设置非当前行歌词字体颜色 */
|
||||||
|
fun setNormalColor(normalColor: Int) {
|
||||||
|
mNormalTextColor = normalColor
|
||||||
|
postInvalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 普通歌词文本字体大小 */
|
||||||
|
fun setNormalTextSize(size: Float) {
|
||||||
|
mNormalTextSize = size
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 当前歌词文本字体大小 */
|
||||||
|
fun setCurrentTextSize(size: Float) {
|
||||||
|
mCurrentTextSize = size
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设置当前行歌词的字体颜色 */
|
||||||
|
fun setCurrentColor(currentColor: Int) {
|
||||||
|
mCurrentTextColor = currentColor
|
||||||
|
postInvalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设置拖动歌词时选中歌词的字体颜色 */
|
||||||
|
fun setTimelineTextColor(timelineTextColor: Int) {
|
||||||
|
mTimelineTextColor = timelineTextColor
|
||||||
|
postInvalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设置拖动歌词时时间线的颜色 */
|
||||||
|
fun setTimelineColor(timelineColor: Int) {
|
||||||
|
mTimelineColor = timelineColor
|
||||||
|
postInvalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设置拖动歌词时右侧时间字体颜色 */
|
||||||
|
fun setTimeTextColor(timeTextColor: Int) {
|
||||||
|
mTimeTextColor = timeTextColor
|
||||||
|
postInvalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置歌词是否允许拖动
|
||||||
|
*
|
||||||
|
* @param draggable 是否允许拖动
|
||||||
|
* @param onPlayClickListener 设置歌词拖动后播放按钮点击监听器,如果允许拖动,则不能为 null
|
||||||
|
*/
|
||||||
|
fun setDraggable(draggable: Boolean, onPlayClickListener: OnPlayClickListener?) {
|
||||||
|
mOnPlayClickListener = if (draggable) {
|
||||||
|
requireNotNull(onPlayClickListener) { "if draggable == true, onPlayClickListener must not be null" }
|
||||||
|
onPlayClickListener
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置播放按钮点击监听器
|
||||||
|
*
|
||||||
|
* @param onPlayClickListener 如果为非 null ,则激活歌词拖动功能,否则将将禁用歌词拖动功能
|
||||||
|
*/
|
||||||
|
@Deprecated("use {@link #setDraggable(boolean, OnPlayClickListener)} instead")
|
||||||
|
fun setOnPlayClickListener(onPlayClickListener: OnPlayClickListener?) {
|
||||||
|
mOnPlayClickListener = onPlayClickListener
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设置歌词为空时屏幕中央显示的文字,如“暂无歌词” */
|
||||||
|
fun setLabel(label: String?) {
|
||||||
|
runOnUi {
|
||||||
|
mDefaultLabel = label
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载歌词文件
|
||||||
|
*
|
||||||
|
* @param lrcFile 歌词文件
|
||||||
|
*/
|
||||||
|
fun loadLrc(lrcFile: File) {
|
||||||
|
loadLrc(lrcFile, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载双语歌词文件,两种语言的歌词时间戳需要一致
|
||||||
|
*
|
||||||
|
* @param mainLrcFile 第一种语言歌词文件
|
||||||
|
* @param secondLrcFile 第二种语言歌词文件
|
||||||
|
*/
|
||||||
|
fun loadLrc(mainLrcFile: File, secondLrcFile: File?) {
|
||||||
|
runOnUi {
|
||||||
|
reset()
|
||||||
|
val sb = StringBuilder("file://")
|
||||||
|
sb.append(mainLrcFile.path)
|
||||||
|
if (secondLrcFile != null) {
|
||||||
|
sb.append("#").append(secondLrcFile.path)
|
||||||
|
}
|
||||||
|
val flag = sb.toString()
|
||||||
|
this.flag = flag
|
||||||
|
object : AsyncTask<File?, Int?, List<LrcEntry>>() {
|
||||||
|
override fun doInBackground(vararg params: File?): List<LrcEntry>? {
|
||||||
|
return LrcUtils.parseLrc(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPostExecute(lrcEntries: List<LrcEntry>) {
|
||||||
|
if (flag === flag) {
|
||||||
|
onLrcLoaded(lrcEntries)
|
||||||
|
this@CoverLrcView.flag = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute(mainLrcFile, secondLrcFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载歌词文本
|
||||||
|
*
|
||||||
|
* @param lrcText 歌词文本
|
||||||
|
*/
|
||||||
|
fun loadLrc(lrcText: String?) {
|
||||||
|
loadLrc(lrcText, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载双语歌词文本,两种语言的歌词时间戳需要一致
|
||||||
|
*
|
||||||
|
* @param mainLrcText 第一种语言歌词文本
|
||||||
|
* @param secondLrcText 第二种语言歌词文本
|
||||||
|
*/
|
||||||
|
fun loadLrc(mainLrcText: String?, secondLrcText: String?) {
|
||||||
|
runOnUi {
|
||||||
|
reset()
|
||||||
|
val sb = StringBuilder("file://")
|
||||||
|
sb.append(mainLrcText)
|
||||||
|
if (secondLrcText != null) {
|
||||||
|
sb.append("#").append(secondLrcText)
|
||||||
|
}
|
||||||
|
val flag = sb.toString()
|
||||||
|
this.flag = flag
|
||||||
|
object : AsyncTask<String?, Int?, List<LrcEntry>>() {
|
||||||
|
override fun doInBackground(vararg params: String?): List<LrcEntry>? {
|
||||||
|
return LrcUtils.parseLrc(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPostExecute(lrcEntries: List<LrcEntry>) {
|
||||||
|
if (flag === flag) {
|
||||||
|
onLrcLoaded(lrcEntries)
|
||||||
|
this@CoverLrcView.flag = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute(mainLrcText, secondLrcText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 加载在线歌词
|
||||||
|
*
|
||||||
|
* @param lrcUrl 歌词文件的网络地址
|
||||||
|
* @param charset 编码格式
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* 加载在线歌词,默认使用 utf-8 编码
|
||||||
|
*
|
||||||
|
* @param lrcUrl 歌词文件的网络地址
|
||||||
|
*/
|
||||||
|
@JvmOverloads
|
||||||
|
fun loadLrcByUrl(lrcUrl: String, charset: String? = "utf-8") {
|
||||||
|
val flag = "url://$lrcUrl"
|
||||||
|
this.flag = flag
|
||||||
|
object : AsyncTask<String?, Int?, String>() {
|
||||||
|
override fun doInBackground(vararg params: String?): String? {
|
||||||
|
return LrcUtils.getContentFromNetwork(params[0], params[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPostExecute(lrcText: String) {
|
||||||
|
if (flag === flag) {
|
||||||
|
loadLrc(lrcText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute(lrcUrl, charset)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 歌词是否有效
|
||||||
|
*
|
||||||
|
* @return true,如果歌词有效,否则false
|
||||||
|
*/
|
||||||
|
fun hasLrc(): Boolean {
|
||||||
|
return mLrcEntryList.isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新歌词
|
||||||
|
*
|
||||||
|
* @param time 当前播放时间
|
||||||
|
*/
|
||||||
|
fun updateTime(time: Long) {
|
||||||
|
runOnUi {
|
||||||
|
if (!hasLrc()) {
|
||||||
|
return@runOnUi
|
||||||
|
}
|
||||||
|
val line = findShowLine(time)
|
||||||
|
if (line != mCurrentLine) {
|
||||||
|
mCurrentLine = line
|
||||||
|
if (!isShowTimeline) {
|
||||||
|
smoothScrollTo(line)
|
||||||
|
} else {
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||||
|
super.onLayout(changed, left, top, right, bottom)
|
||||||
|
if (changed) {
|
||||||
|
initPlayDrawable()
|
||||||
|
initEntryList()
|
||||||
|
if (hasLrc()) {
|
||||||
|
smoothScrollTo(mCurrentLine, 0L)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas) {
|
||||||
|
super.onDraw(canvas)
|
||||||
|
val centerY = height / 2
|
||||||
|
|
||||||
|
// 无歌词文件
|
||||||
|
if (!hasLrc()) {
|
||||||
|
mLrcPaint.color = mCurrentTextColor
|
||||||
|
@SuppressLint("DrawAllocation") val staticLayout = StaticLayout(
|
||||||
|
mDefaultLabel,
|
||||||
|
mLrcPaint,
|
||||||
|
lrcWidth.toInt(),
|
||||||
|
Layout.Alignment.ALIGN_CENTER,
|
||||||
|
1f,
|
||||||
|
0f,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
drawText(canvas, staticLayout, centerY.toFloat())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val centerLine = centerLine
|
||||||
|
if (isShowTimeline) {
|
||||||
|
mPlayDrawable?.draw(canvas)
|
||||||
|
mTimePaint.color = mTimeTextColor
|
||||||
|
val timeText = LrcUtils.formatTime(mLrcEntryList[centerLine].time)
|
||||||
|
val timeX = (width - mTimeTextWidth / 2).toFloat()
|
||||||
|
val timeY = centerY - (mTimeFontMetrics!!.descent + mTimeFontMetrics!!.ascent) / 2
|
||||||
|
canvas.drawText(timeText, timeX, timeY, mTimePaint)
|
||||||
|
}
|
||||||
|
canvas.translate(0f, mOffset)
|
||||||
|
var y = 0f
|
||||||
|
for (i in mLrcEntryList.indices) {
|
||||||
|
if (i > 0) {
|
||||||
|
y += ((mLrcEntryList[i - 1].height + mLrcEntryList[i].height shr 1)
|
||||||
|
+ mDividerHeight)
|
||||||
|
}
|
||||||
|
if (i == mCurrentLine) {
|
||||||
|
mLrcPaint.textSize = mCurrentTextSize
|
||||||
|
mLrcPaint.color = mCurrentTextColor
|
||||||
|
} else if (isShowTimeline && i == centerLine) {
|
||||||
|
mLrcPaint.color = mTimelineTextColor
|
||||||
|
} else {
|
||||||
|
mLrcPaint.textSize = mNormalTextSize
|
||||||
|
mLrcPaint.color = mNormalTextColor
|
||||||
|
}
|
||||||
|
drawText(canvas, mLrcEntryList[i].staticLayout, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 画一行歌词
|
||||||
|
*
|
||||||
|
* @param y 歌词中心 Y 坐标
|
||||||
|
*/
|
||||||
|
private fun drawText(canvas: Canvas, staticLayout: StaticLayout, y: Float) {
|
||||||
|
canvas.save()
|
||||||
|
canvas.translate(mLrcPadding, y - (staticLayout.height shr 1))
|
||||||
|
staticLayout.draw(canvas)
|
||||||
|
canvas.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||||
|
if (event.action == MotionEvent.ACTION_UP
|
||||||
|
|| event.action == MotionEvent.ACTION_CANCEL
|
||||||
|
) {
|
||||||
|
isTouching = false
|
||||||
|
if (hasLrc() && !isFling) {
|
||||||
|
adjustCenter()
|
||||||
|
postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mGestureDetector!!.onTouchEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun computeScroll() {
|
||||||
|
if (mScroller!!.computeScrollOffset()) {
|
||||||
|
mOffset = mScroller!!.currY.toFloat()
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
if (isFling && mScroller!!.isFinished) {
|
||||||
|
isFling = false
|
||||||
|
if (hasLrc() && !isTouching) {
|
||||||
|
adjustCenter()
|
||||||
|
postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
removeCallbacks(hideTimelineRunnable)
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onLrcLoaded(entryList: List<LrcEntry>?) {
|
||||||
|
if (entryList != null && entryList.isNotEmpty()) {
|
||||||
|
mLrcEntryList.addAll(entryList)
|
||||||
|
}
|
||||||
|
mLrcEntryList.sort()
|
||||||
|
initEntryList()
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initPlayDrawable() {
|
||||||
|
val l = (mTimeTextWidth - mDrawableWidth) / 2
|
||||||
|
val t = height / 2 - mDrawableWidth / 2
|
||||||
|
val r = l + mDrawableWidth
|
||||||
|
val b = t + mDrawableWidth
|
||||||
|
mPlayDrawable!!.setBounds(l, t, r, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initEntryList() {
|
||||||
|
if (!hasLrc() || width == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (lrcEntry in mLrcEntryList) {
|
||||||
|
lrcEntry.init(mLrcPaint, lrcWidth.toInt(), mTextGravity)
|
||||||
|
}
|
||||||
|
mOffset = (height / 2).toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
endAnimation()
|
||||||
|
mScroller!!.forceFinished(true)
|
||||||
|
isShowTimeline = false
|
||||||
|
isTouching = false
|
||||||
|
isFling = false
|
||||||
|
removeCallbacks(hideTimelineRunnable)
|
||||||
|
mLrcEntryList.clear()
|
||||||
|
mOffset = 0f
|
||||||
|
mCurrentLine = 0
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将中心行微调至正中心 */
|
||||||
|
private fun adjustCenter() {
|
||||||
|
smoothScrollTo(centerLine, ADJUST_DURATION)
|
||||||
|
}
|
||||||
|
/** 滚动到某一行 */
|
||||||
|
/** 滚动到某一行 */
|
||||||
|
private fun smoothScrollTo(line: Int, duration: Long = mAnimationDuration) {
|
||||||
|
val offset = getOffset(line)
|
||||||
|
endAnimation()
|
||||||
|
mAnimator = ValueAnimator.ofFloat(mOffset, offset).apply {
|
||||||
|
this.duration = duration
|
||||||
|
interpolator = LinearInterpolator()
|
||||||
|
addUpdateListener { animation: ValueAnimator ->
|
||||||
|
mOffset = animation.animatedValue as Float
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
LrcUtils.resetDurationScale()
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 结束滚动动画 */
|
||||||
|
private fun endAnimation() {
|
||||||
|
if (mAnimator != null && mAnimator!!.isRunning) {
|
||||||
|
mAnimator!!.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 二分法查找当前时间应该显示的行数(最后一个 <= time 的行数) */
|
||||||
|
private fun findShowLine(time: Long): Int {
|
||||||
|
var left = 0
|
||||||
|
var right = mLrcEntryList.size
|
||||||
|
while (left <= right) {
|
||||||
|
val middle = (left + right) / 2
|
||||||
|
val middleTime = mLrcEntryList[middle].time
|
||||||
|
if (time < middleTime) {
|
||||||
|
right = middle - 1
|
||||||
|
} else {
|
||||||
|
if (middle + 1 >= mLrcEntryList.size || time < mLrcEntryList[middle + 1].time) {
|
||||||
|
return middle
|
||||||
|
}
|
||||||
|
left = middle + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取当前在视图中央的行数 */
|
||||||
|
private val centerLine: Int
|
||||||
|
get() {
|
||||||
|
var centerLine = 0
|
||||||
|
var minDistance = Float.MAX_VALUE
|
||||||
|
for (i in mLrcEntryList.indices) {
|
||||||
|
if (abs(mOffset - getOffset(i)) < minDistance) {
|
||||||
|
minDistance = abs(mOffset - getOffset(i))
|
||||||
|
centerLine = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return centerLine
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取歌词距离视图顶部的距离 采用懒加载方式 */
|
||||||
|
private fun getOffset(line: Int): Float {
|
||||||
|
if (mLrcEntryList[line].offset == Float.MIN_VALUE) {
|
||||||
|
var offset = (height / 2).toFloat()
|
||||||
|
for (i in 1..line) {
|
||||||
|
offset -= ((mLrcEntryList[i - 1].height + mLrcEntryList[i].height shr 1)
|
||||||
|
+ mDividerHeight)
|
||||||
|
}
|
||||||
|
mLrcEntryList[line].offset = offset
|
||||||
|
}
|
||||||
|
return mLrcEntryList[line].offset
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取歌词宽度 */
|
||||||
|
private val lrcWidth: Float
|
||||||
|
get() = width - mLrcPadding * 2
|
||||||
|
|
||||||
|
/** 在主线程中运行 */
|
||||||
|
private fun runOnUi(r: Runnable) {
|
||||||
|
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||||
|
r.run()
|
||||||
|
} else {
|
||||||
|
post(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 播放按钮点击监听器,点击后应该跳转到指定播放位置 */
|
||||||
|
interface OnPlayClickListener {
|
||||||
|
/**
|
||||||
|
* 播放按钮被点击,应该跳转到指定播放位置
|
||||||
|
*
|
||||||
|
* @return 是否成功消费该事件,如果成功消费,则会更新UI
|
||||||
|
*/
|
||||||
|
fun onPlayClick(time: Long): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ADJUST_DURATION: Long = 100
|
||||||
|
private const val TIMELINE_KEEP_TIME = 4 * DateUtils.SECOND_IN_MILLIS
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
init(attrs)
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,8 +30,6 @@ import androidx.media.app.NotificationCompat.MediaStyle
|
||||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.activities.MainActivity
|
import code.name.monkey.retromusic.activities.MainActivity
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
|
||||||
import code.name.monkey.retromusic.db.toSongEntity
|
|
||||||
import code.name.monkey.retromusic.glide.GlideApp
|
import code.name.monkey.retromusic.glide.GlideApp
|
||||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||||
|
|
|
@ -15,12 +15,7 @@
|
||||||
package code.name.monkey.retromusic.util
|
package code.name.monkey.retromusic.util
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
|
||||||
import code.name.monkey.retromusic.R
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import com.google.android.play.core.review.ReviewManagerFactory
|
import com.google.android.play.core.review.ReviewManagerFactory
|
||||||
|
|
||||||
object AppRater {
|
object AppRater {
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
package code.name.monkey.retromusic.util
|
package code.name.monkey.retromusic.util
|
||||||
|
|
||||||
import android.content.ContentValues
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
@ -32,14 +31,6 @@ class RingtoneManager(val context: Context) {
|
||||||
fun setRingtone(song: Song) {
|
fun setRingtone(song: Song) {
|
||||||
val resolver = context.contentResolver
|
val resolver = context.contentResolver
|
||||||
val uri = getSongFileUri(song.id)
|
val uri = getSongFileUri(song.id)
|
||||||
try {
|
|
||||||
val values = ContentValues(2)
|
|
||||||
values.put(MediaStore.Audio.AudioColumns.IS_RINGTONE, "1")
|
|
||||||
values.put(MediaStore.Audio.AudioColumns.IS_ALARM, "1")
|
|
||||||
resolver.update(uri, values, null, null)
|
|
||||||
} catch (ignored: UnsupportedOperationException) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val cursor = resolver.query(
|
val cursor = resolver.query(
|
||||||
|
|
|
@ -26,7 +26,6 @@ import androidx.core.graphics.BlendModeCompat.SRC_IN
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
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 com.google.android.material.progressindicator.CircularProgressIndicator
|
|
||||||
|
|
||||||
object ViewUtil {
|
object ViewUtil {
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,14 @@ object ThemeManager {
|
||||||
context: Context
|
context: Context
|
||||||
): Int = when (context.generalThemeValue) {
|
): Int = when (context.generalThemeValue) {
|
||||||
LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
|
LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
|
||||||
DARK,
|
DARK -> AppCompatDelegate.MODE_NIGHT_YES
|
||||||
BLACK -> AppCompatDelegate.MODE_NIGHT_YES
|
BLACK -> {
|
||||||
AUTO -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
if (PreferenceUtil.baseTheme == "dark") {
|
||||||
|
AppCompatDelegate.MODE_NIGHT_YES
|
||||||
|
} else {
|
||||||
|
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,11 @@ package code.name.monkey.retromusic.views
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.drawable.ColorDrawable
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import code.name.monkey.appthemehelper.util.NavigationViewUtil
|
import code.name.monkey.appthemehelper.util.NavigationViewUtil
|
||||||
import code.name.monkey.retromusic.R
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
|
||||||
|
@ -49,7 +47,6 @@ class BottomNavigationBarTinted @JvmOverloads constructor(
|
||||||
accentColor
|
accentColor
|
||||||
)
|
)
|
||||||
itemRippleColor = ColorStateList.valueOf(accentColor.addAlpha(0.08F))
|
itemRippleColor = ColorStateList.valueOf(accentColor.addAlpha(0.08F))
|
||||||
background = ColorDrawable(ATHUtil.resolveColor(context, R.attr.bottomSheetTint))
|
|
||||||
itemActiveIndicatorColor = ColorStateList.valueOf(accentColor.addAlpha(0.12F))
|
itemActiveIndicatorColor = ColorStateList.valueOf(accentColor.addAlpha(0.12F))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
5
app/src/main/res/anim/layout_anim_fade.xml
Normal file
5
app/src/main/res/anim/layout_anim_fade.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:animation="@android:anim/fade_in"
|
||||||
|
android:animationOrder="normal"
|
||||||
|
android:delay="15%" />
|
6
app/src/main/res/drawable/rounded_drawable.xml
Normal file
6
app/src/main/res/drawable/rounded_drawable.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<solid android:color="?colorSurface"/>
|
||||||
|
<corners android:radius="28dp" />
|
||||||
|
</shape>
|
|
@ -3,7 +3,8 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface">
|
android:background="?attr/colorSurface"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -16,20 +17,22 @@
|
||||||
app:navigationIcon="@drawable/ic_keyboard_backspace_black"
|
app:navigationIcon="@drawable/ic_keyboard_backspace_black"
|
||||||
app:title="@string/action_tag_editor" />
|
app:title="@string/action_tag_editor" />
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/imageContainer"
|
android:id="@+id/imageContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:layout_weight="1"
|
|
||||||
android:transitionName="@string/transition_album_art"
|
android:transitionName="@string/transition_album_art"
|
||||||
app:cardCornerRadius="24dp"
|
app:cardCornerRadius="24dp"
|
||||||
app:cardElevation="8dp">
|
app:cardElevation="8dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/editorImage"
|
android:id="@+id/editorImage"
|
||||||
|
@ -50,10 +53,14 @@
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
android:id="@+id/content"
|
android:id="@+id/content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1"
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/imageContainer"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -137,7 +144,7 @@
|
||||||
android:layout_height="52dp" />
|
android:layout_height="52dp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
</LinearLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
|
321
app/src/main/res/layout-land/activity_song_tag_editor.xml
Normal file
321
app/src/main/res/layout-land/activity_song_tag_editor.xml
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:focusableInTouchMode="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="false"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
style="@style/Toolbar"
|
||||||
|
app:navigationIcon="@drawable/ic_keyboard_backspace_black"
|
||||||
|
app:title="@string/action_tag_editor" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/imageContainer"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginVertical="40dp"
|
||||||
|
android:transitionName="@string/transition_album_art"
|
||||||
|
app:cardCornerRadius="@dimen/m3_card_large_radius"
|
||||||
|
app:cardElevation="8dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/editorImage"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
tools:srcCompat="@tools:sample/backgrounds/scenic[5]" />
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:id="@+id/content"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/imageContainer"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/songTextContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/songText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/song"
|
||||||
|
android:inputType="text|textCapWords"
|
||||||
|
android:maxLines="1" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/albumTextContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/albumText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/album"
|
||||||
|
android:inputType="text|textCapWords"
|
||||||
|
android:maxLines="1" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/artistContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/artistText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="@string/artist"
|
||||||
|
android:inputType="text|textCapWords"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/albumArtistContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/albumArtistText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="@string/album_artist"
|
||||||
|
android:inputType="text|textCapWords"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/composerContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/songComposerText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="@string/composer"
|
||||||
|
android:inputType="text|textCapWords"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/genreContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/genreText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="@string/genre"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/yearContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/yearText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="@string/year"
|
||||||
|
android:inputType="text|number"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/trackNumberContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/trackNumberText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="@string/track_hint"
|
||||||
|
android:inputType="text|number"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/discNumberContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/discNumberText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="@string/disc_hint"
|
||||||
|
android:inputType="text|number"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/lyricsContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/lyricsText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="@string/lyrics"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:maxLines="15" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="52dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/saveTags"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingStart="32dp"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingEnd="32dp"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:text="@string/save"
|
||||||
|
app:cornerRadius="25dp"
|
||||||
|
app:icon="@drawable/ic_save"
|
||||||
|
app:iconGravity="textStart"
|
||||||
|
tools:backgroundTint="@color/md_red_400" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
android:descendantFocusability="beforeDescendants"
|
android:descendantFocusability="beforeDescendants"
|
||||||
android:fillViewport="true"
|
android:fillViewport="true"
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:descendantFocusability="beforeDescendants"
|
android:descendantFocusability="beforeDescendants"
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
android:layout_marginEnd="@dimen/toolbar_margin_horizontal"
|
android:layout_marginEnd="@dimen/toolbar_margin_horizontal"
|
||||||
android:descendantFocusability="beforeDescendants"
|
android:descendantFocusability="beforeDescendants"
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
android:transitionGroup="true"
|
android:transitionGroup="true"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
|
|
|
@ -54,29 +54,46 @@
|
||||||
app:navigationIcon="@drawable/ic_keyboard_arrow_down_black"
|
app:navigationIcon="@drawable/ic_keyboard_arrow_down_black"
|
||||||
tools:layout_editor_absoluteY="24dp" />
|
tools:layout_editor_absoluteY="24dp" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
<code.name.monkey.retromusic.views.SeekArc
|
|
||||||
android:id="@+id/volumeSeekBar"
|
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginStart="16dp"
|
android:padding="10dp"
|
||||||
android:layout_marginTop="16dp"
|
app:layout_constraintBottom_toBottomOf="@id/volumeSeekBar"
|
||||||
android:layout_marginEnd="16dp"
|
app:layout_constraintEnd_toEndOf="@id/volumeSeekBar"
|
||||||
android:layout_marginBottom="16dp"
|
app:layout_constraintStart_toStartOf="@id/volumeSeekBar"
|
||||||
android:padding="24dp"
|
app:layout_constraintTop_toTopOf="@id/volumeSeekBar">
|
||||||
app:arcColor="?android:attr/colorControlHighlight"
|
|
||||||
app:arcWidth="4dp"
|
<code.name.monkey.retromusic.views.RetroShapeableImageView
|
||||||
|
android:id="@+id/album_cover"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
tools:srcCompat="@tools:sample/backgrounds/scenic[6]" />
|
||||||
|
|
||||||
|
<code.name.monkey.retromusic.views.RetroShapeableImageView
|
||||||
|
android:id="@+id/album_cover_overlay"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:alpha="0.5"
|
||||||
|
android:scaleType="centerCrop" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<me.tankery.lib.circularseekbar.CircularSeekBar
|
||||||
|
android:id="@+id/volumeSeekBar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="300dp"
|
||||||
|
app:cs_circle_stroke_width="4dp"
|
||||||
|
app:cs_end_angle="60"
|
||||||
|
app:cs_move_outside_circle="true"
|
||||||
|
app:cs_pointer_color="@color/md_grey_200"
|
||||||
|
app:cs_pointer_halo_width="0dp"
|
||||||
|
app:cs_pointer_stroke_width="20dp"
|
||||||
|
app:cs_start_angle="120"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintDimensionRatio="1:1"
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
app:layout_constraintEnd_toEndOf="@id/guideline"
|
app:layout_constraintEnd_toEndOf="@id/guideline"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/playerToolbar"
|
app:layout_constraintTop_toBottomOf="@id/playerToolbar"
|
||||||
app:progressWidth="4dp"
|
|
||||||
app:rotation="180"
|
|
||||||
app:roundEdges="true"
|
|
||||||
app:startAngle="30"
|
|
||||||
app:sweepAngle="300"
|
|
||||||
app:touchInside="false"
|
|
||||||
tools:progress="50" />
|
tools:progress="50" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:descendantFocusability="beforeDescendants"
|
android:descendantFocusability="beforeDescendants"
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
android:transitionGroup="true"
|
android:transitionGroup="true"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
android:paddingBottom="96dp"
|
android:paddingBottom="96dp"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:text="@string/my_top_tracks"
|
android:text="@string/my_top_tracks"
|
||||||
app:icon="@drawable/ic_trending_up"
|
app:icon="@drawable/ic_trending_up"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/actionShuffle"
|
app:layout_constraintEnd_toStartOf="@+id/actionShuffle"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="@+id/history"
|
app:layout_constraintStart_toStartOf="@+id/history"
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
android:id="@+id/content"
|
android:id="@+id/content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
|
android:overScrollMode="@integer/overScrollMode">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
|
@ -6,23 +6,17 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<code.name.monkey.retromusic.views.StatusBarView
|
|
||||||
android:id="@+id/status_bar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:background="?attr/colorSurface"
|
|
||||||
tools:ignore="UnusedAttribute" />
|
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface">
|
android:background="?attr/colorSurface"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appBarLayout"
|
android:id="@+id/appBarLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?colorPrimary"
|
android:fitsSystemWindows="true"
|
||||||
app:liftOnScroll="true">
|
app:liftOnScroll="true">
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
@ -37,15 +31,18 @@
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:id="@+id/container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="fill_vertical"
|
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<code.name.monkey.retromusic.views.LollipopFixedWebView
|
<code.name.monkey.retromusic.views.LollipopFixedWebView
|
||||||
android:id="@+id/license"
|
android:id="@+id/license"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -1,8 +1,84 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
tools:context=".fragments.backup.RestoreActivity">
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/backupNameContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginVertical="8dp"
|
||||||
|
android:hint="@string/label_file_name">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/backupName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:enabled="false" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/materialTextView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/choose_restore_title" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/check_settings"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="true"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:text="@string/action_settings" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/check_databases"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:text="@string/databases_description" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/check_queue"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:text="@string/now_playing_queue" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/check_user_images"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:text="@string/user_images_description" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/check_artist_images"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:text="@string/custom_artist_images" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/cancel_button"
|
||||||
|
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:text="@string/action_cancel" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/restore_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:text="@string/restore" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
|
@ -1,5 +1,6 @@
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true"
|
android:fitsSystemWindows="true"
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -32,6 +34,28 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="16dp">
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<code.name.monkey.retromusic.views.WidthFitSquareCardView
|
||||||
|
android:id="@+id/imageContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="32dp"
|
||||||
|
android:transitionName="@string/transition_album_art"
|
||||||
|
app:cardCornerRadius="@dimen/m3_card_large_radius"
|
||||||
|
app:cardElevation="8dp"
|
||||||
|
app:cardUseCompatPadding="true"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/editorImage"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
tools:srcCompat="@tools:sample/backgrounds/scenic[5]" />
|
||||||
|
|
||||||
|
</code.name.monkey.retromusic.views.WidthFitSquareCardView>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/songTextContainer"
|
android:id="@+id/songTextContainer"
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
@ -142,7 +166,6 @@
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
app:hintEnabled="true">
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/genreText"
|
android:id="@+id/genreText"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -165,7 +188,6 @@
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
app:hintEnabled="true">
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/yearText"
|
android:id="@+id/yearText"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -179,26 +201,56 @@
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<LinearLayout
|
||||||
android:id="@+id/trackNumberContainer"
|
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:baselineAligned="false"
|
||||||
app:hintEnabled="true">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
android:id="@+id/trackNumberContainer"
|
||||||
android:id="@+id/trackNumberText"
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_marginTop="8dp"
|
||||||
android:gravity="center_vertical"
|
android:layout_weight="1"
|
||||||
android:hint="@string/track_hint"
|
app:hintEnabled="true">
|
||||||
android:inputType="text|number"
|
|
||||||
android:maxLines="1" />
|
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/trackNumberText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="@string/track_hint"
|
||||||
|
android:inputType="text|number"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/discNumberContainer"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/discNumberText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="@string/disc_hint"
|
||||||
|
android:inputType="text|number"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/lyricsContainer"
|
android:id="@+id/lyricsContainer"
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
android:id="@+id/container"
|
android:id="@+id/container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<include
|
<include
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:nestedScrollingEnabled="false"
|
android:nestedScrollingEnabled="false"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/songTitle"
|
app:layout_constraintTop_toBottomOf="@id/songTitle"
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:descendantFocusability="beforeDescendants"
|
android:descendantFocusability="beforeDescendants"
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:nestedScrollingEnabled="false"
|
android:nestedScrollingEnabled="false"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:barrierDirection="bottom"
|
app:barrierDirection="bottom"
|
||||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:descendantFocusability="beforeDescendants"
|
android:descendantFocusability="beforeDescendants"
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:descendantFocusability="beforeDescendants"
|
android:descendantFocusability="beforeDescendants"
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<code.name.monkey.retromusic.views.insets.InsetsConstraintLayout
|
<code.name.monkey.retromusic.views.insets.InsetsConstraintLayout
|
||||||
|
|
|
@ -17,15 +17,11 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:background="?colorSurface"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/colorSurface" />
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/statusBarContainer"
|
android:id="@+id/statusBarContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -85,23 +81,45 @@
|
||||||
app:layout_constraintTop_toBottomOf="@+id/titleContainer"
|
app:layout_constraintTop_toBottomOf="@+id/titleContainer"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
<code.name.monkey.retromusic.views.SeekArc
|
<FrameLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/volumeSeekBar"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/volumeSeekBar"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/volumeSeekBar"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/volumeSeekBar">
|
||||||
|
|
||||||
|
<code.name.monkey.retromusic.views.RetroShapeableImageView
|
||||||
|
android:id="@+id/album_cover"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
tools:srcCompat="@tools:sample/backgrounds/scenic[6]" />
|
||||||
|
|
||||||
|
<code.name.monkey.retromusic.views.RetroShapeableImageView
|
||||||
|
android:id="@+id/album_cover_overlay"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:alpha="0.5"
|
||||||
|
android:scaleType="centerCrop" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<me.tankery.lib.circularseekbar.CircularSeekBar
|
||||||
android:id="@+id/volumeSeekBar"
|
android:id="@+id/volumeSeekBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="300dp"
|
android:layout_height="300dp"
|
||||||
android:padding="28dp"
|
app:cs_circle_stroke_width="4dp"
|
||||||
app:arcColor="?android:attr/colorControlHighlight"
|
app:cs_end_angle="60"
|
||||||
app:arcWidth="4dp"
|
app:cs_move_outside_circle="true"
|
||||||
|
app:cs_pointer_color="@color/md_grey_200"
|
||||||
|
app:cs_pointer_halo_width="0dp"
|
||||||
|
app:cs_pointer_stroke_width="20dp"
|
||||||
|
app:cs_start_angle="120"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:progressWidth="4dp"
|
|
||||||
app:rotation="180"
|
|
||||||
app:roundEdges="true"
|
|
||||||
app:startAngle="30"
|
|
||||||
app:sweepAngle="300"
|
|
||||||
app:touchInside="false"
|
|
||||||
tools:progress="50" />
|
tools:progress="50" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
@ -139,14 +157,15 @@
|
||||||
app:tint="@color/md_green_500" />
|
app:tint="@color/md_green_500" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/materialTextView3"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/volume"
|
android:text="@string/volume"
|
||||||
android:textAppearance="@style/TextViewSubtitle2"
|
android:textAppearance="@style/TextViewSubtitle2"
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/volumeSeekBar"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="@+id/volumeSeekBar" />
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/volumeSeekBar" />
|
||||||
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatSeekBar
|
<androidx.appcompat.widget.AppCompatSeekBar
|
||||||
|
|
|
@ -140,7 +140,8 @@
|
||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:listitem="@layout/item_list" />
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
|
tools:listitem="@layout/item_list" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
|
@ -153,7 +153,6 @@
|
||||||
android:layout_height="52dp"
|
android:layout_height="52dp"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:background="?colorAccent"
|
android:background="?colorAccent"
|
||||||
android:foreground="?attr/rectSelector"
|
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
tools:ignore="MissingPrefix"
|
tools:ignore="MissingPrefix"
|
||||||
|
|
|
@ -82,6 +82,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -150,6 +150,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:background="?attr/colorSurface"
|
android:background="?attr/colorSurface"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:descendantFocusability="beforeDescendants"
|
android:descendantFocusability="beforeDescendants"
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<code.name.monkey.retromusic.views.insets.InsetsConstraintLayout
|
<code.name.monkey.retromusic.views.insets.InsetsConstraintLayout
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/songCurrentProgress"
|
android:id="@+id/songCurrentProgress"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/songTotalTime"
|
android:id="@+id/songTotalTime"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
android:transitionGroup="true"
|
android:transitionGroup="true"
|
||||||
app:layout_dodgeInsetEdges="bottom"
|
app:layout_dodgeInsetEdges="bottom"
|
||||||
|
|
|
@ -46,7 +46,8 @@
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
tools:listitem="@layout/item_list"
|
tools:listitem="@layout/item_list"
|
||||||
android:transitionGroup="true"/>
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
|
android:transitionGroup="true" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@android:id/empty"
|
android:id="@android:id/empty"
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/scrollView"
|
android:id="@+id/scrollView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:overScrollMode="@integer/overScrollMode">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/container"
|
android:id="@+id/container"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
@ -7,49 +8,24 @@
|
||||||
<androidx.viewpager.widget.ViewPager
|
<androidx.viewpager.widget.ViewPager
|
||||||
android:id="@+id/viewPager"
|
android:id="@+id/viewPager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent"
|
||||||
|
android:overScrollMode="@integer/overScrollMode">
|
||||||
|
|
||||||
<FrameLayout
|
</androidx.viewpager.widget.ViewPager>
|
||||||
android:id="@+id/playerLyrics"
|
|
||||||
|
<code.name.monkey.retromusic.lyrics.CoverLrcView
|
||||||
|
android:id="@+id/lyricsView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center"
|
android:layout_margin="16dp"
|
||||||
android:alpha="0"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
android:elevation="20dp"
|
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
|
app:lrcLabel="@string/no_lyrics_found"
|
||||||
|
app:lrcNormalTextSize="28sp"
|
||||||
|
app:lrcPadding="24dp"
|
||||||
|
app:lrcTextGravity="center"
|
||||||
|
app:lrcTextSize="32sp"
|
||||||
|
app:lrcTimelineColor="@color/transparent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/mask_lyrics"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/lyrics_mask" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/player_lyrics_line1"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:shadowColor="@color/md_black_1000"
|
|
||||||
android:shadowRadius="4"
|
|
||||||
android:textAppearance="@style/TextViewHeadline5"
|
|
||||||
android:textColor="@color/md_white_1000"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/player_lyrics_line2"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:shadowColor="@color/md_black_1000"
|
|
||||||
android:shadowRadius="4"
|
|
||||||
android:textAppearance="@style/TextViewHeadline5"
|
|
||||||
android:textColor="@color/md_white_1000" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
|
@ -31,6 +31,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
android:paddingBottom="96dp"
|
android:paddingBottom="96dp"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
|
|
|
@ -35,7 +35,9 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
|
android:layoutAnimation="@anim/layout_anim_fade"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
|
@ -73,7 +73,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:scrollbarSize="0dp">
|
android:scrollbars="none"
|
||||||
|
android:overScrollMode="@integer/overScrollMode">
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
<com.google.android.material.chip.ChipGroup
|
||||||
android:id="@+id/searchFilterGroup"
|
android:id="@+id/searchFilterGroup"
|
||||||
|
@ -126,6 +127,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
android:scrollbarStyle="outsideOverlay"
|
android:scrollbarStyle="outsideOverlay"
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||||
|
|
|
@ -66,7 +66,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:nestedScrollingEnabled="false"
|
android:nestedScrollingEnabled="false"
|
||||||
tools:itemCount="10"
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
|
tools:itemCount="10"
|
||||||
tools:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
tools:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||||
tools:listitem="@layout/item_album_card"
|
tools:listitem="@layout/item_album_card"
|
||||||
tools:spanCount="3" />
|
tools:spanCount="3" />
|
||||||
|
|
|
@ -4,5 +4,5 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?actionBarSize"
|
android:layout_height="?actionBarSize"
|
||||||
android:elevation="@dimen/mcab_toolbar_elevation"
|
android:elevation="@dimen/mcab_toolbar_elevation"
|
||||||
android:theme="@style/ThemeOverlay.Material3.ActionBar"
|
android:theme="@style/mcab_theme"
|
||||||
tools:ignore="UnusedAttribute" />
|
tools:ignore="UnusedAttribute" />
|
|
@ -41,6 +41,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:nestedScrollingEnabled="false"
|
android:nestedScrollingEnabled="false"
|
||||||
|
android:overScrollMode="@integer/overScrollMode"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/clickable_area"
|
app:layout_constraintTop_toBottomOf="@+id/clickable_area"
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
<item name="android:windowLightNavigationBar">false</item>
|
<item name="android:windowLightNavigationBar">false</item>
|
||||||
<item name="colorSurface">@color/darkColorSurface</item>
|
<item name="colorSurface">@color/darkColorSurface</item>
|
||||||
<item name="materialCardViewStyle">@style/Widget.MaterialComponents.CardView</item>
|
<item name="materialCardViewStyle">@style/Widget.MaterialComponents.CardView</item>
|
||||||
<item name="bottomSheetTint">@color/bottomSheetColor</item>
|
|
||||||
<item name="elevationOverlayColor">@color/elevationOverlayDark</item>
|
<item name="elevationOverlayColor">@color/elevationOverlayDark</item>
|
||||||
<item name="floatingActionButtonStyle">
|
<item name="floatingActionButtonStyle">
|
||||||
@style/Widget.MaterialComponents.FloatingActionButton
|
@style/Widget.MaterialComponents.FloatingActionButton
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
<item name="bottomNavigationStyle">@style/Widget.Material3.BottomNavigationView</item>
|
<item name="bottomNavigationStyle">@style/Widget.Material3.BottomNavigationView</item>
|
||||||
<item name="materialButtonStyle">@style/MaterialButtonTheme</item>
|
<item name="materialButtonStyle">@style/MaterialButtonTheme</item>
|
||||||
<item name="materialCardViewStyle">@style/Widget.Material3.CardView.Elevated</item>
|
<item name="materialCardViewStyle">@style/Widget.Material3.CardView.Elevated</item>
|
||||||
<item name="bottomSheetTint">@color/bottomSheetColor</item>
|
|
||||||
<item name="elevationOverlayColor">@color/elevationOverlay</item>
|
<item name="elevationOverlayColor">@color/elevationOverlay</item>
|
||||||
<item name="floatingActionButtonStyle">
|
<item name="floatingActionButtonStyle">
|
||||||
@style/Widget.MaterialComponents.FloatingActionButton
|
@style/Widget.MaterialComponents.FloatingActionButton
|
||||||
|
@ -54,7 +53,6 @@
|
||||||
<item name="bottomNavigationStyle">@style/Widget.Material3.BottomNavigationView</item>
|
<item name="bottomNavigationStyle">@style/Widget.Material3.BottomNavigationView</item>
|
||||||
<item name="android:windowBackground">@color/window_color_dark</item>
|
<item name="android:windowBackground">@color/window_color_dark</item>
|
||||||
<item name="materialCardViewStyle">@style/Widget.Material3.CardView.Elevated</item>
|
<item name="materialCardViewStyle">@style/Widget.Material3.CardView.Elevated</item>
|
||||||
<item name="bottomSheetTint">@color/bottomSheetColor</item>
|
|
||||||
<item name="elevationOverlayColor">@color/elevationOverlay</item>
|
<item name="elevationOverlayColor">@color/elevationOverlay</item>
|
||||||
<item name="floatingActionButtonStyle">
|
<item name="floatingActionButtonStyle">
|
||||||
@style/Widget.MaterialComponents.FloatingActionButton
|
@style/Widget.MaterialComponents.FloatingActionButton
|
||||||
|
@ -78,7 +76,6 @@
|
||||||
<item name="materialButtonStyle">@style/MaterialButtonTheme</item>
|
<item name="materialButtonStyle">@style/MaterialButtonTheme</item>
|
||||||
<item name="bottomNavigationStyle">@style/Widget.Material3.BottomNavigationView</item>
|
<item name="bottomNavigationStyle">@style/Widget.Material3.BottomNavigationView</item>
|
||||||
<item name="materialCardViewStyle">@style/Widget.Material3.CardView.Elevated</item>
|
<item name="materialCardViewStyle">@style/Widget.Material3.CardView.Elevated</item>
|
||||||
<item name="bottomSheetTint">@color/bottomSheetColorLight</item>
|
|
||||||
<item name="elevationOverlayColor">@color/elevationOverlayLight</item>
|
<item name="elevationOverlayColor">@color/elevationOverlayLight</item>
|
||||||
<item name="floatingActionButtonStyle">
|
<item name="floatingActionButtonStyle">
|
||||||
@style/Widget.MaterialComponents.FloatingActionButton
|
@style/Widget.MaterialComponents.FloatingActionButton
|
||||||
|
|
|
@ -4,4 +4,5 @@
|
||||||
<bool name="md3_enabled">true</bool>
|
<bool name="md3_enabled">true</bool>
|
||||||
|
|
||||||
<bool name="colored_notification_available">false</bool>
|
<bool name="colored_notification_available">false</bool>
|
||||||
|
<integer name="overScrollMode">0</integer>
|
||||||
</resources>
|
</resources>
|
|
@ -6,7 +6,6 @@
|
||||||
<attr name="defaultFooterColor" format="color" />
|
<attr name="defaultFooterColor" format="color" />
|
||||||
<attr name="toolbarPopupTheme" format="reference" />
|
<attr name="toolbarPopupTheme" format="reference" />
|
||||||
<attr name="lineHeightHint" format="dimension" />
|
<attr name="lineHeightHint" format="dimension" />
|
||||||
<attr name="bottomSheetTint" format="reference" />
|
|
||||||
|
|
||||||
<declare-styleable name="NetworkImageView">
|
<declare-styleable name="NetworkImageView">
|
||||||
<attr name="url_link" format="string" />
|
<attr name="url_link" format="string" />
|
||||||
|
|
|
@ -28,4 +28,6 @@
|
||||||
<bool name="md3_enabled">false</bool>
|
<bool name="md3_enabled">false</bool>
|
||||||
|
|
||||||
<bool name="colored_notification_available">true</bool>
|
<bool name="colored_notification_available">true</bool>
|
||||||
|
<integer name="overScrollMode">2</integer>
|
||||||
|
<bool name="allowBackup">true</bool>
|
||||||
</resources>
|
</resources>
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<integer name="lrc_animation_duration">1000</integer>
|
<integer name="lrc_animation_duration">1000</integer>
|
||||||
<dimen name="lrc_text_size">16sp</dimen>
|
<dimen name="lrc_text_size">20sp</dimen>
|
||||||
<dimen name="lrc_time_text_size">12sp</dimen>
|
<dimen name="lrc_time_text_size">16sp</dimen>
|
||||||
<dimen name="lrc_divider_height">16dp</dimen>
|
<dimen name="lrc_divider_height">16dp</dimen>
|
||||||
<dimen name="lrc_timeline_height">1dp</dimen>
|
<dimen name="lrc_timeline_height">1dp</dimen>
|
||||||
<dimen name="lrc_drawable_width">30dp</dimen>
|
<dimen name="lrc_drawable_width">30dp</dimen>
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
<string name="app_widget_big_name">Full Image</string>
|
<string name="app_widget_big_name">Full Image</string>
|
||||||
<string name="app_widget_card_name">Card</string>
|
<string name="app_widget_card_name">Card</string>
|
||||||
<string name="app_widget_classic_name">Classic</string>
|
<string name="app_widget_classic_name">Classic</string>
|
||||||
|
<string name="app_widget_md3_name">MD3</string>
|
||||||
<string name="app_widget_small_name">Small</string>
|
<string name="app_widget_small_name">Small</string>
|
||||||
<string name="app_widget_text_name">Minimal Text</string>
|
<string name="app_widget_text_name">Minimal Text</string>
|
||||||
<string name="artist">Artist</string>
|
<string name="artist">Artist</string>
|
||||||
|
@ -81,6 +82,7 @@
|
||||||
<string name="audio_focus_denied">Audio focus denied.</string>
|
<string name="audio_focus_denied">Audio focus denied.</string>
|
||||||
<string name="audio_settings_summary">Change the sound settings and adjust the equalizer controls</string>
|
<string name="audio_settings_summary">Change the sound settings and adjust the equalizer controls</string>
|
||||||
<string name="auto">Auto</string>
|
<string name="auto">Auto</string>
|
||||||
|
<string name="backup_restore_settings_summary">Backup and restore your settings, playlists</string>
|
||||||
<string name="backup_restore_title">
|
<string name="backup_restore_title">
|
||||||
<![CDATA[Backup & Restore]]>
|
<![CDATA[Backup & Restore]]>
|
||||||
</string>
|
</string>
|
||||||
|
@ -113,6 +115,7 @@
|
||||||
<string name="cascading">Cascading</string>
|
<string name="cascading">Cascading</string>
|
||||||
<string name="changelog">Changelog</string>
|
<string name="changelog">Changelog</string>
|
||||||
<string name="changelog_summary">Check out What\'s New</string>
|
<string name="changelog_summary">Check out What\'s New</string>
|
||||||
|
<string name="choose_restore_title">Choose what to restore</string>
|
||||||
<string name="circle">Circle</string>
|
<string name="circle">Circle</string>
|
||||||
<string name="circular">Circular</string>
|
<string name="circular">Circular</string>
|
||||||
<string name="classic">Classic</string>
|
<string name="classic">Classic</string>
|
||||||
|
@ -132,7 +135,9 @@
|
||||||
<string name="created_playlist_x">Created playlist %1$s.</string>
|
<string name="created_playlist_x">Created playlist %1$s.</string>
|
||||||
<string name="credit_title">Members and contributors </string>
|
<string name="credit_title">Members and contributors </string>
|
||||||
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
||||||
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kinda Dark</string>
|
<string name="dark_theme_name">Kinda Dark</string>
|
||||||
|
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
||||||
<string name="delete_playlist_title">Delete playlist</string>
|
<string name="delete_playlist_title">Delete playlist</string>
|
||||||
<string name="delete_playlist_x">
|
<string name="delete_playlist_x">
|
||||||
<![CDATA[Delete the playlist <b>%1$s</b>?]]>
|
<![CDATA[Delete the playlist <b>%1$s</b>?]]>
|
||||||
|
@ -156,6 +161,7 @@
|
||||||
<string name="device_info">Device info</string>
|
<string name="device_info">Device info</string>
|
||||||
<string name="dialog_message_set_ringtone">Allow Retro Music to modify audio settings</string>
|
<string name="dialog_message_set_ringtone">Allow Retro Music to modify audio settings</string>
|
||||||
<string name="dialog_title_set_ringtone">Set ringtone</string>
|
<string name="dialog_title_set_ringtone">Set ringtone</string>
|
||||||
|
<string name="disc_hint">Disc Number</string>
|
||||||
<string name="do_you_want_to_clear_the_blacklist">Do you want to clear the blacklist?</string>
|
<string name="do_you_want_to_clear_the_blacklist">Do you want to clear the blacklist?</string>
|
||||||
<string name="do_you_want_to_remove_from_the_blacklist">
|
<string name="do_you_want_to_remove_from_the_blacklist">
|
||||||
<![CDATA[Do you want to remove <b>%1$s</b> from the blacklist?]]>
|
<![CDATA[Do you want to remove <b>%1$s</b> from the blacklist?]]>
|
||||||
|
@ -404,6 +410,7 @@
|
||||||
<string name="reset_action">Reset</string>
|
<string name="reset_action">Reset</string>
|
||||||
<string name="reset_artist_image">Reset artist image</string>
|
<string name="reset_artist_image">Reset artist image</string>
|
||||||
<string name="restore">Restore</string>
|
<string name="restore">Restore</string>
|
||||||
|
<string name="restore_message">Do you want to restore backup?</string>
|
||||||
<string name="restored_previous_purchase_please_restart">Restored previous purchase. Please restart the app to make use of all features.</string>
|
<string name="restored_previous_purchase_please_restart">Restored previous purchase. Please restart the app to make use of all features.</string>
|
||||||
<string name="restored_previous_purchases">Restored previous purchases.</string>
|
<string name="restored_previous_purchases">Restored previous purchases.</string>
|
||||||
<string name="restoring_purchase">Restoring purchase…</string>
|
<string name="restoring_purchase">Restoring purchase…</string>
|
||||||
|
@ -453,8 +460,8 @@
|
||||||
<string name="sort_order">Sort order</string>
|
<string name="sort_order">Sort order</string>
|
||||||
<string name="sort_order_a_z">Ascending</string>
|
<string name="sort_order_a_z">Ascending</string>
|
||||||
<string name="sort_order_album">Album</string>
|
<string name="sort_order_album">Album</string>
|
||||||
<string name="sort_order_artist">Artist</string>
|
|
||||||
<string name="sort_order_album_artist">@string/album_artist</string>
|
<string name="sort_order_album_artist">@string/album_artist</string>
|
||||||
|
<string name="sort_order_artist">Artist</string>
|
||||||
<string name="sort_order_composer">Composer</string>
|
<string name="sort_order_composer">Composer</string>
|
||||||
<string name="sort_order_date">Date added</string>
|
<string name="sort_order_date">Date added</string>
|
||||||
<string name="sort_order_date_modified">Date modified</string>
|
<string name="sort_order_date_modified">Date modified</string>
|
||||||
|
@ -480,6 +487,7 @@
|
||||||
<string name="tiny">Tiny</string>
|
<string name="tiny">Tiny</string>
|
||||||
<string name="tiny_card_style">Tiny card</string>
|
<string name="tiny_card_style">Tiny card</string>
|
||||||
<string name="title">Title</string>
|
<string name="title">Title</string>
|
||||||
|
<string name="title_new_backup">New Backup</string>
|
||||||
<string name="today">Today</string>
|
<string name="today">Today</string>
|
||||||
<string name="top_albums">Top albums</string>
|
<string name="top_albums">Top albums</string>
|
||||||
<string name="top_artists">Top artists</string>
|
<string name="top_artists">Top artists</string>
|
||||||
|
@ -495,6 +503,7 @@
|
||||||
<string name="up_next">Up next</string>
|
<string name="up_next">Up next</string>
|
||||||
<string name="update_image">Update image</string>
|
<string name="update_image">Update image</string>
|
||||||
<string name="updating">Updating…</string>
|
<string name="updating">Updating…</string>
|
||||||
|
<string name="user_images_description">User Images</string>
|
||||||
<string name="user_name">User Name</string>
|
<string name="user_name">User Name</string>
|
||||||
<string name="username">Username</string>
|
<string name="username">Username</string>
|
||||||
<string name="version">Version</string>
|
<string name="version">Version</string>
|
||||||
|
@ -515,8 +524,4 @@
|
||||||
<string name="you_have_to_select_at_least_one_category">You have to select at least one category.</string>
|
<string name="you_have_to_select_at_least_one_category">You have to select at least one category.</string>
|
||||||
<string name="you_will_be_forwarded_to_the_issue_tracker_website">You will be forwarded to the issue tracker website.</string>
|
<string name="you_will_be_forwarded_to_the_issue_tracker_website">You will be forwarded to the issue tracker website.</string>
|
||||||
<string name="your_account_data_is_only_used_for_authentication">Your account data is only used for authentication.</string>
|
<string name="your_account_data_is_only_used_for_authentication">Your account data is only used for authentication.</string>
|
||||||
<string name="restore_message">Do you want to restore backup?</string>
|
|
||||||
<string name="title_new_backup">New Backup</string>
|
|
||||||
<string name="backup_restore_settings_summary">Backup and restore your settings, playlists</string>
|
|
||||||
<string name="app_widget_md3_name">MD3</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue