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()
|
||||
shrinkResources true
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
debug {
|
||||
|
@ -95,7 +95,7 @@ dependencies {
|
|||
implementation 'androidx.annotation:annotation:1.3.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
|
||||
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.palette:palette-ktx:1.0.0'
|
||||
|
||||
|
@ -105,12 +105,11 @@ dependencies {
|
|||
//WebServer by NanoHttpd
|
||||
implementation "org.nanohttpd:nanohttpd:2.3.1"
|
||||
|
||||
def nav_version = '2.4.0-beta02'
|
||||
implementation "androidx.navigation:navigation-runtime-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-runtime-ktx:$navigation_version"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$navigation_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-ktx:$room_version"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
|
@ -121,7 +120,7 @@ dependencies {
|
|||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
||||
|
||||
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'
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||
|
@ -138,7 +137,7 @@ dependencies {
|
|||
|
||||
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-android:$kotlin_coroutines_version"
|
||||
|
||||
|
@ -153,12 +152,13 @@ dependencies {
|
|||
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
|
||||
|
||||
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.r0adkll:slidableactivity:2.1.0'
|
||||
implementation 'com.heinrichreimersoftware:material-intro:2.0.0'
|
||||
implementation 'com.github.dhaval2404:imagepicker:2.1'
|
||||
implementation 'me.zhanghai.android.fastscroll:library:1.1.7'
|
||||
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'
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<bool name="md3_available">true</bool>
|
||||
<bool name="allowBackup">false</bool>
|
||||
</resources>
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
<application
|
||||
android:name=".App"
|
||||
android:allowBackup="true"
|
||||
android:allowBackup="@bool/allowBackup"
|
||||
android:configChanges="locale|layoutDirection"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
|
@ -123,15 +123,38 @@
|
|||
<activity android:name=".activities.LockScreenActivity" />
|
||||
<activity
|
||||
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>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<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="content" />
|
||||
<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" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
@ -273,10 +296,9 @@
|
|||
<service
|
||||
android:name=".service.MusicService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="mediaPlayback"
|
||||
android:label="@string/app_name"
|
||||
tools:ignore="ExportedService">
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.media.browse.MediaBrowserService" />
|
||||
</intent-filter>
|
||||
|
|
|
@ -24,40 +24,48 @@
|
|||
padding-top: 8px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p><b><a href="https://github.com/kabouzeid/Phonograph" title="Phonograph"> Phonograph</a></b> by
|
||||
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"
|
||||
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/square/retrofit" title="Retrofit"> Retrofit</a></b> by Square team
|
||||
</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">
|
||||
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"
|
||||
title="Android In-App Billing v3 Library"> Android In-App Billing v3 Library</a></b> by
|
||||
Henning Dodenhof</p>
|
||||
<p><b><a href="https://github.com/h6ah4i/android-advancedrecyclerview"
|
||||
title="Advanced RecyclerView"> Advanced RecyclerView</a></b> by Haruki Hasegawa</p>
|
||||
<p><b><a href="https://github.com/ksoichiro/Android-ObservableScrollView"
|
||||
title="Android-ObservableScrollView"> Android-ObservableScrollView</a></b> by Soichiro
|
||||
Kashima</p>
|
||||
<p><b><a href="https://github.com/Ereza/CustomActivityOnCrash"
|
||||
title="Custom Activity on Crash">Custom Activity on Crash</a></b> by Eduard Ereza Martínez
|
||||
</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://www.techjuice.pk" title="City wallpaper"> Material Design City Wallpaper</a></b>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -21,7 +21,6 @@ import android.graphics.PorterDuff
|
|||
import android.os.Bundle
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.widget.SeekBar
|
||||
import androidx.activity.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
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.db.toSongEntity
|
||||
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.glide.BlurTransformation
|
||||
import code.name.monkey.retromusic.glide.GlideApp
|
||||
|
@ -50,7 +47,6 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
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.os.Bundle
|
||||
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.util.ATHUtil.isWindowBackgroundDark
|
||||
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.retromusic.R
|
||||
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.InputStreamReader
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
/** Created by hemanths on 2019-09-27. */
|
||||
class LicenseActivity : AbsThemeActivity() {
|
||||
private lateinit var binding: ActivityLicenseBinding
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_license)
|
||||
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
||||
setSupportActionBar(toolbar)
|
||||
ToolbarContentTintHelper.colorBackButton(toolbar)
|
||||
toolbar.setBackgroundColor(resolveColor(this, R.attr.colorSurface))
|
||||
val webView = findViewById<WebView>(R.id.license)
|
||||
binding = ActivityLicenseBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setSupportActionBar(binding.toolbar)
|
||||
ToolbarContentTintHelper.colorBackButton(binding.toolbar)
|
||||
try {
|
||||
val buf = StringBuilder()
|
||||
val json = assets.open("oldindex.html")
|
||||
val br = BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8))
|
||||
var str: String?
|
||||
while (br.readLine().also { str = it } != null) {
|
||||
buf.append(str)
|
||||
BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8)).use { br ->
|
||||
var str: String?
|
||||
while (br.readLine().also { str = it } != null) {
|
||||
buf.append(str)
|
||||
}
|
||||
}
|
||||
br.close()
|
||||
|
||||
// Inject color values for WebView body background and links
|
||||
val isDark = isWindowBackgroundDark(this)
|
||||
|
@ -72,12 +71,13 @@ class LicenseActivity : AbsThemeActivity() {
|
|||
lightenColor(accentColor(this))
|
||||
)
|
||||
)
|
||||
webView.loadData(changeLog, "text/html", "UTF-8")
|
||||
binding.license.loadData(changeLog, "text/html", "UTF-8")
|
||||
} catch (e: Throwable) {
|
||||
webView.loadData(
|
||||
binding.license.loadData(
|
||||
"<h1>Unable to load</h1><p>" + e.localizedMessage + "</p>", "text/html", "UTF-8"
|
||||
)
|
||||
}
|
||||
binding.license.drawAboveSystemBars()
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
|
|
@ -22,9 +22,9 @@ import android.net.Uri
|
|||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.view.View
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.core.view.isVisible
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
|
||||
|
@ -84,12 +84,12 @@ class PermissionActivity : AbsMusicServiceActivity() {
|
|||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
override fun onResume() {
|
||||
if (hasStoragePermission()) {
|
||||
binding.storagePermission.checkImage.visibility = View.VISIBLE
|
||||
binding.storagePermission.checkImage.isVisible = true
|
||||
binding.storagePermission.checkImage.imageTintList =
|
||||
ColorStateList.valueOf(ThemeStore.accentColor(this))
|
||||
}
|
||||
if (hasAudioPermission()) {
|
||||
binding.audioPermission.checkImage.visibility = View.VISIBLE
|
||||
binding.audioPermission.checkImage.isVisible = true
|
||||
binding.audioPermission.checkImage.imageTintList =
|
||||
ColorStateList.valueOf(ThemeStore.accentColor(this))
|
||||
}
|
||||
|
|
|
@ -34,12 +34,16 @@ class SettingsActivity : AbsThemeActivity(), ColorCallback, OnThemeChangedListen
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
val mSavedInstanceState = extra<Bundle>(TAG).value ?: savedInstanceState
|
||||
super.onCreate(mSavedInstanceState)
|
||||
setLightStatusBarAuto(surfaceColor())
|
||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setupToolbar()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setNavigationBarColorPreOreo(surfaceColor())
|
||||
}
|
||||
|
||||
private fun setupToolbar() {
|
||||
applyToolbar(binding.toolbar)
|
||||
val navController: NavController = findNavController(R.id.contentFrame)
|
||||
|
@ -81,7 +85,6 @@ class SettingsActivity : AbsThemeActivity(), ColorCallback, OnThemeChangedListen
|
|||
ThemeStore.editTheme(this).accentColor(color).commit()
|
||||
if (VersionUtils.hasNougatMR())
|
||||
DynamicShortcutManager(this).updateDynamicShortcuts()
|
||||
|
||||
restart()
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import code.name.monkey.retromusic.R
|
|||
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
|
||||
import code.name.monkey.retromusic.databinding.ActivityWhatsNewBinding
|
||||
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.setTaskDescriptionColorAuto
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion
|
||||
|
@ -38,12 +39,12 @@ class WhatsNewActivity : AbsThemeActivity() {
|
|||
try {
|
||||
val buf = StringBuilder()
|
||||
val json = assets.open("retro-changelog.html")
|
||||
val br = BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8))
|
||||
var str: String?
|
||||
while (br.readLine().also { str = it } != null) {
|
||||
buf.append(str)
|
||||
BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8)).use { br ->
|
||||
var str: String?
|
||||
while (br.readLine().also { str = it } != null) {
|
||||
buf.append(str)
|
||||
}
|
||||
}
|
||||
br.close()
|
||||
|
||||
// Inject color values for WebView body background and links
|
||||
val isDark = isWindowBackgroundDark(this)
|
||||
|
@ -100,6 +101,7 @@ class WhatsNewActivity : AbsThemeActivity() {
|
|||
binding.tgFab.extend()
|
||||
}
|
||||
}
|
||||
binding.webView.drawAboveSystemBars()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -14,12 +14,15 @@
|
|||
*/
|
||||
package code.name.monkey.retromusic.activities.base
|
||||
|
||||
import android.animation.ArgbEvaluator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import android.view.animation.PathInterpolator
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.view.ViewCompat
|
||||
|
@ -28,7 +31,6 @@ import androidx.core.view.isGone
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.commit
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.retromusic.R
|
||||
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.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import code.name.monkey.retromusic.util.ViewUtil
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
|
||||
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||
companion object {
|
||||
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
|
||||
|
@ -78,14 +82,27 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
|||
private var nowPlayingScreen: NowPlayingScreen? = null
|
||||
private var taskColor: Int = 0
|
||||
private var paletteColor: Int = Color.WHITE
|
||||
private var navigationBarColor = 0
|
||||
protected abstract fun createContentView(): SlidingMusicPanelLayoutBinding
|
||||
private val panelState: Int
|
||||
get() = bottomSheetBehavior.state
|
||||
private lateinit var binding: SlidingMusicPanelLayoutBinding
|
||||
|
||||
private var navigationBarColorAnimator: ValueAnimator? = null
|
||||
private val argbEvaluator: ArgbEvaluator = ArgbEvaluator()
|
||||
|
||||
private val bottomSheetCallbackList = object : BottomSheetCallback() {
|
||||
|
||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||
setMiniPlayerAlphaProgress(slideOffset)
|
||||
navigationBarColorAnimator?.cancel()
|
||||
setNavigationBarColorPreOreo(
|
||||
argbEvaluator.evaluate(
|
||||
slideOffset,
|
||||
surfaceColor(),
|
||||
navigationBarColor
|
||||
) as Int
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||
|
@ -131,6 +148,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
|||
updateColor()
|
||||
binding.slidingPanel.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
|
||||
bottomNavigationView.backgroundTintList = ColorStateList.valueOf(darkAccentColor())
|
||||
navigationBarColor = surfaceColor()
|
||||
}
|
||||
|
||||
private fun setupBottomSheet() {
|
||||
|
@ -177,9 +195,25 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
|||
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() {
|
||||
setMiniPlayerAlphaProgress(0F)
|
||||
// restore values
|
||||
animateNavigationBarColor(surfaceColor())
|
||||
setLightStatusBarAuto(surfaceColor())
|
||||
setLightNavigationAuto()
|
||||
setTaskDescriptionColor(taskColor)
|
||||
|
@ -252,18 +286,25 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
|||
|
||||
private fun onPaletteColorChanged() {
|
||||
if (panelState == STATE_EXPANDED) {
|
||||
navigationBarColor = surfaceColor()
|
||||
setTaskDescColor(paletteColor)
|
||||
val isColorLight = ColorUtil.isColorLight(paletteColor)
|
||||
if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat)) {
|
||||
setLightNavigationBar(true)
|
||||
setLightStatusBar(isColorLight)
|
||||
} else if (nowPlayingScreen == Card || nowPlayingScreen == Blur || nowPlayingScreen == BlurCard) {
|
||||
animateNavigationBarColor(Color.BLACK)
|
||||
navigationBarColor = Color.BLACK
|
||||
setLightStatusBar(false)
|
||||
setLightNavigationBar(true)
|
||||
} else if (nowPlayingScreen == Color || nowPlayingScreen == Tiny || nowPlayingScreen == Gradient) {
|
||||
animateNavigationBarColor(paletteColor)
|
||||
navigationBarColor = paletteColor
|
||||
setLightNavigationBar(isColorLight)
|
||||
setLightStatusBar(isColorLight)
|
||||
} else if (nowPlayingScreen == Full) {
|
||||
animateNavigationBarColor(paletteColor)
|
||||
navigationBarColor = paletteColor
|
||||
setLightNavigationBar(isColorLight)
|
||||
setLightStatusBar(false)
|
||||
} else if (nowPlayingScreen == Classic) {
|
||||
|
@ -273,10 +314,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
|||
} else {
|
||||
setLightStatusBar(
|
||||
ColorUtil.isColorLight(
|
||||
ATHUtil.resolveColor(
|
||||
this,
|
||||
android.R.attr.windowBackground
|
||||
)
|
||||
surfaceColor()
|
||||
)
|
||||
)
|
||||
setLightNavigationBar(true)
|
||||
|
|
|
@ -34,7 +34,6 @@ import androidx.appcompat.app.AlertDialog
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.viewbinding.ViewBinding
|
||||
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.VersionUtils
|
||||
import code.name.monkey.retromusic.R
|
||||
|
@ -60,14 +59,13 @@ import java.io.File
|
|||
import java.util.*
|
||||
|
||||
abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
|
||||
abstract val editorImage: ImageView?
|
||||
abstract val editorImage: ImageView
|
||||
val repository by inject<Repository>()
|
||||
|
||||
lateinit var saveFab: MaterialButton
|
||||
protected var id: Long = 0
|
||||
private set
|
||||
private var paletteColorPrimary: Int = 0
|
||||
private var isInNoImageMode: Boolean = false
|
||||
private var songPaths: List<String>? = null
|
||||
private var savedSongPaths: List<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?
|
||||
get() {
|
||||
return try {
|
||||
|
@ -239,7 +246,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
|
|||
getString(R.string.web_search),
|
||||
getString(R.string.remove_cover)
|
||||
)
|
||||
editorImage?.setOnClickListener { show }
|
||||
editorImage.setOnClickListener { show }
|
||||
}
|
||||
|
||||
private fun startImagePicker() {
|
||||
|
@ -306,17 +313,6 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
|
|||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
protected fun setNoImageMode() {
|
||||
isInNoImageMode = true
|
||||
setColors(
|
||||
intent.getIntExtra(
|
||||
EXTRA_PALETTE,
|
||||
ATHUtil.resolveColor(this, R.attr.colorPrimary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
protected fun dataChanged() {
|
||||
showFab()
|
||||
}
|
||||
|
@ -335,9 +331,9 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
|
|||
|
||||
protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) {
|
||||
if (bitmap == null) {
|
||||
editorImage?.setImageResource(drawable.default_audio_art)
|
||||
editorImage.setImageResource(drawable.default_audio_art)
|
||||
} else {
|
||||
editorImage?.setImageBitmap(bitmap)
|
||||
editorImage.setImageBitmap(bitmap)
|
||||
}
|
||||
setColors(bgColor)
|
||||
}
|
||||
|
|
|
@ -29,9 +29,11 @@ import android.view.LayoutInflater
|
|||
import android.widget.ImageView
|
||||
import android.widget.Toast
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding
|
||||
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.glide.GlideApp
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||
|
@ -63,41 +65,6 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
|
|||
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 deleteAlbumArt: Boolean = false
|
||||
|
||||
|
@ -171,6 +138,41 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
|
|||
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() {
|
||||
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
|
||||
fieldKeyValueMap[FieldKey.ALBUM] = binding.albumText.text.toString()
|
||||
|
@ -213,6 +215,16 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
|
|||
override fun setColors(color: Int) {
|
||||
super.setColors(color)
|
||||
saveFab.backgroundTintList = ColorStateList.valueOf(color)
|
||||
saveFab.backgroundTintList = ColorStateList.valueOf(color)
|
||||
ColorStateList.valueOf(
|
||||
MaterialValueHelper.getPrimaryTextColor(
|
||||
this,
|
||||
color.isColorLight
|
||||
)
|
||||
).also {
|
||||
saveFab.iconTint = it
|
||||
saveFab.setTextColor(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,17 +15,36 @@
|
|||
package code.name.monkey.retromusic.activities.tageditor
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
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.extensions.appHandleColor
|
||||
import code.name.monkey.retromusic.extensions.isColorLight
|
||||
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.util.ImageUtil
|
||||
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 org.jaudiotagger.tag.FieldKey
|
||||
import org.koin.android.ext.android.inject
|
||||
|
@ -39,12 +58,14 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
|||
|
||||
private val songRepository by inject<SongRepository>()
|
||||
|
||||
private var albumArtBitmap: Bitmap? = null
|
||||
private var deleteAlbumArt: Boolean = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setUpViews()
|
||||
setNoImageMode()
|
||||
setSupportActionBar(binding.toolbar)
|
||||
binding.appBarLayout.statusBarForeground =
|
||||
binding.appBarLayout?.statusBarForeground =
|
||||
MaterialShapeDrawable.createWithElevationOverlay(this)
|
||||
}
|
||||
|
||||
|
@ -59,6 +80,7 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
|||
binding.yearContainer.setTint(false)
|
||||
binding.genreContainer.setTint(false)
|
||||
binding.trackNumberContainer.setTint(false)
|
||||
binding.discNumberContainer.setTint(false)
|
||||
binding.lyricsContainer.setTint(false)
|
||||
|
||||
binding.songText.appHandleColor().addTextChangedListener(this)
|
||||
|
@ -68,13 +90,9 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
|||
binding.genreText.appHandleColor().addTextChangedListener(this)
|
||||
binding.yearText.appHandleColor().addTextChangedListener(this)
|
||||
binding.trackNumberText.appHandleColor().addTextChangedListener(this)
|
||||
binding.discNumberText.appHandleColor().addTextChangedListener(this)
|
||||
binding.lyricsText.appHandleColor().addTextChangedListener(this)
|
||||
binding.songComposerText.appHandleColor().addTextChangedListener(this)
|
||||
|
||||
binding.lyricsText.setOnTouchListener { view, _ ->
|
||||
view.parent.requestDisallowInterceptTouchEvent(true)
|
||||
return@setOnTouchListener false
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillViewsWithFileTags() {
|
||||
|
@ -85,16 +103,50 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
|||
binding.genreText.setText(genreName)
|
||||
binding.yearText.setText(songYear)
|
||||
binding.trackNumberText.setText(trackNumber)
|
||||
binding.discNumberText.setText(discNumber)
|
||||
binding.lyricsText.setText(lyrics)
|
||||
binding.songComposerText.setText(composer)
|
||||
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() {
|
||||
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.YEAR] = binding.yearText.text.toString()
|
||||
fieldKeyValueMap[FieldKey.TRACK] = binding.trackNumberText.text.toString()
|
||||
fieldKeyValueMap[FieldKey.DISC_NO] = binding.discNumberText.text.toString()
|
||||
fieldKeyValueMap[FieldKey.LYRICS] = binding.lyricsText.text.toString()
|
||||
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = binding.albumArtistText.text.toString()
|
||||
fieldKeyValueMap[FieldKey.COMPOSER] = binding.songComposerText.text.toString()
|
||||
writeValuesToFiles(fieldKeyValueMap, 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)
|
||||
|
@ -115,6 +173,38 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
|||
override fun getSongUris(): List<Uri> = listOf(MusicUtil.getSongFileUri(id))
|
||||
|
||||
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) {
|
||||
|
@ -131,6 +221,6 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
|
|||
val TAG: String = SongTagEditorActivity::class.java.simpleName
|
||||
}
|
||||
|
||||
override val editorImage: ImageView?
|
||||
get() = null
|
||||
override val editorImage: ImageView
|
||||
get() = binding.editorImage
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ import org.jaudiotagger.audio.exceptions.CannotWriteException
|
|||
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException
|
||||
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException
|
||||
import org.jaudiotagger.tag.TagException
|
||||
import org.jaudiotagger.tag.images.AndroidArtwork
|
||||
import org.jaudiotagger.tag.images.Artwork
|
||||
import org.jaudiotagger.tag.images.ArtworkFactory
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
|
@ -58,11 +58,11 @@ class TagWriter {
|
|||
try {
|
||||
albumArtFile = createAlbumArtFile(context).canonicalFile
|
||||
info.artworkInfo.artwork.compress(
|
||||
Bitmap.CompressFormat.PNG,
|
||||
0,
|
||||
Bitmap.CompressFormat.JPEG,
|
||||
100,
|
||||
FileOutputStream(albumArtFile)
|
||||
)
|
||||
artwork = ArtworkFactory.createArtworkFromFile(albumArtFile)
|
||||
artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
@ -131,11 +131,11 @@ class TagWriter {
|
|||
try {
|
||||
albumArtFile = createAlbumArtFile(context).canonicalFile
|
||||
info.artworkInfo.artwork.compress(
|
||||
Bitmap.CompressFormat.PNG,
|
||||
0,
|
||||
Bitmap.CompressFormat.JPEG,
|
||||
100,
|
||||
FileOutputStream(albumArtFile)
|
||||
)
|
||||
artwork = ArtworkFactory.createArtworkFromFile(albumArtFile)
|
||||
artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
|
||||
} catch (e: IOException) {
|
||||
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.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.helper.menu.SongMenuHelper
|
||||
import code.name.monkey.retromusic.model.*
|
||||
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
|
||||
import code.name.monkey.retromusic.repository.PlaylistSongsLoader
|
||||
import code.name.monkey.retromusic.model.Album
|
||||
import code.name.monkey.retromusic.model.Artist
|
||||
import code.name.monkey.retromusic.model.Genre
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import java.util.*
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ import android.view.LayoutInflater
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import code.name.monkey.retromusic.R
|
||||
|
|
|
@ -30,7 +30,11 @@ class ImportPlaylistDialog : DialogFragment() {
|
|||
return materialDialog(R.string.import_playlist)
|
||||
.setMessage(R.string.import_playlist_message)
|
||||
.setPositiveButton(R.string.import_label) { _, _ ->
|
||||
libraryViewModel.importPlaylists()
|
||||
try {
|
||||
libraryViewModel.importPlaylists()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
.create()
|
||||
.colorButtons()
|
||||
|
|
|
@ -14,14 +14,16 @@
|
|||
*/
|
||||
package code.name.monkey.retromusic.extensions
|
||||
|
||||
import android.R
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.DimenRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
|
||||
fun AppCompatActivity.applyToolbar(toolbar: MaterialToolbar) {
|
||||
//toolbar.setBackgroundColor(surfaceColor())
|
||||
ToolbarContentTintHelper.colorBackButton(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 {
|
||||
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.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.core.view.isGone
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import code.name.monkey.appthemehelper.ATH
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
|
@ -46,7 +47,6 @@ fun AppCompatActivity.exitFullscreen() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fun AppCompatActivity.hideStatusBar() {
|
||||
hideStatusBar(PreferenceUtil.isFullScreenMode)
|
||||
}
|
||||
|
@ -54,16 +54,25 @@ fun AppCompatActivity.hideStatusBar() {
|
|||
private fun AppCompatActivity.hideStatusBar(fullscreen: Boolean) {
|
||||
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
|
||||
if (statusBar != null) {
|
||||
statusBar.visibility = if (fullscreen) View.GONE else View.VISIBLE
|
||||
statusBar.isGone = fullscreen
|
||||
}
|
||||
}
|
||||
|
||||
fun AppCompatActivity.setDrawBehindSystemBars() {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
window.statusBarColor = Color.TRANSPARENT
|
||||
window.navigationBarColor = Color.TRANSPARENT
|
||||
if (VersionUtils.hasQ()) {
|
||||
window.isNavigationBarContrastEnforced = false
|
||||
if (VersionUtils.hasOreo()) {
|
||||
if (VersionUtils.hasQ()) {
|
||||
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) {
|
||||
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
|
||||
setStatusBarColor(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 {
|
||||
try {
|
||||
return this.getInt(this.getColumnIndex(columnName))
|
||||
return getInt(getColumnIndexOrThrow(columnName))
|
||||
} catch (ex: Throwable) {
|
||||
throw IllegalStateException("invalid column $columnName", ex)
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ internal fun Cursor.getInt(columnName: String): Int {
|
|||
|
||||
internal fun Cursor.getLong(columnName: String): Long {
|
||||
try {
|
||||
return this.getLong(this.getColumnIndex(columnName))
|
||||
return getLong(getColumnIndexOrThrow(columnName))
|
||||
} catch (ex: Throwable) {
|
||||
throw IllegalStateException("invalid column $columnName", ex)
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ internal fun Cursor.getLong(columnName: String): Long {
|
|||
|
||||
internal fun Cursor.getString(columnName: String): String {
|
||||
try {
|
||||
return this.getString(this.getColumnIndex(columnName))
|
||||
return getString(getColumnIndexOrThrow(columnName))
|
||||
} catch (ex: Throwable) {
|
||||
throw IllegalStateException("invalid column $columnName", ex)
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ internal fun Cursor.getString(columnName: String): String {
|
|||
|
||||
internal fun Cursor.getStringOrNull(columnName: String): String? {
|
||||
try {
|
||||
return this.getString(this.getColumnIndex(columnName))
|
||||
return getString(getColumnIndexOrThrow(columnName))
|
||||
} catch (ex: Throwable) {
|
||||
throw IllegalStateException("invalid column $columnName", ex)
|
||||
}
|
||||
|
|
|
@ -66,7 +66,6 @@ val FragmentManager.currentNavigationFragment: Fragment?
|
|||
fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
|
||||
val navHostFragment: NavHostFragment =
|
||||
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
||||
navHostFragment.targetFragment
|
||||
return navHostFragment.childFragmentManager.fragments.firstOrNull()
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package code.name.monkey.retromusic.extensions
|
|||
|
||||
import android.net.Uri
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.fragment.app.Fragment
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
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.R
|
||||
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.fragments.GridStyle
|
||||
import code.name.monkey.retromusic.fragments.ReloadType
|
||||
|
|
|
@ -7,7 +7,7 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
|
@ -49,7 +49,9 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
|||
val openFilePicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
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) {
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.restore)
|
||||
.setMessage(R.string.restore_message)
|
||||
.setPositiveButton(R.string.restore) { _, _ ->
|
||||
lifecycleScope.launch {
|
||||
backupViewModel.restoreBackup(requireActivity(), file.inputStream())
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
.show()
|
||||
lifecycleScope.launch {
|
||||
startActivity(Intent(context, RestoreActivity::class.java).apply {
|
||||
data = file.toUri()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
|
|
|
@ -5,6 +5,8 @@ import android.content.Intent
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
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 kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -25,12 +27,12 @@ class BackupViewModel : ViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun restoreBackup(activity: Activity, inputStream: InputStream?) {
|
||||
BackupHelper.restoreBackup(activity, inputStream)
|
||||
suspend fun restoreBackup(activity: Activity, inputStream: InputStream?, contents: List<BackupContent>) {
|
||||
BackupHelper.restoreBackup(activity, inputStream, contents)
|
||||
withContext(Dispatchers.Main) {
|
||||
val intent = Intent(
|
||||
activity,
|
||||
activity::class.java
|
||||
MainActivity::class.java
|
||||
)
|
||||
activity.startActivity(intent)
|
||||
exitProcess(0)
|
||||
|
|
|
@ -1,12 +1,89 @@
|
|||
package code.name.monkey.retromusic.fragments.backup
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import androidx.activity.viewModels
|
||||
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() {
|
||||
|
||||
lateinit var binding: ActivityRestoreBinding
|
||||
private val backupViewModel: BackupViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
updateTheme()
|
||||
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.view.*
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.loader.app.LoaderManager
|
||||
import androidx.loader.content.Loader
|
||||
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.R
|
||||
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.base.AbsRecyclerViewFragment
|
||||
import code.name.monkey.retromusic.interfaces.IGenreClickListener
|
||||
import code.name.monkey.retromusic.model.Genre
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.view.View
|
|||
import androidx.activity.addCallback
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.core.view.doOnLayout
|
||||
import androidx.core.view.doOnPreDraw
|
||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||
import androidx.navigation.fragment.findNavController
|
||||
|
@ -87,6 +88,21 @@ class HomeFragment :
|
|||
remove()
|
||||
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() {
|
||||
|
|
|
@ -64,14 +64,6 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
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)
|
||||
binding.progressIndicator.hide()
|
||||
when (args.type) {
|
||||
|
@ -92,6 +84,10 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
binding.recyclerView.updatePadding(bottom = height.toInt())
|
||||
}
|
||||
})
|
||||
binding.appBarLayout.statusBarForeground =
|
||||
MaterialShapeDrawable.createWithElevationOverlay(requireContext())
|
||||
postponeEnterTransition()
|
||||
view.doOnPreDraw { startPostponedEnterTransition() }
|
||||
}
|
||||
|
||||
private fun lastAddedSongs() {
|
||||
|
@ -104,6 +100,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
binding.recyclerView.apply {
|
||||
adapter = songAdapter
|
||||
layoutManager = linearLayoutManager()
|
||||
scheduleLayoutAnimation()
|
||||
}
|
||||
libraryViewModel.recentSongs().observe(viewLifecycleOwner, { songs ->
|
||||
songAdapter.swapDataSet(songs)
|
||||
|
|
|
@ -134,12 +134,11 @@ class UserInfoFragment : Fragment() {
|
|||
private fun loadProfile() {
|
||||
binding.bannerImage.let {
|
||||
GlideApp.with(this)
|
||||
.asBitmap()
|
||||
.load(RetroGlideExtension.getBannerModel())
|
||||
.profileBannerOptions(RetroGlideExtension.getBannerModel())
|
||||
.into(it)
|
||||
}
|
||||
GlideApp.with(this).asBitmap()
|
||||
GlideApp.with(this)
|
||||
.load(RetroGlideExtension.getUserModel())
|
||||
.userProfileOptions(RetroGlideExtension.getUserModel())
|
||||
.into(binding.userImage)
|
||||
|
|
|
@ -14,42 +14,36 @@
|
|||
*/
|
||||
package code.name.monkey.retromusic.fragments.player
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.SHOW_LYRICS
|
||||
import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter
|
||||
import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter.AlbumCoverFragment
|
||||
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.base.AbsMusicServiceFragment
|
||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||
import code.name.monkey.retromusic.fragments.base.goToLyrics
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
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.transform.CarousalPagerTransformer
|
||||
import code.name.monkey.retromusic.transform.ParallaxPagerTransformer
|
||||
import code.name.monkey.retromusic.util.LyricUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
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),
|
||||
ViewPager.OnPageChangeListener, MusicProgressViewUpdateHelper.Callback,
|
||||
|
@ -70,9 +64,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
|||
}
|
||||
private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null
|
||||
|
||||
private val lyricsLayout: FrameLayout get() = binding.playerLyrics
|
||||
private val lyricsLine1: TextView get() = binding.playerLyricsLine1
|
||||
private val lyricsLine2: TextView get() = binding.playerLyricsLine2
|
||||
private val lrcView: CoverLrcView get() = binding.lyricsView
|
||||
|
||||
var lyrics: Lyrics? = null
|
||||
|
||||
|
@ -82,102 +74,28 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
|||
}
|
||||
|
||||
private fun updateLyrics() {
|
||||
lyrics = null
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val song = MusicPlayerRemote.currentSong
|
||||
val lyrics = try {
|
||||
var lrcFile: File? = null
|
||||
if (LyricUtil.isLrcOriginalFileExist(song.data)) {
|
||||
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
|
||||
binding.lyricsView.setLabel("Empty")
|
||||
val song = MusicPlayerRemote.currentSong
|
||||
when {
|
||||
LyricUtil.isLrcOriginalFileExist(song.data) -> {
|
||||
LyricUtil.getLocalLyricOriginalFile(song.data)
|
||||
?.let { binding.lyricsView.loadLrc(it) }
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
this@PlayerAlbumCoverFragment.lyrics = lyrics
|
||||
LyricUtil.isLrcFileExist(song.title, song.artistName) -> {
|
||||
LyricUtil.getLocalLyricFile(song.title, song.artistName)
|
||||
?.let { binding.lyricsView.loadLrc(it) }
|
||||
}
|
||||
else -> {
|
||||
binding.lyricsView.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUpdateProgressViews(progress: Int, total: Int) {
|
||||
if (_binding == null) return
|
||||
|
||||
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
|
||||
}
|
||||
binding.lyricsView.updateTime(progress.toLong())
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
_binding = FragmentPlayerAlbumCoverBinding.bind(view)
|
||||
|
@ -210,14 +128,25 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
|||
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
|
||||
// Don't show lyrics container for below conditions
|
||||
if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) {
|
||||
lyricsLayout.isVisible = false
|
||||
lrcView.isVisible = false
|
||||
viewPager.isInvisible = false
|
||||
progressViewUpdateHelper?.stop()
|
||||
} else {
|
||||
lyricsLayout.isVisible = true
|
||||
lrcView.isVisible = true
|
||||
viewPager.isInvisible = true
|
||||
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
|
||||
binding.playerLyricsLine2.setOnClickListener {
|
||||
lrcView.setOnClickListener {
|
||||
goToLyrics(requireActivity())
|
||||
}
|
||||
}
|
||||
|
@ -227,10 +156,12 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
|||
val nps = PreferenceUtil.nowPlayingScreen
|
||||
// Don't show lyrics container for below conditions
|
||||
if (nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics) {
|
||||
lyricsLayout.isVisible = false
|
||||
lrcView.isVisible = false
|
||||
viewPager.isInvisible = false
|
||||
progressViewUpdateHelper?.stop()
|
||||
} else {
|
||||
lyricsLayout.isVisible = true
|
||||
lrcView.isVisible = true
|
||||
viewPager.isInvisible = true
|
||||
progressViewUpdateHelper?.start()
|
||||
}
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
|
@ -266,30 +197,42 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
|||
val nps = PreferenceUtil.nowPlayingScreen
|
||||
// Don't show lyrics container for below conditions
|
||||
if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) {
|
||||
lyricsLayout.isVisible = false
|
||||
progressViewUpdateHelper?.stop()
|
||||
} else {
|
||||
lyricsLayout.isVisible = true
|
||||
lrcView.isVisible = true
|
||||
viewPager.isInvisible = true
|
||||
progressViewUpdateHelper?.start()
|
||||
lyricsLayout.animate().alpha(1f).duration =
|
||||
lrcView.animate().alpha(1f).duration =
|
||||
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
|
||||
binding.playerLyrics.isVisible = true
|
||||
} else {
|
||||
lrcView.isVisible = false
|
||||
viewPager.isInvisible = false
|
||||
progressViewUpdateHelper?.stop()
|
||||
}
|
||||
} else {
|
||||
lrcView.isVisible = false
|
||||
viewPager.isInvisible = false
|
||||
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() {
|
||||
binding.viewPager.apply {
|
||||
adapter = AlbumCoverPagerAdapter(childFragmentManager, MusicPlayerRemote.playingQueue)
|
||||
|
@ -321,6 +264,18 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
|||
|
||||
private fun notifyColorChange(color: MediaNotificationProcessor) {
|
||||
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) {
|
||||
|
|
|
@ -47,7 +47,7 @@ class AdaptiveFragment : AbsPlayerFragment(R.layout.fragment_adaptive_player) {
|
|||
_binding = FragmentAdaptivePlayerBinding.bind(view)
|
||||
setUpSubFragments()
|
||||
setUpPlayerToolbar()
|
||||
binding.root.drawAboveSystemBars()
|
||||
binding.playbackControlsFragment.drawAboveSystemBars()
|
||||
}
|
||||
|
||||
private fun setUpSubFragments() {
|
||||
|
|
|
@ -16,6 +16,8 @@ package code.name.monkey.retromusic.fragments.player.blur
|
|||
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
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.fragments.base.AbsPlayerFragment
|
||||
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
||||
import code.name.monkey.retromusic.glide.BlurTransformation
|
||||
import code.name.monkey.retromusic.glide.GlideApp
|
||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||
import code.name.monkey.retromusic.glide.*
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil.blurAmount
|
||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||
|
||||
|
||||
class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private var lastRequest: GlideRequest<Drawable>? = null
|
||||
|
||||
override fun playerToolbar(): Toolbar {
|
||||
return binding.playerToolbar
|
||||
}
|
||||
|
@ -111,23 +113,20 @@ class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
|
|||
get() = lastColor
|
||||
|
||||
private fun updateBlur() {
|
||||
binding.colorBackground.clearColorFilter()
|
||||
GlideApp.with(requireActivity()).asBitmapPalette()
|
||||
.songCoverOptions(MusicPlayerRemote.currentSong)
|
||||
// https://github.com/bumptech/glide/issues/527#issuecomment-148840717
|
||||
GlideApp.with(this)
|
||||
.load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong))
|
||||
.dontAnimate()
|
||||
.simpleSongCoverOptions(MusicPlayerRemote.currentSong)
|
||||
.transform(
|
||||
BlurTransformation.Builder(requireContext())
|
||||
.blurRadius(blurAmount.toFloat())
|
||||
BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat())
|
||||
.build()
|
||||
)
|
||||
.into(object : RetroMusicColoredTarget(binding.colorBackground) {
|
||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||
if (colors.backgroundColor == defaultFooterColor) {
|
||||
binding.colorBackground.setColorFilter(colors.backgroundColor)
|
||||
}
|
||||
}
|
||||
})
|
||||
).thumbnail(lastRequest)
|
||||
.error(GlideApp.with(this).load(ColorDrawable(Color.DKGRAY)).fitCenter())
|
||||
.also {
|
||||
lastRequest = it.clone()
|
||||
it.crossfadeListener()
|
||||
.into(binding.colorBackground)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {
|
||||
|
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.fragments.player.cardblur
|
|||
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
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.player.PlayerAlbumCoverFragment
|
||||
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
|
||||
import code.name.monkey.retromusic.glide.BlurTransformation
|
||||
import code.name.monkey.retromusic.glide.GlideApp
|
||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||
import code.name.monkey.retromusic.glide.*
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
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 val binding get() = _binding!!
|
||||
private var lastRequest: GlideRequest<Drawable>? = null
|
||||
|
||||
override fun onShow() {
|
||||
playbackControlsFragment.show()
|
||||
|
@ -136,22 +135,19 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
|
|||
}
|
||||
|
||||
private fun updateBlur() {
|
||||
binding.colorBackground.clearColorFilter()
|
||||
GlideApp.with(requireActivity()).asBitmapPalette()
|
||||
.songCoverOptions(MusicPlayerRemote.currentSong)
|
||||
// https://github.com/bumptech/glide/issues/527#issuecomment-148840717
|
||||
GlideApp.with(this)
|
||||
.load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong))
|
||||
.dontAnimate()
|
||||
.simpleSongCoverOptions(MusicPlayerRemote.currentSong)
|
||||
.transform(
|
||||
BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat())
|
||||
.build()
|
||||
)
|
||||
.into(object : RetroMusicColoredTarget(binding.colorBackground) {
|
||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||
if (colors.backgroundColor == defaultFooterColor) {
|
||||
binding.colorBackground.setColorFilter(colors.backgroundColor)
|
||||
}
|
||||
}
|
||||
})
|
||||
.thumbnail(lastRequest).also {
|
||||
lastRequest = it.clone()
|
||||
it.crossfadeListener()
|
||||
.into(binding.colorBackground)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
|
|
@ -18,19 +18,19 @@ import android.animation.ObjectAnimator
|
|||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.media.AudioManager
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.widget.SeekBar
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import code.name.monkey.appthemehelper.util.*
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.databinding.FragmentCirclePlayerBinding
|
||||
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.goToAlbum
|
||||
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.MusicProgressViewUpdateHelper
|
||||
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.ViewUtil
|
||||
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.OnAudioVolumeChangedListener
|
||||
import me.tankery.lib.circularseekbar.CircularSeekBar
|
||||
|
||||
/**
|
||||
* 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,
|
||||
OnAudioVolumeChangedListener,
|
||||
OnSeekArcChangeListener {
|
||||
CircularSeekBar.OnCircularSeekBarChangeListener {
|
||||
|
||||
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
|
||||
private var audioVolumeObserver: AudioVolumeObserver? = null
|
||||
|
@ -69,6 +69,9 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
|||
private var _binding: FragmentCirclePlayerBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var rotateAnimator: ObjectAnimator? = null
|
||||
private var lastRequest: GlideRequest<Drawable>? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
|
||||
|
@ -116,11 +119,17 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
|||
ThemeStore.accentColor(requireContext()),
|
||||
false
|
||||
)
|
||||
binding.volumeSeekBar.progressColor = accentColor()
|
||||
binding.volumeSeekBar.arcColor = ColorUtil.withAlpha(accentColor(), 0.25f)
|
||||
binding.volumeSeekBar.circleProgressColor = accentColor()
|
||||
binding.volumeSeekBar.circleColor = ColorUtil.withAlpha(accentColor(), 0.25f)
|
||||
setUpPlayPauseFab()
|
||||
setUpPrevNext()
|
||||
setUpPlayerToolbar()
|
||||
binding.albumCoverOverlay.background = ColorDrawable(
|
||||
MaterialValueHelper.getPrimaryTextColor(
|
||||
requireContext(),
|
||||
accentColor().isColorLight
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun setUpPrevNext() {
|
||||
|
@ -144,6 +153,17 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
|||
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() {
|
||||
super.onResume()
|
||||
progressViewUpdateHelper.start()
|
||||
|
@ -153,11 +173,11 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
|||
audioVolumeObserver?.register(AudioManager.STREAM_MUSIC, this)
|
||||
|
||||
val audioManager = audioManager
|
||||
if (audioManager != null) {
|
||||
binding.volumeSeekBar.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
|
||||
binding.volumeSeekBar.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||
}
|
||||
binding.volumeSeekBar.setOnSeekArcChangeListener(this)
|
||||
binding.volumeSeekBar.max =
|
||||
audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC).toFloat()
|
||||
binding.volumeSeekBar.progress =
|
||||
audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat()
|
||||
binding.volumeSeekBar.setOnSeekBarChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
@ -191,6 +211,11 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
|||
|
||||
override fun onPlayStateChanged() {
|
||||
updatePlayPauseDrawableState()
|
||||
if (MusicPlayerRemote.isPlaying) {
|
||||
if (rotateAnimator?.isStarted == true) rotateAnimator?.resume() else rotateAnimator?.start()
|
||||
} else {
|
||||
rotateAnimator?.pause()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlayingMetaChanged() {
|
||||
|
@ -202,6 +227,7 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
|||
super.onServiceConnected()
|
||||
updateSong()
|
||||
updatePlayPauseDrawableState()
|
||||
setupRotateAnimation()
|
||||
}
|
||||
|
||||
private fun updateSong() {
|
||||
|
@ -215,6 +241,16 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
|||
} else {
|
||||
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() {
|
||||
|
@ -225,8 +261,8 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
|||
}
|
||||
|
||||
override fun onAudioVolumeChanged(currentVolume: Int, maxVolume: Int) {
|
||||
_binding?.volumeSeekBar?.max = maxVolume
|
||||
_binding?.volumeSeekBar?.progress = currentVolume
|
||||
_binding?.volumeSeekBar?.max = maxVolume.toFloat()
|
||||
_binding?.volumeSeekBar?.progress = currentVolume.toFloat()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -237,15 +273,16 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
|||
_binding = null
|
||||
}
|
||||
|
||||
override fun onProgressChanged(seekArc: SeekArc?, progress: Int, fromUser: Boolean) {
|
||||
|
||||
override fun onProgressChanged(seekBar: CircularSeekBar?, progress: Float, fromUser: Boolean) {
|
||||
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() {
|
||||
|
|
|
@ -26,14 +26,13 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.view.animation.LinearInterpolator
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import android.widget.SeekBar
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.databinding.FragmentFullPlayerControlsBinding
|
||||
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.applyColor
|
||||
import code.name.monkey.retromusic.extensions.getSongInfo
|
||||
|
|
|
@ -23,9 +23,9 @@ import android.graphics.drawable.AnimatedVectorDrawable
|
|||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.animation.LinearInterpolator
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import android.widget.SeekBar
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
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.adapter.song.PlayingQueueAdapter
|
||||
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.fragments.base.AbsPlayerControlsFragment
|
||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||
|
|
|
@ -281,12 +281,13 @@ class TinyPlayerFragment : AbsPlayerFragment(R.layout.fragment_tiny_player),
|
|||
return gestureDetector.onTouchEvent(event)
|
||||
}
|
||||
|
||||
@Suppress("Deprecation")
|
||||
private fun vibrate() {
|
||||
val v = requireContext().getSystemService(Context.VIBRATOR_SERVICE) as Vibrator?
|
||||
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 {
|
||||
v!!.vibrate(10)
|
||||
v?.vibrate(10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,10 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
|
|||
setupRecyclerView()
|
||||
|
||||
binding.voiceSearch.setOnClickListener { startMicSearch() }
|
||||
binding.clearText.setOnClickListener { binding.searchView.clearText() }
|
||||
binding.clearText.setOnClickListener {
|
||||
binding.searchView.clearText()
|
||||
searchAdapter.swapDataSet(listOf())
|
||||
}
|
||||
binding.searchView.apply {
|
||||
addTextChangedListener(this@SearchFragment)
|
||||
focusAndShowKeyboard()
|
||||
|
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.fragments.settings
|
|||
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
|
@ -26,6 +27,7 @@ import androidx.preference.Preference
|
|||
import androidx.preference.PreferenceManager
|
||||
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat
|
||||
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.preferences.*
|
||||
import code.name.monkey.retromusic.util.NavigationUtil
|
||||
|
@ -67,11 +69,15 @@ abstract class AbsSettingsFragment : ATEPreferenceFragmentCompat() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
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
|
||||
// So we get insets from decor view
|
||||
// https://github.com/material-components/material-components-android/issues/1310
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
requireActivity().window.decorView
|
||||
requireActivity().rootView
|
||||
) { _, insets ->
|
||||
listView.updatePadding(bottom = insets.safeGetBottomInsets())
|
||||
insets
|
||||
|
|
|
@ -28,6 +28,7 @@ import code.name.monkey.retromusic.App
|
|||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.databinding.FragmentMainSettingsBinding
|
||||
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.show
|
||||
import code.name.monkey.retromusic.util.NavigationUtil
|
||||
|
@ -89,9 +90,9 @@ class MainSettingsFragment : Fragment(), View.OnClickListener {
|
|||
}
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
requireActivity().window.decorView
|
||||
requireActivity().rootView
|
||||
) { _, insets ->
|
||||
binding.container.updatePadding(bottom = insets.safeGetBottomInsets())
|
||||
_binding?.container?.updatePadding(bottom = insets.safeGetBottomInsets())
|
||||
insets
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,15 @@ import com.bumptech.glide.RequestBuilder
|
|||
import com.bumptech.glide.annotation.GlideExtension
|
||||
import com.bumptech.glide.annotation.GlideOption
|
||||
import com.bumptech.glide.annotation.GlideType
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.Key
|
||||
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.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 java.io.File
|
||||
|
||||
|
@ -116,6 +122,16 @@ object RetroGlideExtension {
|
|||
.signature(createSignature(song))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@GlideOption
|
||||
fun simpleSongCoverOptions(
|
||||
baseRequestOptions: BaseRequestOptions<*>,
|
||||
song: Song
|
||||
): BaseRequestOptions<*> {
|
||||
return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
|
||||
.signature(createSignature(song))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@GlideOption
|
||||
fun albumCoverOptions(
|
||||
|
@ -194,4 +210,33 @@ object RetroGlideExtension {
|
|||
fun <TranscodeType> getDefaultTransition(): GenericTransitionOptions<TranscodeType> {
|
||||
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;
|
||||
|
||||
import org.jaudiotagger.audio.exceptions.CannotReadException;
|
||||
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
|
||||
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
|
||||
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
|
||||
} catch (ReadOnlyFileException | InvalidAudioFrameException | TagException | IOException ignored) {
|
||||
} catch (ReadOnlyFileException | InvalidAudioFrameException | TagException | IOException | CannotReadException ignored) {
|
||||
}
|
||||
|
||||
// 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.os.Environment
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import code.name.monkey.retromusic.App
|
||||
import code.name.monkey.retromusic.BuildConfig
|
||||
import code.name.monkey.retromusic.helper.BackupContent.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.*
|
||||
|
@ -24,10 +28,11 @@ object BackupHelper {
|
|||
zipItems.addAll(getSettingsZipItems(context))
|
||||
getUserImageZipItems(context)?.let { zipItems.addAll(it) }
|
||||
zipItems.addAll(getCustomArtistZipItems(context))
|
||||
zipItems.addAll(getQueueZipItems(context))
|
||||
zipAll(zipItems, backupFile)
|
||||
}
|
||||
|
||||
private suspend fun zipAll(zipItems: List<ZipItem>, backupFile: File) {
|
||||
private suspend fun zipAll(zipItems: List<ZipItem>, backupFile: File) =
|
||||
withContext(Dispatchers.IO) {
|
||||
kotlin.runCatching {
|
||||
ZipOutputStream(BufferedOutputStream(FileOutputStream(backupFile))).use { out ->
|
||||
|
@ -42,27 +47,42 @@ object BackupHelper {
|
|||
}
|
||||
}
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(App.getContext(), "Couldn't create backup", Toast.LENGTH_SHORT)
|
||||
.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> {
|
||||
return context.databaseList().filter {
|
||||
it.endsWith(".db")
|
||||
it.endsWith(".db") && it != queueDatabase
|
||||
}.map {
|
||||
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> {
|
||||
val sharedPrefPath = context.filesDir.parentFile?.absolutePath + "/shared_prefs/"
|
||||
return listOf(
|
||||
|
@ -94,33 +114,47 @@ object BackupHelper {
|
|||
)
|
||||
}?.toList() ?: listOf()
|
||||
)
|
||||
zipItemList.add(
|
||||
ZipItem(
|
||||
sharedPrefPath + File.separator + "custom_artist_image.xml",
|
||||
"$CUSTOM_ARTISTS_PATH${File.separator}prefs${File.separator}custom_artist_image.xml"
|
||||
)
|
||||
)
|
||||
File(sharedPrefPath + File.separator + "custom_artist_image.xml").let {
|
||||
if (it.exists()) {
|
||||
zipItemList.add(
|
||||
ZipItem(
|
||||
it.absolutePath,
|
||||
"$CUSTOM_ARTISTS_PATH${File.separator}prefs${File.separator}custom_artist_image.xml"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return zipItemList
|
||||
}
|
||||
|
||||
suspend fun restoreBackup(context: Context, inputStream: InputStream?) {
|
||||
suspend fun restoreBackup(
|
||||
context: Context,
|
||||
inputStream: InputStream?,
|
||||
contents: List<BackupContent>
|
||||
) {
|
||||
withContext(Dispatchers.IO) {
|
||||
ZipInputStream(inputStream).use {
|
||||
var entry = it.nextEntry
|
||||
while (entry != null) {
|
||||
if (entry.isDatabaseEntry()) restoreDatabase(context, it, entry)
|
||||
if (entry.isPreferenceEntry()) restorePreferences(context, it, entry)
|
||||
if (entry.isImageEntry()) restoreImages(context, it, entry)
|
||||
if (entry.isCustomArtistImageEntry()) restoreCustomArtistImages(
|
||||
context,
|
||||
it,
|
||||
entry
|
||||
)
|
||||
if (entry.isCustomArtistPrefEntry()) restoreCustomArtistPrefs(
|
||||
context,
|
||||
it,
|
||||
entry
|
||||
)
|
||||
if (entry.isDatabaseEntry() && contents.contains(PLAYLISTS)) {
|
||||
restoreDatabase(context, it, entry)
|
||||
} else if (entry.isPreferenceEntry() && contents.contains(SETTINGS)) {
|
||||
restorePreferences(context, it, entry)
|
||||
} else if (entry.isImageEntry() && contents.contains(USER_IMAGES)) {
|
||||
restoreImages(context, it, entry)
|
||||
|
||||
} else if (entry.isCustomArtistImageEntry() && contents.contains(
|
||||
CUSTOM_ARTIST_IMAGES
|
||||
)
|
||||
) {
|
||||
restoreCustomArtistImages(context, it, entry)
|
||||
restoreCustomArtistPrefs(context, it, entry)
|
||||
} else if (entry.isQueueEntry() && contents.contains(QUEUE)) {
|
||||
restoreQueueDatabase(context, it, entry)
|
||||
}
|
||||
|
||||
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(
|
||||
context: Context,
|
||||
zipIn: ZipInputStream,
|
||||
|
@ -218,10 +267,12 @@ object BackupHelper {
|
|||
const val BACKUP_EXTENSION = "rmbak"
|
||||
const val APPEND_EXTENSION = ".$BACKUP_EXTENSION"
|
||||
private const val DATABASES_PATH = "databases"
|
||||
private const val QUEUE_PATH = "queue"
|
||||
private const val SETTINGS_PATH = "prefs"
|
||||
private const val IMAGES_PATH = "userImages"
|
||||
private const val CUSTOM_ARTISTS_PATH = "artistImages"
|
||||
private const val THEME_PREFS_KEY_DEFAULT = "[[kabouzeid_app-theme-helper]]"
|
||||
private const val queueDatabase = "music_playback_state.db"
|
||||
|
||||
private fun ZipEntry.isDatabaseEntry(): Boolean {
|
||||
return name.startsWith(DATABASES_PATH)
|
||||
|
@ -243,6 +294,10 @@ object BackupHelper {
|
|||
return name.startsWith(CUSTOM_ARTISTS_PATH) && name.contains("prefs")
|
||||
}
|
||||
|
||||
private fun ZipEntry.isQueueEntry(): Boolean {
|
||||
return name.startsWith(QUEUE_PATH)
|
||||
}
|
||||
|
||||
private fun ZipEntry.getFileName(): String {
|
||||
return name.substring(name.lastIndexOf(File.separator))
|
||||
}
|
||||
|
@ -261,4 +316,12 @@ fun CharSequence.sanitize(): String {
|
|||
.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 songs = playlist.getSongs()
|
||||
if (songs.isNotEmpty()) {
|
||||
val bw = BufferedWriter(FileWriter(file))
|
||||
bw.write(M3UConstants.HEADER)
|
||||
for (song in songs) {
|
||||
bw.newLine()
|
||||
bw.write(M3UConstants.ENTRY + song.duration + M3UConstants.DURATION_SEPARATOR + song.artistName + " - " + song.title)
|
||||
bw.newLine()
|
||||
bw.write(song.data)
|
||||
BufferedWriter(FileWriter(file)).use { bw ->
|
||||
bw.write(M3UConstants.HEADER)
|
||||
for (song in songs) {
|
||||
bw.newLine()
|
||||
bw.write(M3UConstants.ENTRY + song.duration + M3UConstants.DURATION_SEPARATOR + song.artistName + " - " + song.title)
|
||||
bw.newLine()
|
||||
bw.write(song.data)
|
||||
}
|
||||
}
|
||||
bw.close()
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
@ -54,15 +54,15 @@ object M3UWriter : M3UConstants {
|
|||
it.songPrimaryKey
|
||||
}.toSongs()
|
||||
if (songs.isNotEmpty()) {
|
||||
val bufferedWriter = BufferedWriter(FileWriter(file))
|
||||
bufferedWriter.write(M3UConstants.HEADER)
|
||||
songs.forEach {
|
||||
bufferedWriter.newLine()
|
||||
bufferedWriter.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title)
|
||||
bufferedWriter.newLine()
|
||||
bufferedWriter.write(it.data)
|
||||
BufferedWriter(FileWriter(file)).use { bw->
|
||||
bw.write(M3UConstants.HEADER)
|
||||
songs.forEach {
|
||||
bw.newLine()
|
||||
bw.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title)
|
||||
bw.newLine()
|
||||
bw.write(it.data)
|
||||
}
|
||||
}
|
||||
bufferedWriter.close()
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
@ -72,15 +72,15 @@ object M3UWriter : M3UConstants {
|
|||
it.songPrimaryKey
|
||||
}.toSongs()
|
||||
if (songs.isNotEmpty()) {
|
||||
val bufferedWriter = outputStream.bufferedWriter()
|
||||
bufferedWriter.write(M3UConstants.HEADER)
|
||||
songs.forEach {
|
||||
bufferedWriter.newLine()
|
||||
bufferedWriter.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title)
|
||||
bufferedWriter.newLine()
|
||||
bufferedWriter.write(it.data)
|
||||
outputStream.bufferedWriter().use{ bw->
|
||||
bw.write(M3UConstants.HEADER)
|
||||
songs.forEach {
|
||||
bw.newLine()
|
||||
bw.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title)
|
||||
bw.newLine()
|
||||
bw.write(it.data)
|
||||
}
|
||||
}
|
||||
bufferedWriter.close()
|
||||
}
|
||||
outputStream.flush()
|
||||
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.retromusic.R
|
||||
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.RetroGlideExtension
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||
|
|
|
@ -15,12 +15,7 @@
|
|||
package code.name.monkey.retromusic.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
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
|
||||
|
||||
object AppRater {
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
package code.name.monkey.retromusic.util
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
@ -32,14 +31,6 @@ class RingtoneManager(val context: Context) {
|
|||
fun setRingtone(song: Song) {
|
||||
val resolver = context.contentResolver
|
||||
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 {
|
||||
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.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
|
||||
object ViewUtil {
|
||||
|
||||
|
|
|
@ -29,9 +29,14 @@ object ThemeManager {
|
|||
context: Context
|
||||
): Int = when (context.generalThemeValue) {
|
||||
LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
|
||||
DARK,
|
||||
BLACK -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
AUTO -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
DARK -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
BLACK -> {
|
||||
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.res.ColorStateList
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.util.AttributeSet
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.NavigationViewUtil
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
|
||||
|
@ -49,7 +47,6 @@ class BottomNavigationBarTinted @JvmOverloads constructor(
|
|||
accentColor
|
||||
)
|
||||
itemRippleColor = ColorStateList.valueOf(accentColor.addAlpha(0.08F))
|
||||
background = ColorDrawable(ATHUtil.resolveColor(context, R.attr.bottomSheetTint))
|
||||
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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface">
|
||||
android:background="?attr/colorSurface"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -16,20 +17,22 @@
|
|||
app:navigationIcon="@drawable/ic_keyboard_backspace_black"
|
||||
app:title="@string/action_tag_editor" />
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/imageContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_weight="1"
|
||||
android:transitionName="@string/transition_album_art"
|
||||
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
|
||||
android:id="@+id/editorImage"
|
||||
|
@ -50,10 +53,14 @@
|
|||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
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"
|
||||
|
@ -137,7 +144,7 @@
|
|||
android:layout_height="52dp" />
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<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:fillViewport="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
android:layout_weight="1"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:focusableInTouchMode="true"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
android:layout_marginEnd="@dimen/toolbar_margin_horizontal"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:focusableInTouchMode="true"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
android:transitionGroup="true"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
|
|
|
@ -54,29 +54,46 @@
|
|||
app:navigationIcon="@drawable/ic_keyboard_arrow_down_black"
|
||||
tools:layout_editor_absoluteY="24dp" />
|
||||
|
||||
|
||||
<code.name.monkey.retromusic.views.SeekArc
|
||||
android:id="@+id/volumeSeekBar"
|
||||
<FrameLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:padding="24dp"
|
||||
app:arcColor="?android:attr/colorControlHighlight"
|
||||
app:arcWidth="4dp"
|
||||
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: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_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="@id/guideline"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
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" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:focusableInTouchMode="true"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
android:transitionGroup="true"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
android:paddingBottom="96dp"
|
||||
android:scrollbars="none"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/my_top_tracks"
|
||||
app:icon="@drawable/ic_trending_up"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/actionShuffle"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="@+id/history"
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
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
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<LinearLayout
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<LinearLayout
|
||||
|
|
|
@ -6,23 +6,17 @@
|
|||
android:layout_height="match_parent"
|
||||
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
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface">
|
||||
android:background="?attr/colorSurface"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?colorPrimary"
|
||||
android:fitsSystemWindows="true"
|
||||
app:liftOnScroll="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
|
@ -37,15 +31,18 @@
|
|||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="fill_vertical"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<code.name.monkey.retromusic.views.LollipopFixedWebView
|
||||
android:id="@+id/license"
|
||||
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.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,8 +1,84 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".fragments.backup.RestoreActivity">
|
||||
android:layout_height="wrap_content"
|
||||
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"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
|
@ -24,6 +25,7 @@
|
|||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<LinearLayout
|
||||
|
@ -32,6 +34,28 @@
|
|||
android:orientation="vertical"
|
||||
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
|
||||
android:id="@+id/songTextContainer"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
|
@ -142,7 +166,6 @@
|
|||
android:layout_weight="1"
|
||||
app:hintEnabled="true">
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/genreText"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -165,7 +188,6 @@
|
|||
android:layout_weight="1"
|
||||
app:hintEnabled="true">
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/yearText"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -179,26 +201,56 @@
|
|||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/trackNumberContainer"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:hintEnabled="true">
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal">
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/trackNumberText"
|
||||
<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_gravity="center"
|
||||
android:gravity="center_vertical"
|
||||
android:hint="@string/track_hint"
|
||||
android:inputType="text|number"
|
||||
android:maxLines="1" />
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_weight="1"
|
||||
app:hintEnabled="true">
|
||||
|
||||
</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
|
||||
android:id="@+id/lyricsContainer"
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<include
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/songTitle"
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:focusableInTouchMode="true"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:barrierDirection="bottom"
|
||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:focusableInTouchMode="true"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:focusableInTouchMode="true"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<code.name.monkey.retromusic.views.insets.InsetsConstraintLayout
|
||||
|
|
|
@ -17,15 +17,11 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?colorSurface"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/statusBarContainer"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -85,23 +81,45 @@
|
|||
app:layout_constraintTop_toBottomOf="@+id/titleContainer"
|
||||
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:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="300dp"
|
||||
android:padding="28dp"
|
||||
app:arcColor="?android:attr/colorControlHighlight"
|
||||
app:arcWidth="4dp"
|
||||
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_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="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" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
|
@ -139,14 +157,15 @@
|
|||
app:tint="@color/md_green_500" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/materialTextView3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/volume"
|
||||
android:textAppearance="@style/TextViewSubtitle2"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/volumeSeekBar"
|
||||
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
|
||||
|
|
|
@ -140,7 +140,8 @@
|
|||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:listitem="@layout/item_list" />
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
tools:listitem="@layout/item_list" />
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
|
|
@ -153,7 +153,6 @@
|
|||
android:layout_height="52dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:background="?colorAccent"
|
||||
android:foreground="?attr/rectSelector"
|
||||
android:padding="12dp"
|
||||
android:scaleType="fitCenter"
|
||||
tools:ignore="MissingPrefix"
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
android:scrollbars="none"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -150,6 +150,7 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/colorSurface"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:focusableInTouchMode="true"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<code.name.monkey.retromusic.views.insets.InsetsConstraintLayout
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/songCurrentProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:gravity="center"
|
||||
|
@ -41,7 +41,7 @@
|
|||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/songTotalTime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:gravity="center"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
android:scrollbars="none"
|
||||
android:transitionGroup="true"
|
||||
app:layout_dodgeInsetEdges="bottom"
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
android:scrollbars="none"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
tools:listitem="@layout/item_list"
|
||||
android:transitionGroup="true"/>
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
android:transitionGroup="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/empty"
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/scrollView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:overScrollMode="@integer/overScrollMode">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
@ -7,49 +8,24 @@
|
|||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"
|
||||
android:overScrollMode="@integer/overScrollMode">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/playerLyrics"
|
||||
</androidx.viewpager.widget.ViewPager>
|
||||
|
||||
<code.name.monkey.retromusic.lyrics.CoverLrcView
|
||||
android:id="@+id/lyricsView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:alpha="0"
|
||||
android:clipToPadding="false"
|
||||
android:elevation="20dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="16dp"
|
||||
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>
|
|
@ -31,6 +31,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
android:paddingBottom="96dp"
|
||||
android:scrollbars="none"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
|
|
|
@ -35,7 +35,9 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
android:scrollbars="none"
|
||||
android:layoutAnimation="@anim/layout_anim_fade"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||
|
||||
<LinearLayout
|
||||
|
|
|
@ -73,7 +73,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dp"
|
||||
android:scrollbarSize="0dp">
|
||||
android:scrollbars="none"
|
||||
android:overScrollMode="@integer/overScrollMode">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/searchFilterGroup"
|
||||
|
@ -126,6 +127,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:scrollbars="vertical"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||
|
|
|
@ -66,7 +66,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nestedScrollingEnabled="false"
|
||||
tools:itemCount="10"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
tools:itemCount="10"
|
||||
tools:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
tools:listitem="@layout/item_album_card"
|
||||
tools:spanCount="3" />
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:elevation="@dimen/mcab_toolbar_elevation"
|
||||
android:theme="@style/ThemeOverlay.Material3.ActionBar"
|
||||
android:theme="@style/mcab_theme"
|
||||
tools:ignore="UnusedAttribute" />
|
|
@ -41,6 +41,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/clickable_area"
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
<item name="android:windowLightNavigationBar">false</item>
|
||||
<item name="colorSurface">@color/darkColorSurface</item>
|
||||
<item name="materialCardViewStyle">@style/Widget.MaterialComponents.CardView</item>
|
||||
<item name="bottomSheetTint">@color/bottomSheetColor</item>
|
||||
<item name="elevationOverlayColor">@color/elevationOverlayDark</item>
|
||||
<item name="floatingActionButtonStyle">
|
||||
@style/Widget.MaterialComponents.FloatingActionButton
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
<item name="bottomNavigationStyle">@style/Widget.Material3.BottomNavigationView</item>
|
||||
<item name="materialButtonStyle">@style/MaterialButtonTheme</item>
|
||||
<item name="materialCardViewStyle">@style/Widget.Material3.CardView.Elevated</item>
|
||||
<item name="bottomSheetTint">@color/bottomSheetColor</item>
|
||||
<item name="elevationOverlayColor">@color/elevationOverlay</item>
|
||||
<item name="floatingActionButtonStyle">
|
||||
@style/Widget.MaterialComponents.FloatingActionButton
|
||||
|
@ -54,7 +53,6 @@
|
|||
<item name="bottomNavigationStyle">@style/Widget.Material3.BottomNavigationView</item>
|
||||
<item name="android:windowBackground">@color/window_color_dark</item>
|
||||
<item name="materialCardViewStyle">@style/Widget.Material3.CardView.Elevated</item>
|
||||
<item name="bottomSheetTint">@color/bottomSheetColor</item>
|
||||
<item name="elevationOverlayColor">@color/elevationOverlay</item>
|
||||
<item name="floatingActionButtonStyle">
|
||||
@style/Widget.MaterialComponents.FloatingActionButton
|
||||
|
@ -78,7 +76,6 @@
|
|||
<item name="materialButtonStyle">@style/MaterialButtonTheme</item>
|
||||
<item name="bottomNavigationStyle">@style/Widget.Material3.BottomNavigationView</item>
|
||||
<item name="materialCardViewStyle">@style/Widget.Material3.CardView.Elevated</item>
|
||||
<item name="bottomSheetTint">@color/bottomSheetColorLight</item>
|
||||
<item name="elevationOverlayColor">@color/elevationOverlayLight</item>
|
||||
<item name="floatingActionButtonStyle">
|
||||
@style/Widget.MaterialComponents.FloatingActionButton
|
||||
|
|
|
@ -4,4 +4,5 @@
|
|||
<bool name="md3_enabled">true</bool>
|
||||
|
||||
<bool name="colored_notification_available">false</bool>
|
||||
<integer name="overScrollMode">0</integer>
|
||||
</resources>
|
|
@ -6,7 +6,6 @@
|
|||
<attr name="defaultFooterColor" format="color" />
|
||||
<attr name="toolbarPopupTheme" format="reference" />
|
||||
<attr name="lineHeightHint" format="dimension" />
|
||||
<attr name="bottomSheetTint" format="reference" />
|
||||
|
||||
<declare-styleable name="NetworkImageView">
|
||||
<attr name="url_link" format="string" />
|
||||
|
|
|
@ -28,4 +28,6 @@
|
|||
<bool name="md3_enabled">false</bool>
|
||||
|
||||
<bool name="colored_notification_available">true</bool>
|
||||
<integer name="overScrollMode">2</integer>
|
||||
<bool name="allowBackup">true</bool>
|
||||
</resources>
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<integer name="lrc_animation_duration">1000</integer>
|
||||
<dimen name="lrc_text_size">16sp</dimen>
|
||||
<dimen name="lrc_time_text_size">12sp</dimen>
|
||||
<dimen name="lrc_text_size">20sp</dimen>
|
||||
<dimen name="lrc_time_text_size">16sp</dimen>
|
||||
<dimen name="lrc_divider_height">16dp</dimen>
|
||||
<dimen name="lrc_timeline_height">1dp</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_card_name">Card</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_text_name">Minimal Text</string>
|
||||
<string name="artist">Artist</string>
|
||||
|
@ -81,6 +82,7 @@
|
|||
<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="auto">Auto</string>
|
||||
<string name="backup_restore_settings_summary">Backup and restore your settings, playlists</string>
|
||||
<string name="backup_restore_title">
|
||||
<![CDATA[Backup & Restore]]>
|
||||
</string>
|
||||
|
@ -113,6 +115,7 @@
|
|||
<string name="cascading">Cascading</string>
|
||||
<string name="changelog">Changelog</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="circular">Circular</string>
|
||||
<string name="classic">Classic</string>
|
||||
|
@ -132,7 +135,9 @@
|
|||
<string name="created_playlist_x">Created playlist %1$s.</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="custom_artist_images">Custom Artist Images</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_x">
|
||||
<![CDATA[Delete the playlist <b>%1$s</b>?]]>
|
||||
|
@ -156,6 +161,7 @@
|
|||
<string name="device_info">Device info</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="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_remove_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_artist_image">Reset artist image</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_purchases">Restored previous purchases.</string>
|
||||
<string name="restoring_purchase">Restoring purchase…</string>
|
||||
|
@ -453,8 +460,8 @@
|
|||
<string name="sort_order">Sort order</string>
|
||||
<string name="sort_order_a_z">Ascending</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_artist">Artist</string>
|
||||
<string name="sort_order_composer">Composer</string>
|
||||
<string name="sort_order_date">Date added</string>
|
||||
<string name="sort_order_date_modified">Date modified</string>
|
||||
|
@ -480,6 +487,7 @@
|
|||
<string name="tiny">Tiny</string>
|
||||
<string name="tiny_card_style">Tiny card</string>
|
||||
<string name="title">Title</string>
|
||||
<string name="title_new_backup">New Backup</string>
|
||||
<string name="today">Today</string>
|
||||
<string name="top_albums">Top albums</string>
|
||||
<string name="top_artists">Top artists</string>
|
||||
|
@ -495,6 +503,7 @@
|
|||
<string name="up_next">Up next</string>
|
||||
<string name="update_image">Update image</string>
|
||||
<string name="updating">Updating…</string>
|
||||
<string name="user_images_description">User Images</string>
|
||||
<string name="user_name">User Name</string>
|
||||
<string name="username">Username</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_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="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>
|
||||
|
|
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