Merge pull request #1320 from prathameshmm02/dev

Bug fixes
This commit is contained in:
Daksh P. Jain 2022-04-07 20:07:01 +05:30 committed by GitHub
commit 4d873e59f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
60 changed files with 735 additions and 1064 deletions

View file

@ -14,7 +14,7 @@ android {
vectorDrawables.useSupportLibrary = true
applicationId "code.name.monkey.retromusic"
versionCode 10570
versionCode 10573
versionName '5.8.0'
buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"")
@ -172,4 +172,5 @@ dependencies {
implementation 'cat.ereza:customactivityoncrash:2.3.0'
implementation 'me.tankery.lib:circularSeekBar:1.3.2'
debugImplementation 'com.github.amitshekhariitbhu:Android-Debug-Database:1.0.6'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
}

View file

@ -38,8 +38,8 @@
<activity
android:name=".activities.MainActivity"
android:exported="true"
android:theme="@style/SplashTheme"
android:launchMode="singleTop">
android:launchMode="singleTop"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.MUSIC_PLAYER" />
@ -212,7 +212,7 @@
</provider>
<receiver
android:name=".service.MediaButtonIntentReceiver"
android:name="androidx.media.session.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
@ -323,6 +323,9 @@
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</service>
<meta-data

View file

@ -63,16 +63,21 @@
<body>
<div>
<h5>March 13, 2022</h5>
<h5>April 8, 2022</h5>
<h2>v5.8.0</h2>
<h3>What's New</h3>
<ul>
<li>Updated translations</li>
<li>Minor UI improvements</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fixed Classic Notification crash</li>
<li>Fixed crash when clicking on Playlist in the Search Tab</li>
<li>Fixed settings change not reflecting immediately</li>
<li>Fixed shuffle</li>
<li>Fixed Song duration not visible in Card & Blur card themes</li>
<li>Fixed some Album skip styles</li>
<li>Minor bug fixes & UI improvements</li>
</ul>
</div>
<div>

View file

@ -53,7 +53,7 @@ class ErrorActivity : AppCompatActivity() {
)
.setNeutralButton(
R.string.customactivityoncrash_error_activity_error_details_share
) { dialog, which ->
) { _, _ ->
val bugReport = createFile(
context = this,

View file

@ -131,7 +131,6 @@ class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
val expand = intent?.extra<Boolean>(EXPAND_PANEL)?.value ?: false
if (expand && PreferenceUtil.isExpandPanel) {
fromNotification = true
@ -141,6 +140,11 @@ class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
}
}
override fun onResume() {
super.onResume()
PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
}
override fun onDestroy() {
super.onDestroy()
PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)

View file

@ -9,6 +9,7 @@ import code.name.monkey.retromusic.cast.RetroWebServer
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManager
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
@ -16,7 +17,7 @@ import com.google.android.gms.common.GoogleApiAvailability
abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
private var mCastSession: CastSession? = null
private lateinit var castContext: CastContext
private lateinit var sessionManager: SessionManager
private var webServer: RetroWebServer? = null
private var playServicesAvailable: Boolean = false
@ -87,17 +88,17 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
}
private fun setupCast() {
castContext = CastContext.getSharedInstance(this)
sessionManager = CastContext.getSharedInstance(applicationContext).sessionManager
}
override fun onResume() {
if (playServicesAvailable) {
castContext.sessionManager.addSessionManagerListener(
sessionManager.addSessionManagerListener(
sessionManagerListener,
CastSession::class.java
)
if (mCastSession == null) {
mCastSession = castContext.sessionManager.currentCastSession
mCastSession = sessionManager.currentCastSession
}
}
super.onResume()

View file

@ -64,7 +64,6 @@ import code.name.monkey.retromusic.model.CategoryInfo
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
import dev.chrisbanes.insetter.applyInsetter
import org.koin.androidx.viewmodel.ext.android.viewModel

View file

@ -14,11 +14,8 @@
*/
package code.name.monkey.retromusic.activities.bugreport
import android.app.Activity
import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
@ -28,8 +25,8 @@ import android.view.inputmethod.EditorInfo
import android.widget.Toast
import androidx.annotation.StringDef
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.core.content.getSystemService
import androidx.lifecycle.lifecycleScope
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.appthemehelper.util.TintHelper
@ -43,10 +40,12 @@ import code.name.monkey.retromusic.activities.bugreport.model.github.GithubLogin
import code.name.monkey.retromusic.activities.bugreport.model.github.GithubTarget
import code.name.monkey.retromusic.databinding.ActivityBugReportBinding
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.misc.DialogAsyncTask
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.eclipse.egit.github.core.Issue
import org.eclipse.egit.github.core.client.GitHubClient
import org.eclipse.egit.github.core.client.RequestException
@ -226,9 +225,9 @@ open class BugReportActivity : AbsThemeActivity() {
onSaveExtraInfo()
val report = Report(bugTitle, bugDescription, deviceInfo, extraInfo)
val target = GithubTarget("RetroMusicPlayer", "RetroMusicPlayer")
val target = GithubTarget("prathameshmm02", "RetroMusicPlayer")
ReportIssueAsyncTask.report(this, report, target, login)
reportIssue(report, target, login)
}
private fun onSaveExtraInfo() {}
@ -240,92 +239,75 @@ open class BugReportActivity : AbsThemeActivity() {
return super.onOptionsItemSelected(item)
}
private class ReportIssueAsyncTask private constructor(
activity: Activity,
private val report: Report,
private val target: GithubTarget,
private val login: GithubLogin
) : DialogAsyncTask<Void, Void, String>(activity) {
override fun createDialog(context: Context): Dialog {
return AlertDialog.Builder(context).show()
}
@Result
override fun doInBackground(vararg params: Void): String {
private fun reportIssue(
report: Report,
target: GithubTarget,
login: GithubLogin
) {
val client: GitHubClient = if (login.shouldUseApiToken()) {
GitHubClient().setOAuth2Token(login.apiToken)
} else {
GitHubClient().setCredentials(login.username, login.password)
}
val issue = Issue().setTitle(report.title).setBody(report.description)
try {
val issue = Issue().setTitle(report.title).setBody(report.getDescription())
lifecycleScope.launch(Dispatchers.IO) {
val result = try {
IssueService(client).createIssue(target.username, target.repository, issue)
return RESULT_SUCCESS
RESULT_SUCCESS
} catch (e: RequestException) {
return when (e.status) {
when (e.status) {
STATUS_BAD_CREDENTIALS -> {
if (login.shouldUseApiToken()) RESULT_INVALID_TOKEN else RESULT_BAD_CREDENTIALS
}
STATUS_ISSUES_NOT_ENABLED -> RESULT_ISSUES_NOT_ENABLED
else -> {
e.printStackTrace()
RESULT_UNKNOWN
throw e
}
}
} catch (e: IOException) {
e.printStackTrace()
return RESULT_UNKNOWN
}
RESULT_UNKNOWN
}
override fun onPostExecute(@Result result: String) {
super.onPostExecute(result)
val context = context ?: return
withContext(Dispatchers.Main) {
val activity = this@BugReportActivity
when (result) {
RESULT_SUCCESS -> tryToFinishActivity()
RESULT_BAD_CREDENTIALS -> MaterialAlertDialogBuilder(context)
RESULT_SUCCESS -> MaterialAlertDialogBuilder(activity)
.setTitle(R.string.bug_report_success)
.setPositiveButton(android.R.string.ok) { _, _ -> tryToFinishActivity() }
.show()
RESULT_BAD_CREDENTIALS -> MaterialAlertDialogBuilder(activity)
.setTitle(R.string.bug_report_failed)
.setMessage(R.string.bug_report_failed_wrong_credentials)
.setPositiveButton(android.R.string.ok, null)
.show()
RESULT_INVALID_TOKEN -> MaterialAlertDialogBuilder(context)
RESULT_INVALID_TOKEN -> MaterialAlertDialogBuilder(activity)
.setTitle(R.string.bug_report_failed)
.setMessage(R.string.bug_report_failed_invalid_token)
.setPositiveButton(android.R.string.ok, null).show()
RESULT_ISSUES_NOT_ENABLED -> MaterialAlertDialogBuilder(context)
.setPositiveButton(android.R.string.ok, null)
.show()
RESULT_ISSUES_NOT_ENABLED -> MaterialAlertDialogBuilder(activity)
.setTitle(R.string.bug_report_failed)
.setMessage(R.string.bug_report_failed_issues_not_available)
.setPositiveButton(android.R.string.ok, null)
else -> MaterialAlertDialogBuilder(context)
.show()
else -> MaterialAlertDialogBuilder(activity)
.setTitle(R.string.bug_report_failed)
.setMessage(R.string.bug_report_failed_unknown)
.setPositiveButton(android.R.string.ok) { _, _ -> tryToFinishActivity() }
.setNegativeButton(android.R.string.cancel) { _, _ -> tryToFinishActivity() }
.show()
}
}
}
}
private fun tryToFinishActivity() {
val context = context
if (context is Activity && !context.isFinishing) {
context.finish()
}
}
companion object {
fun report(
activity: Activity,
report: Report,
target: GithubTarget,
login: GithubLogin
) {
ReportIssueAsyncTask(activity, report, target, login).execute()
}
if (!isFinishing) {
finish()
}
}
@ -333,6 +315,6 @@ open class BugReportActivity : AbsThemeActivity() {
private const val STATUS_BAD_CREDENTIALS = 401
private const val STATUS_ISSUES_NOT_ENABLED = 410
private const val ISSUE_TRACKER_LINK = "https://github.com/RetroMusicPlayer/RetroMusicPlayer"
private const val ISSUE_TRACKER_LINK = "https://github.com/prathameshmm02/RetroMusicPlayer"
}
}

View file

@ -1,202 +0,0 @@
package code.name.monkey.retromusic.activities.bugreport.model;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.Locale;
import code.name.monkey.retromusic.util.PreferenceUtil;
public class DeviceInfo {
@SuppressLint("NewApi")
private final String[] abis =
Build.SUPPORTED_ABIS;
@SuppressLint("NewApi")
private final String[] abis32Bits =
Build.SUPPORTED_32_BIT_ABIS;
@SuppressLint("NewApi")
private final String[] abis64Bits =
Build.SUPPORTED_64_BIT_ABIS;
private final String baseTheme;
private final String brand = Build.BRAND;
private final String buildID = Build.DISPLAY;
private final String buildVersion = Build.VERSION.INCREMENTAL;
private final String device = Build.DEVICE;
private final String hardware = Build.HARDWARE;
private final boolean isAdaptive;
private final String manufacturer = Build.MANUFACTURER;
private final String model = Build.MODEL;
private final String nowPlayingTheme;
private final String product = Build.PRODUCT;
private final String releaseVersion = Build.VERSION.RELEASE;
@IntRange(from = 0)
private final int sdkVersion = Build.VERSION.SDK_INT;
private final int versionCode;
private final String versionName;
private final String selectedLang;
public DeviceInfo(Context context) {
PackageInfo packageInfo;
try {
packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
packageInfo = null;
}
if (packageInfo != null) {
versionCode = packageInfo.versionCode;
versionName = packageInfo.versionName;
} else {
versionCode = -1;
versionName = null;
}
baseTheme = PreferenceUtil.INSTANCE.getBaseTheme();
nowPlayingTheme =
context.getString(PreferenceUtil.INSTANCE.getNowPlayingScreen().getTitleRes());
isAdaptive = PreferenceUtil.INSTANCE.isAdaptiveColor();
selectedLang = PreferenceUtil.INSTANCE.getLanguageCode();
}
public String toMarkdown() {
return "Device info:\n"
+ "---\n"
+ "<table>\n"
+ "<tr><td><b>App version</b></td><td>"
+ versionName
+ "</td></tr>\n"
+ "<tr><td>App version code</td><td>"
+ versionCode
+ "</td></tr>\n"
+ "<tr><td>Android build version</td><td>"
+ buildVersion
+ "</td></tr>\n"
+ "<tr><td>Android release version</td><td>"
+ releaseVersion
+ "</td></tr>\n"
+ "<tr><td>Android SDK version</td><td>"
+ sdkVersion
+ "</td></tr>\n"
+ "<tr><td>Android build ID</td><td>"
+ buildID
+ "</td></tr>\n"
+ "<tr><td>Device brand</td><td>"
+ brand
+ "</td></tr>\n"
+ "<tr><td>Device manufacturer</td><td>"
+ manufacturer
+ "</td></tr>\n"
+ "<tr><td>Device name</td><td>"
+ device
+ "</td></tr>\n"
+ "<tr><td>Device model</td><td>"
+ model
+ "</td></tr>\n"
+ "<tr><td>Device product name</td><td>"
+ product
+ "</td></tr>\n"
+ "<tr><td>Device hardware name</td><td>"
+ hardware
+ "</td></tr>\n"
+ "<tr><td>ABIs</td><td>"
+ Arrays.toString(abis)
+ "</td></tr>\n"
+ "<tr><td>ABIs (32bit)</td><td>"
+ Arrays.toString(abis32Bits)
+ "</td></tr>\n"
+ "<tr><td>ABIs (64bit)</td><td>"
+ Arrays.toString(abis64Bits)
+ "</td></tr>\n"
+ "<tr><td>Language</td><td>"
+ selectedLang
+ "</td></tr>\n"
+ "</table>\n";
}
@NonNull
@Override
public String toString() {
return "App version: "
+ versionName
+ "\n"
+ "App version code: "
+ versionCode
+ "\n"
+ "Android build version: "
+ buildVersion
+ "\n"
+ "Android release version: "
+ releaseVersion
+ "\n"
+ "Android SDK version: "
+ sdkVersion
+ "\n"
+ "Android build ID: "
+ buildID
+ "\n"
+ "Device brand: "
+ brand
+ "\n"
+ "Device manufacturer: "
+ manufacturer
+ "\n"
+ "Device name: "
+ device
+ "\n"
+ "Device model: "
+ model
+ "\n"
+ "Device product name: "
+ product
+ "\n"
+ "Device hardware name: "
+ hardware
+ "\n"
+ "ABIs: "
+ Arrays.toString(abis)
+ "\n"
+ "ABIs (32bit): "
+ Arrays.toString(abis32Bits)
+ "\n"
+ "ABIs (64bit): "
+ Arrays.toString(abis64Bits)
+ "\n"
+ "Base theme: "
+ baseTheme
+ "\n"
+ "Now playing theme: "
+ nowPlayingTheme
+ "\n"
+ "Adaptive: "
+ isAdaptive
+ "\n"
+ "System language: "
+ Locale.getDefault().toLanguageTag()
+ "\n"
+ "In-App Language: "
+ selectedLang;
}
}

View file

@ -0,0 +1,110 @@
package code.name.monkey.retromusic.activities.bugreport.model
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.annotation.IntRange
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil.isAdaptiveColor
import code.name.monkey.retromusic.util.PreferenceUtil.languageCode
import code.name.monkey.retromusic.util.PreferenceUtil.nowPlayingScreen
import java.util.*
class DeviceInfo(context: Context) {
@SuppressLint("NewApi")
private val abis = Build.SUPPORTED_ABIS
@SuppressLint("NewApi")
private val abis32Bits = Build.SUPPORTED_32_BIT_ABIS
@SuppressLint("NewApi")
private val abis64Bits = Build.SUPPORTED_64_BIT_ABIS
private val baseTheme: String
private val brand = Build.BRAND
private val buildID = Build.DISPLAY
private val buildVersion = Build.VERSION.INCREMENTAL
private val device = Build.DEVICE
private val hardware = Build.HARDWARE
private val isAdaptive: Boolean
private val manufacturer = Build.MANUFACTURER
private val model = Build.MODEL
private val nowPlayingTheme: String
private val product = Build.PRODUCT
private val releaseVersion = Build.VERSION.RELEASE
@IntRange(from = 0)
private val sdkVersion = Build.VERSION.SDK_INT
private var versionCode = 0
private var versionName: String? = null
private val selectedLang: String
fun toMarkdown(): String {
return """
Device info:
---
<table>
<tr><td><b>App version</b></td><td>$versionName</td></tr>
<tr><td>App version code</td><td>$versionCode</td></tr>
<tr><td>Android build version</td><td>$buildVersion</td></tr>
<tr><td>Android release version</td><td>$releaseVersion</td></tr>
<tr><td>Android SDK version</td><td>$sdkVersion</td></tr>
<tr><td>Android build ID</td><td>$buildID</td></tr>
<tr><td>Device brand</td><td>$brand</td></tr>
<tr><td>Device manufacturer</td><td>$manufacturer</td></tr>
<tr><td>Device name</td><td>$device</td></tr>
<tr><td>Device model</td><td>$model</td></tr>
<tr><td>Device product name</td><td>$product</td></tr>
<tr><td>Device hardware name</td><td>$hardware</td></tr>
<tr><td>ABIs</td><td>${Arrays.toString(abis)}</td></tr>
<tr><td>ABIs (32bit)</td><td>${Arrays.toString(abis32Bits)}</td></tr>
<tr><td>ABIs (64bit)</td><td>${Arrays.toString(abis64Bits)}</td></tr>
<tr><td>Language</td><td>$selectedLang</td></tr>
</table>
""".trimIndent()
}
override fun toString(): String {
return """
App version: $versionName
App version code: $versionCode
Android build version: $buildVersion
Android release version: $releaseVersion
Android SDK version: $sdkVersion
Android build ID: $buildID
Device brand: $brand
Device manufacturer: $manufacturer
Device name: $device
Device model: $model
Device product name: $product
Device hardware name: $hardware
ABIs: ${Arrays.toString(abis)}
ABIs (32bit): ${Arrays.toString(abis32Bits)}
ABIs (64bit): ${Arrays.toString(abis64Bits)}
Base theme: $baseTheme
Now playing theme: $nowPlayingTheme
Adaptive: $isAdaptive
System language: ${Locale.getDefault().toLanguageTag()}
In-App Language: $selectedLang
""".trimIndent()
}
init {
val packageInfo = try {
context.packageManager.getPackageInfo(context.packageName, 0)
} catch (e: PackageManager.NameNotFoundException) {
null
}
if (packageInfo != null) {
versionCode = packageInfo.versionCode
versionName = packageInfo.versionName
} else {
versionCode = -1
versionName = null
}
baseTheme = PreferenceUtil.baseTheme
nowPlayingTheme = context.getString(nowPlayingScreen.titleRes)
isAdaptive = isAdaptiveColor
selectedLang = languageCode
}
}

View file

@ -1,34 +0,0 @@
package code.name.monkey.retromusic.activities.bugreport.model;
import code.name.monkey.retromusic.activities.bugreport.model.github.ExtraInfo;
public class Report {
private final String description;
private final DeviceInfo deviceInfo;
private final ExtraInfo extraInfo;
private final String title;
public Report(String title, String description, DeviceInfo deviceInfo, ExtraInfo extraInfo) {
this.title = title;
this.description = description;
this.deviceInfo = deviceInfo;
this.extraInfo = extraInfo;
}
public String getDescription() {
return description
+ "\n\n"
+ "-\n\n"
+ deviceInfo.toMarkdown()
+ "\n\n"
+ extraInfo.toMarkdown();
}
public String getTitle() {
return title;
}
}

View file

@ -0,0 +1,22 @@
package code.name.monkey.retromusic.activities.bugreport.model
import code.name.monkey.retromusic.activities.bugreport.model.github.ExtraInfo
class Report(
val title: String,
private val description: String,
private val deviceInfo: DeviceInfo?,
private val extraInfo: ExtraInfo
) {
fun getDescription(): String {
return """
$description
-
${deviceInfo?.toMarkdown()}
${extraInfo.toMarkdown()}
""".trimIndent()
}
}

View file

@ -1,61 +0,0 @@
package code.name.monkey.retromusic.activities.bugreport.model.github;
import java.util.LinkedHashMap;
import java.util.Map;
public class ExtraInfo {
private final Map<String, String> extraInfo = new LinkedHashMap<>();
public void put(String key, String value) {
extraInfo.put(key, value);
}
public void put(String key, boolean value) {
extraInfo.put(key, Boolean.toString(value));
}
public void put(String key, double value) {
extraInfo.put(key, Double.toString(value));
}
public void put(String key, float value) {
extraInfo.put(key, Float.toString(value));
}
public void put(String key, long value) {
extraInfo.put(key, Long.toString(value));
}
public void put(String key, int value) {
extraInfo.put(key, Integer.toString(value));
}
public void put(String key, Object value) {
extraInfo.put(key, String.valueOf(value));
}
public void remove(String key) {
extraInfo.remove(key);
}
public String toMarkdown() {
if (extraInfo.isEmpty()) {
return "";
}
StringBuilder output = new StringBuilder();
output.append("Extra info:\n" + "---\n" + "<table>\n");
for (String key : extraInfo.keySet()) {
output
.append("<tr><td>")
.append(key)
.append("</td><td>")
.append(extraInfo.get(key))
.append("</td></tr>\n");
}
output.append("</table>\n");
return output.toString();
}
}

View file

@ -0,0 +1,61 @@
package code.name.monkey.retromusic.activities.bugreport.model.github
class ExtraInfo {
private val extraInfo: MutableMap<String, String> = LinkedHashMap()
fun put(key: String, value: String) {
extraInfo[key] = value
}
fun put(key: String, value: Boolean) {
extraInfo[key] = value.toString()
}
fun put(key: String, value: Double) {
extraInfo[key] = value.toString()
}
fun put(key: String, value: Float) {
extraInfo[key] = value.toString()
}
fun put(key: String, value: Long) {
extraInfo[key] = value.toString()
}
fun put(key: String, value: Int) {
extraInfo[key] = value.toString()
}
fun put(key: String, value: Any) {
extraInfo[key] = value.toString()
}
fun remove(key: String) {
extraInfo.remove(key)
}
fun toMarkdown(): String {
if (extraInfo.isEmpty()) {
return ""
}
val output = StringBuilder()
output.append(
"""
Extra info:
---
<table>
""".trimIndent()
)
for (key in extraInfo.keys) {
output
.append("<tr><td>")
.append(key)
.append("</td><td>")
.append(extraInfo[key])
.append("</td></tr>\n")
}
output.append("</table>\n")
return output.toString()
}
}

View file

@ -1,40 +0,0 @@
package code.name.monkey.retromusic.activities.bugreport.model.github;
import android.text.TextUtils;
public class GithubLogin {
private final String apiToken;
private final String password;
private final String username;
public GithubLogin(String username, String password) {
this.username = username;
this.password = password;
this.apiToken = null;
}
public GithubLogin(String apiToken) {
this.username = null;
this.password = null;
this.apiToken = apiToken;
}
public String getApiToken() {
return apiToken;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
public boolean shouldUseApiToken() {
return TextUtils.isEmpty(username) || TextUtils.isEmpty(password);
}
}

View file

@ -0,0 +1,25 @@
package code.name.monkey.retromusic.activities.bugreport.model.github
import android.text.TextUtils
class GithubLogin {
val apiToken: String?
val password: String?
val username: String?
constructor(username: String?, password: String?) {
this.username = username
this.password = password
apiToken = null
}
constructor(apiToken: String?) {
username = null
password = null
this.apiToken = apiToken
}
fun shouldUseApiToken(): Boolean {
return TextUtils.isEmpty(username) || TextUtils.isEmpty(password)
}
}

View file

@ -1,21 +0,0 @@
package code.name.monkey.retromusic.activities.bugreport.model.github;
public class GithubTarget {
private final String repository;
private final String username;
public GithubTarget(String username, String repository) {
this.username = username;
this.repository = repository;
}
public String getRepository() {
return repository;
}
public String getUsername() {
return username;
}
}

View file

@ -0,0 +1,3 @@
package code.name.monkey.retromusic.activities.bugreport.model.github
class GithubTarget(val username: String, val repository: String)

View file

@ -51,7 +51,7 @@ class TagWriter {
suspend fun writeTagsToFiles(context: Context, info: AudioTagInfo) {
withContext(Dispatchers.IO) {
kotlin.runCatching {
runCatching {
var artwork: Artwork? = null
var albumArtFile: File? = null
if (info.artworkInfo?.artwork != null) {
@ -124,7 +124,7 @@ class TagWriter {
suspend fun writeTagsToFilesR(context: Context, info: AudioTagInfo): List<File> =
withContext(Dispatchers.IO) {
val cacheFiles = mutableListOf<File>()
kotlin.runCatching {
runCatching {
var artwork: Artwork? = null
var albumArtFile: File? = null
if (info.artworkInfo?.artwork != null) {

View file

@ -64,4 +64,7 @@ interface PlaylistDao {
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
fun favoritesSongs(playlistId: Long): List<SongEntity>
@Query("SELECT EXISTS(SELECT * FROM PlaylistEntity WHERE playlist_id = :playlistId)")
fun checkPlaylistExists(playlistId: Long): LiveData<Boolean>
}

View file

@ -15,15 +15,9 @@
package code.name.monkey.retromusic.fragments.base
import android.os.Bundle
import android.view.View
import androidx.annotation.LayoutRes
import code.name.monkey.appthemehelper.util.ColorUtil
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.extensions.setLightStatusBarAuto
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.LibraryViewModel
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
@ -38,26 +32,4 @@ abstract class AbsMainActivityFragment(@LayoutRes layout: Int) : AbsMusicService
setHasOptionsMenu(true)
mainActivity.setTaskDescriptionColorAuto()
}
private fun setStatusBarColor(view: View, color: Int) {
val statusBar = view.findViewById<View>(R.id.status_bar)
if (statusBar != null) {
if (VersionUtils.hasMarshmallow()) {
statusBar.setBackgroundColor(color)
mainActivity.setLightStatusBarAuto(color)
} else {
statusBar.setBackgroundColor(color)
}
}
}
fun setStatusBarColorAuto(view: View) {
val colorPrimary = surfaceColor()
// we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat
if (VersionUtils.hasMarshmallow()) {
setStatusBarColor(view, colorPrimary)
} else {
setStatusBarColor(view, ColorUtil.darkenColor(colorPrimary))
}
}
}

View file

@ -220,10 +220,10 @@ abstract class AbsPlayerControlsFragment(@LayoutRes layout: Int) : AbsMusicServi
childFragmentManager.beginTransaction()
.replace(R.id.volumeFragmentContainer, VolumeFragment()).commit()
childFragmentManager.executePendingTransactions()
}
volumeFragment =
childFragmentManager.findFragmentById(R.id.volumeFragmentContainer) as? VolumeFragment
}
}
override fun onResume() {
super.onResume()

View file

@ -137,7 +137,6 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum
}
companion object {
fun newInstance(): VolumeFragment {
return VolumeFragment()
}

View file

@ -77,7 +77,10 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
fun removeSlideEffect() {
val transformer = ParallaxPagerTransformer(R.id.player_image)
transformer.setSpeed(0.3f)
lifecycleScope.launchWhenStarted {
viewPager.setPageTransformer(false, transformer)
}
}
private fun updateLyrics() {
binding.lyricsView.setLabel(context?.getString(R.string.no_lyrics_found))

View file

@ -19,6 +19,7 @@ import android.os.Bundle
import android.view.View
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
@ -59,6 +60,12 @@ class CardPlaybackControlsFragment :
override val previousButton: ImageButton
get() = binding.mediaButton.previousButton
override val songTotalTime: TextView
get() = binding.songTotalTime
override val songCurrentProgress: TextView
get() = binding.songCurrentProgress
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentCardPlayerPlaybackControlsBinding.bind(view)

View file

@ -20,6 +20,7 @@ import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R
@ -55,6 +56,12 @@ class CardBlurPlaybackControlsFragment :
override val previousButton: ImageButton
get() = binding.mediaButton.previousButton
override val songTotalTime: TextView
get() = binding.songTotalTime
override val songCurrentProgress: TextView
get() = binding.songCurrentProgress
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentCardBlurPlayerPlaybackControlsBinding.bind(view)

View file

@ -39,7 +39,6 @@ class ColorFragment : AbsPlayerFragment(R.layout.fragment_color_player) {
private var _binding: FragmentColorPlayerBinding? = null
private val binding get() = _binding!!
override fun playerToolbar(): Toolbar {
return binding.playerToolbar
}

View file

@ -9,6 +9,7 @@ import androidx.activity.addCallback
import androidx.core.view.ViewCompat
import androidx.core.view.doOnPreDraw
import androidx.core.view.isVisible
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -58,7 +59,6 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(view)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
setHasOptionsMenu(true)
mainActivity.addMusicServiceEventListener(viewModel)
mainActivity.setSupportActionBar(binding.toolbar)
ViewCompat.setTransitionName(binding.container, "playlist")
playlist = arguments.extraPlaylist
@ -67,6 +67,11 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
viewModel.getSongs().observe(viewLifecycleOwner) {
songs(it.toSongs())
}
viewModel.playlistExists().observe(viewLifecycleOwner) {
if (!it) {
findNavController().navigateUp()
}
}
postponeEnterTransition()
requireView().doOnPreDraw { startPostponedEnterTransition() }
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {

View file

@ -22,24 +22,15 @@ import code.name.monkey.retromusic.db.SongEntity
import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.repository.RealRoomRepository
class PlaylistDetailsViewModel(
private val realRepository: RealRepository,
private var playlist: PlaylistWithSongs
) : ViewModel(), IMusicServiceEventListener {
private val playListSongs = MutableLiveData<List<Song>>()
) : ViewModel() {
fun getSongs(): LiveData<List<SongEntity>> =
realRepository.playlistSongs(playlist.playlistEntity.playListId)
override fun onMediaStoreChanged() {}
override fun onServiceConnected() {}
override fun onServiceDisconnected() {}
override fun onQueueChanged() {}
override fun onPlayingMetaChanged() {}
override fun onPlayStateChanged() {}
override fun onRepeatModeChanged() {}
override fun onShuffleModeChanged() {}
override fun onFavoriteStateChanged() {}
fun playlistExists(): LiveData<Boolean> =
realRepository.checkPlaylistExists(playlist.playlistEntity.playListId)
}

View file

@ -14,6 +14,7 @@
*/
package code.name.monkey.retromusic.fragments.search
import android.app.Activity.RESULT_OK
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.res.ColorStateList
@ -221,6 +222,16 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
val spokenText: String? =
data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
.let { text -> text?.get(0) }
binding.searchView.setText(spokenText)
}
}
override fun onDestroyView() {
hideKeyboard(view)
super.onDestroyView()

View file

@ -25,7 +25,6 @@ import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.GridStyle
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder.SongSortOrder
import code.name.monkey.retromusic.interfaces.ICabCallback
import code.name.monkey.retromusic.interfaces.ICabHolder
@ -66,7 +65,7 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
get() = true
override fun onShuffleClicked() {
libraryViewModel.getSongs().value?.let { MusicPlayerRemote.openAndShuffleQueue(it, true) }
libraryViewModel.shuffleSongs()
}
override fun createLayoutManager(): GridLayoutManager {

View file

@ -302,7 +302,7 @@ object MusicPlayerRemote : KoinComponent {
fun setShuffleMode(shuffleMode: Int): Boolean {
if (musicService != null) {
musicService!!.shuffleMode = shuffleMode
musicService!!.setShuffleMode(shuffleMode)
return true
}
return false

View file

@ -111,6 +111,7 @@ interface Repository {
suspend fun searchAlbums(query: String): List<Album>
suspend fun isSongFavorite(songId: Long): Boolean
fun getSongByGenre(genreId: Long): Song
fun checkPlaylistExists(playListId: Long): LiveData<Boolean>
}
class RealRepository(
@ -277,6 +278,9 @@ class RealRepository(
override suspend fun checkPlaylistExists(playlistName: String): List<PlaylistEntity> =
roomRepository.checkPlaylistExists(playlistName)
override fun checkPlaylistExists(playListId: Long): LiveData<Boolean> =
roomRepository.checkPlaylistExists(playListId)
override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long =
roomRepository.createPlaylist(playlistEntity)
@ -377,7 +381,7 @@ class RealRepository(
}
override suspend fun suggestions(): List<Song> {
if (!PreferenceUtil.homeSuggestions) return listOf<Song>()
if (!PreferenceUtil.homeSuggestions) return listOf()
return NotPlayedPlaylist().songs().shuffled().takeIf {
it.size > 9
} ?: emptyList()

View file

@ -49,6 +49,7 @@ interface RoomRepository {
suspend fun blackListPaths(): List<BlackListStoreEntity>
suspend fun deleteSongs(songs: List<Song>)
suspend fun isSongFavorite(context: Context, songId: Long): Boolean
fun checkPlaylistExists(playListId: Long): LiveData<Boolean>
}
class RealRoomRepository(
@ -97,6 +98,9 @@ class RealRoomRepository(
override fun getSongs(playListId: Long): LiveData<List<SongEntity>> =
playlistDao.songsFromPlaylist(playListId)
override fun checkPlaylistExists(playListId: Long): LiveData<Boolean> =
playlistDao.checkPlaylistExists(playListId)
override suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>) =
playlistDao.deletePlaylists(playlistEntities)

View file

@ -43,6 +43,8 @@ interface SongRepository {
fun songs(cursor: Cursor?): List<Song>
fun sortedSongs(cursor: Cursor?): List<Song>
fun songs(query: String): List<Song>
fun songsByFilePath(filePath: String, ignoreBlacklist: Boolean = false): List<Song>
@ -57,7 +59,7 @@ interface SongRepository {
class RealSongRepository(private val context: Context) : SongRepository {
override fun songs(): List<Song> {
return songs(makeSongCursor(null, null))
return sortedSongs(makeSongCursor(null, null))
}
override fun songs(cursor: Cursor?): List<Song> {
@ -68,7 +70,12 @@ class RealSongRepository(private val context: Context) : SongRepository {
} while (cursor.moveToNext())
}
cursor?.close()
return songs
}
override fun sortedSongs(cursor: Cursor?): List<Song> {
val collator = Collator.getInstance()
val songs = songs(cursor)
return when (PreferenceUtil.songSortOrder) {
SortOrder.SongSortOrder.SONG_A_Z -> {
songs.sortedWith{ s1, s2 -> collator.compare(s1.title, s2.title) }

View file

@ -9,6 +9,7 @@ import android.media.MediaPlayer
import android.media.audiofx.AudioEffect
import android.net.Uri
import android.os.PowerManager
import android.util.Log
import android.widget.Toast
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -296,6 +297,7 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
Toast.LENGTH_SHORT
)
.show()
Log.e(TAG, what.toString() + extra)
return false
}
@ -354,6 +356,10 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
override fun setCrossFadeDuration(duration: Int) {
crossFadeDuration = duration
}
companion object {
val TAG: String = CrossFadePlayer::class.java.simpleName
}
}
internal fun crossFadeScope(): CoroutineScope = CoroutineScope(Job() + Dispatchers.Main)

View file

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

View file

@ -15,7 +15,6 @@
package code.name.monkey.retromusic.service
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.provider.MediaStore
import android.support.v4.media.session.MediaSessionCompat
@ -179,10 +178,6 @@ class MediaSessionCallback(
musicService.seek(pos.toInt())
}
override fun onMediaButtonEvent(mediaButtonIntent: Intent): Boolean {
return MediaButtonIntentReceiver.handleIntent(context, mediaButtonIntent)
}
override fun onCustomAction(action: String, extras: Bundle?) {
when (action) {
CYCLE_REPEAT -> {

View file

@ -330,6 +330,7 @@ public class MultiPlayer
context.getResources().getString(R.string.unplayable_file),
Toast.LENGTH_SHORT)
.show();
Log.e(TAG, String.valueOf(what) + extra);
}
return false;
}

View file

@ -14,7 +14,6 @@
package code.name.monkey.retromusic.service
import android.app.NotificationManager
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.bluetooth.BluetoothDevice
import android.content.*
@ -47,9 +46,9 @@ import androidx.media.AudioAttributesCompat.CONTENT_TYPE_MUSIC
import androidx.media.AudioFocusRequestCompat
import androidx.media.AudioManagerCompat
import androidx.media.MediaBrowserServiceCompat
import androidx.media.session.MediaButtonReceiver.handleIntent
import androidx.preference.PreferenceManager
import code.name.monkey.appthemehelper.util.VersionUtils.hasMarshmallow
import code.name.monkey.appthemehelper.util.VersionUtils.hasQ
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.activities.LockScreenActivity
import code.name.monkey.retromusic.appwidgets.*
@ -175,10 +174,10 @@ class MusicService : MediaBrowserServiceCompat(),
private lateinit var mediaStoreObserver: ContentObserver
private var musicPlayerHandlerThread: HandlerThread? = null
private var notHandledMetaChangedForCurrentTrack = false
private var originalPlayingQueue = mutableListOf<Song>()
private var originalPlayingQueue = ArrayList<Song>()
@JvmField
var playingQueue = mutableListOf<Song>()
var playingQueue = ArrayList<Song>()
var isPausedByTransientLossOfFocus = false
private val becomingNoisyReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@ -540,7 +539,7 @@ class MusicService : MediaBrowserServiceCompat(),
return shuffleMode
}
private fun setShuffleMode(shuffleMode: Int) {
fun setShuffleMode(shuffleMode: Int) {
PreferenceManager.getDefaultSharedPreferences(this)
.edit()
.putInt(SAVED_SHUFFLE_MODE, shuffleMode)
@ -752,6 +751,7 @@ class MusicService : MediaBrowserServiceCompat(),
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent != null && intent.action != null) {
handleIntent(mediaSession, intent)
restoreQueuesAndPositionIfNecessary()
when (intent.action) {
ACTION_TOGGLE_PAUSE -> if (isPlaying) {
@ -822,8 +822,8 @@ class MusicService : MediaBrowserServiceCompat(),
}
}
@Synchronized
fun openTrackAndPrepareNextAt(position: Int): Boolean {
synchronized(this) {
this.position = position
val prepared = openCurrent()
if (prepared) {
@ -833,7 +833,6 @@ class MusicService : MediaBrowserServiceCompat(),
notHandledMetaChangedForCurrentTrack = false
return prepared
}
}
fun pause() {
Log.i(TAG, "Paused")
@ -856,8 +855,8 @@ class MusicService : MediaBrowserServiceCompat(),
}
}
@Synchronized
fun play() {
synchronized(this) {
if (requestFocus()) {
if (playback != null && !playback!!.isPlaying) {
if (!playback!!.isInitialized) {
@ -899,7 +898,6 @@ class MusicService : MediaBrowserServiceCompat(),
.show()
}
}
}
fun playNextSong(force: Boolean) {
playSongAt(getNextPosition(force))
@ -947,8 +945,8 @@ class MusicService : MediaBrowserServiceCompat(),
}
}
@Synchronized
fun prepareNextImpl() {
synchronized(this) {
try {
val nextPosition = getNextPosition(false)
playback?.setNextDataSource(getTrackUri(getSongAt(nextPosition)))
@ -956,7 +954,6 @@ class MusicService : MediaBrowserServiceCompat(),
} catch (ignored: Exception) {
}
}
}
fun quit() {
pause()
@ -1037,8 +1034,8 @@ class MusicService : MediaBrowserServiceCompat(),
SAVED_POSITION_IN_TRACK, -1
)
if (restoredQueue.size > 0 && restoredQueue.size == restoredOriginalQueue.size && restoredPosition != -1) {
originalPlayingQueue = restoredOriginalQueue
playingQueue = restoredQueue
originalPlayingQueue = ArrayList(restoredOriginalQueue)
playingQueue = ArrayList(restoredQueue)
position = restoredPosition
openCurrent()
prepareNext()
@ -1073,8 +1070,8 @@ class MusicService : MediaBrowserServiceCompat(),
savePositionInTrack()
}
@Synchronized
fun seek(millis: Int): Int {
synchronized(this) {
return try {
var newPosition = 0
if (playback != null) {
@ -1086,7 +1083,6 @@ class MusicService : MediaBrowserServiceCompat(),
-1
}
}
}
// to let other apps know whats playing. i.E. last.fm (scrobbling) or musixmatch
fun sendPublicIntent(what: String) {
@ -1223,6 +1219,7 @@ class MusicService : MediaBrowserServiceCompat(),
}
META_CHANGED -> {
playingNotification?.updateMetadata(currentSong) { startForegroundOrNotify() }
playingNotification?.updateFavorite(currentSong) { startForegroundOrNotify() }
updateMediaSessionMetaData()
updateMediaSessionPlaybackState()
savePosition()
@ -1248,19 +1245,19 @@ class MusicService : MediaBrowserServiceCompat(),
private fun startForegroundOrNotify() {
if (playingNotification != null && currentSong.id != -1L) {
val isPlaying = isPlaying
if (isForeground != isPlaying && !isPlaying) {
if (!VersionUtils.hasS()) {
if (isForeground && !isPlaying) {
// This makes the notification dismissible
// We can't call stopForeground(false) on A12 though, which may result in crashes
// when we call startForeground after that e.g. when Alarm goes off,
if (VERSION.SDK_INT < VERSION_CODES.S) {
// when we call startForeground after that e.g. when Alarm goes off
stopForeground(false)
isForeground = false
}
}
if (!isForeground && isPlaying) {
if (!isForeground) {
// Specify that this is a media service, if supported.
if (hasQ()) {
if (VersionUtils.hasQ()) {
startForeground(
PlayingNotification.NOTIFICATION_ID, playingNotification!!.build(),
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
@ -1279,7 +1276,6 @@ class MusicService : MediaBrowserServiceCompat(),
)
}
}
return
}
private fun stopForegroundAndNotification() {
@ -1288,9 +1284,9 @@ class MusicService : MediaBrowserServiceCompat(),
isForeground = false
}
@Synchronized
private fun openCurrent(): Boolean {
synchronized(this) {
try {
return try {
if (playback != null) {
return playback!!.setDataSource(
getTrackUri(
@ -1299,14 +1295,12 @@ class MusicService : MediaBrowserServiceCompat(),
)
)
)
}
} else false
} catch (e: Exception) {
e.printStackTrace()
return false
false
}
}
return false
}
private fun playFromPlaylist(intent: Intent) {
val playlist: AbsSmartPlaylist? = intent.getParcelableExtra(INTENT_EXTRA_PLAYLIST)
@ -1443,24 +1437,13 @@ class MusicService : MediaBrowserServiceCompat(),
}
private fun setupMediaSession() {
val mediaButtonReceiverComponentName =
ComponentName(applicationContext, MediaButtonIntentReceiver::class.java)
val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON)
mediaButtonIntent.component = mediaButtonReceiverComponentName
val mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(
applicationContext, 0, mediaButtonIntent,
if (hasMarshmallow()) PendingIntent.FLAG_IMMUTABLE else 0
)
mediaSession = MediaSessionCompat(
this,
"RetroMusicPlayer",
mediaButtonReceiverComponentName,
mediaButtonReceiverPendingIntent
"RetroMusicPlayer"
)
val mediasessionCallback = MediaSessionCallback(applicationContext, this)
mediaSession?.setCallback(mediasessionCallback)
mediaSession?.isActive = true
mediaSession?.setMediaButtonReceiver(mediaButtonReceiverPendingIntent)
}
inner class MusicBinder : Binder() {

View file

@ -25,6 +25,7 @@ import android.graphics.Color
import android.graphics.drawable.Drawable
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.media.app.NotificationCompat.DecoratedMediaCustomViewStyle
import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
@ -57,7 +58,6 @@ class PlayingNotificationClassic(
val context: Context
) : PlayingNotification(context) {
private var primaryColor: Int = 0
private var isInitialized = false
private fun getCombinedRemoteViews(collapsed: Boolean, song: Song): RemoteViews {
val remoteViews = RemoteViews(
@ -75,7 +75,6 @@ class PlayingNotificationClassic(
}
override fun updateMetadata(song: Song, onUpdate: () -> Unit) {
isInitialized = true
val notificationLayout = getCombinedRemoteViews(true, song)
val notificationLayoutBig = getCombinedRemoteViews(false, song)
@ -98,11 +97,11 @@ class PlayingNotificationClassic(
setContentIntent(clickIntent)
setDeleteIntent(deleteIntent)
setCategory(NotificationCompat.CATEGORY_SERVICE)
setColorized(PreferenceUtil.isColoredNotification)
priority = NotificationCompat.PRIORITY_MAX
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
setCustomContentView(notificationLayout)
setCustomBigContentView(notificationLayoutBig)
setStyle(DecoratedMediaCustomViewStyle())
setOngoing(true)
val bigNotificationImageSize = context.resources
.getDimensionPixelSize(R.dimen.notification_big_image_size)
@ -164,6 +163,7 @@ class PlayingNotificationClassic(
setNotificationContent(ColorUtil.isColorLight(bgColorFinal))
} else {
if (PreferenceUtil.isColoredNotification) {
setColorized(true)
color = bgColor
setNotificationContent(color.isColorLight)
} else {

View file

@ -46,7 +46,10 @@ import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@SuppressLint("RestrictedApi")
class PlayingNotificationImpl24(
@ -114,11 +117,6 @@ class PlayingNotificationImpl24(
.setShowActionsInCompactView(1, 2, 3)
)
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
if (Build.VERSION.SDK_INT <=
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
) {
this.color = color
}
}
override fun updateMetadata(song: Song, onUpdate: () -> Unit) {
@ -181,7 +179,6 @@ class PlayingNotificationImpl24(
onUpdate()
}
})
updateFavorite(song, onUpdate)
}
private fun buildPlayAction(isPlaying: Boolean): NotificationCompat.Action {

View file

@ -49,6 +49,4 @@ class CarousalPagerTransformer(context: Context) : ViewPager.PageTransformer {
val m = context.resources.displayMetrics.density
return (dipValue * m + 0.5f).toInt()
}
}

View file

@ -22,21 +22,28 @@ class CascadingPageTransformer : ViewPager.PageTransformer {
private var mScaleOffset = 40
override fun transformPage(page: View, position: Float) {
if (position <= 0.0f) {//被滑动的那页 position 是-下标~ 0
page.translationX = 0f
//旋转角度 45° * -0.1 = -4.5°
page.rotation = 45 * position
//X轴偏移 li: 300/3 * -0.1 = -10
page.translationX = page.width / 3 * position
} else {
//缩放比例
val scale = (page.width - mScaleOffset * position) / page.width.toFloat()
page.apply {
when {
position < -1 -> { // [-Infinity,-1)
alpha = 0f
}
position <= 0 -> {
alpha = 1f
rotation = 45 * position
translationX = width / 3 * position
}
else -> {
alpha = 1f
rotation = 0f
val scale = (width - mScaleOffset * position) / width.toFloat()
page.scaleX = scale
page.scaleY = scale
scaleX = scale
scaleY = scale
page.translationX = -page.width * position
page.translationY = mScaleOffset * 0.8f * position
translationX = -width * position
translationY = mScaleOffset * 0.8f * position
}
}
}
}
}

View file

@ -0,0 +1,8 @@
package code.name.monkey.retromusic.transform
import android.view.View
import androidx.viewpager.widget.ViewPager
class DefaultTransformer : ViewPager.PageTransformer {
override fun transformPage(page: View, position: Float) {}
}

View file

@ -20,28 +20,40 @@ import kotlin.math.abs
class DepthTransformation : ViewPager.PageTransformer {
override fun transformPage(page: View, position: Float) {
page.apply {
when {
position < -1 -> { // [-Infinity,-1)
// This page is way off-screen to the left.
page.alpha = 0f
alpha = 0f
}
position <= 0 -> { // [-1,0]
page.alpha = 1f
page.translationX = 0f
page.scaleX = 1f
page.scaleY = 1f
// Use the default slide transition when moving to the left page
alpha = 1f
translationX = 0f
scaleX = 1f
scaleY = 1f
}
position <= 1 -> { // (0,1]
page.translationX = -position * page.width
page.alpha = 1 - abs(position)
page.scaleX = 1 - abs(position)
page.scaleY = 1 - abs(position)
// Fade the page out.
alpha = 1 - position
// Counteract the default slide transition
translationX = width * -position
// Scale the page down (between MIN_SCALE and 1)
val scaleFactor = (MIN_SCALE + (1 - MIN_SCALE) * (1 - abs(position)))
scaleX = scaleFactor
scaleY = scaleFactor
}
else -> { // (1,+Infinity]
// This page is way off-screen to the right.
page.alpha = 0f
alpha = 0f
}
}
}
}
}
}
companion object {
private const val MIN_SCALE = 0.5f
}
}

View file

@ -21,35 +21,35 @@ import kotlin.math.abs
class HingeTransformation : ViewPager.PageTransformer {
override fun transformPage(page: View, position: Float) {
page.translationX = -position * page.width
page.pivotX = 0f
page.pivotY = 0f
page.apply {
translationX = -position * width
pivotX = 0f
pivotY = 0f
when {
position < -1 -> { // [-Infinity,-1)
// This page is way off-screen to the left.
page.alpha = 0f
alpha = 0f
// The Page is off-screen but it may still interfere with
// click events of current page if
// it's visibility is not set to Gone
page.isVisible = false
isVisible = false
}
position <= 0 -> { // [-1,0]
page.rotation = 90 * abs(position)
page.alpha = 1 - abs(position)
page.isVisible = true
rotation = 90 * abs(position)
alpha = 1 - abs(position)
isVisible = true
}
position <= 1 -> { // (0,1]
page.rotation = 0f
page.alpha = 1f
page.isVisible = true
rotation = 0f
alpha = 1f
isVisible = true
}
else -> { // (1,+Infinity]
// This page is way off-screen to the right.
page.alpha = 0f
page.isVisible = false
alpha = 0f
isVisible = false
}
}
}
}

View file

@ -22,7 +22,7 @@ import kotlin.math.abs
class HorizontalFlipTransformation : ViewPager.PageTransformer {
override fun transformPage(page: View, position: Float) {
page.apply {
page.translationX = -position * page.width
page.cameraDistance = 20000f
@ -32,7 +32,6 @@ class HorizontalFlipTransformation : ViewPager.PageTransformer {
page.isInvisible = true
}
when {
position < -1 -> { // [-Infinity,-1)
// This page is way off-screen to the left.
@ -52,4 +51,5 @@ class HorizontalFlipTransformation : ViewPager.PageTransformer {
}
}
}
}
}

View file

@ -25,39 +25,41 @@ import kotlin.math.max
class NormalPageTransformer : ViewPager.PageTransformer {
override fun transformPage(view: View, position: Float) {
val pageWidth = view.width
val pageHeight = view.height
override fun transformPage(page: View, position: Float) {
page.apply {
val pageWidth = width
val pageHeight = height
when {
position < -1 -> { // [-Infinity,-1)
// This page is way off-screen to the left.
view.alpha = 1f
view.scaleY = 0.7f
alpha = 1f
scaleY = 0.7f
}
position <= 1 -> { // [-1,1]
// Modify the default slide transition to shrink the page as well
val scaleFactor = max(MIN_SCALE, 1 - abs(position))
val vertMargin = pageHeight * (1 - scaleFactor) / 2
val horzMargin = pageWidth * (1 - scaleFactor) / 2
if (position < 0) {
view.translationX = horzMargin - vertMargin / 2
translationX = if (position < 0) {
horzMargin - vertMargin / 2
} else {
view.translationX = -horzMargin + vertMargin / 2
-horzMargin + vertMargin / 2
}
// Scale the page down (between MIN_SCALE and 1)
view.scaleX = scaleFactor
view.scaleY = scaleFactor
scaleX = scaleFactor
scaleY = scaleFactor
// Fade the page relative to its size.
//view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
//setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
}
else -> { // (1,+Infinity]
// This page is way off-screen to the right.
view.alpha = 1f
view.scaleY = 0.7f
alpha = 1f
scaleY = 0.7f
}
}
}
}

View file

@ -14,8 +14,6 @@
package code.name.monkey.retromusic.transform
import android.annotation.TargetApi
import android.os.Build
import android.view.View
import androidx.viewpager.widget.ViewPager
@ -27,22 +25,21 @@ class ParallaxPagerTransformer(private val id: Int) : ViewPager.PageTransformer
private var border = 0
private var speed = 0.2f
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
override fun transformPage(view: View, position: Float) {
val parallaxView = view.findViewById<View>(id)
override fun transformPage(page: View, position: Float) {
val parallaxView = page.findViewById<View>(id)
page.apply {
if (parallaxView != null) {
if (position > -1 && position < 1) {
val width = parallaxView.width.toFloat()
parallaxView.translationX = -(position * width * speed)
val sc = (view.width.toFloat() - border) / view.width
val sc = (width - border) / width
if (position == 0f) {
view.scaleX = 1f
view.scaleY = 1f
scaleX = 1f
scaleY = 1f
} else {
view.scaleX = sc
view.scaleY = sc
scaleX = sc
scaleY = sc
}
}
}
}

View file

@ -22,37 +22,35 @@ import kotlin.math.abs
class VerticalFlipTransformation : ViewPager.PageTransformer {
override fun transformPage(page: View, position: Float) {
page.translationX = -position * page.width
page.cameraDistance = 100000f
page.apply {
translationX = -position * width
cameraDistance = 100000f
if (position < 0.5 && position > -0.5) {
page.isVisible = true
isVisible = true
} else {
page.isInvisible = true
isInvisible = true
}
when {
position < -1 -> { // [-Infinity,-1)
// This page is way off-screen to the left.
page.alpha = 0f
alpha = 0f
}
position <= 0 -> { // [-1,0]
page.alpha = 1f
page.rotationY = 180 * (1 - abs(position) + 1)
alpha = 1f
rotationY = 180 * (1 - abs(position) + 1)
}
position <= 1 -> { // (0,1]
page.alpha = 1f
page.rotationY = -180 * (1 - abs(position) + 1)
alpha = 1f
rotationY = -180 * (1 - abs(position) + 1)
}
else -> { // (1,+Infinity]
// This page is way off-screen to the right.
page.alpha = 0f
alpha = 0f
}
}
}
}
}

View file

@ -19,11 +19,14 @@ import androidx.viewpager.widget.ViewPager
class VerticalStackTransformer : ViewPager.PageTransformer {
override fun transformPage(page: View, position: Float) {
page.apply {
if (position >= 0) {
page.scaleX = (0.9f - 0.05f * position)
page.scaleY = 0.9f
page.translationX = -page.width * position
page.translationY = -30 * position
scaleX = (0.9f - 0.05f * position)
scaleY = 0.9f
translationX = -width * position
translationY = -30 * position
}
}
}
}

View file

@ -1,64 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.volume;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Handler;
import androidx.annotation.NonNull;
public class AudioVolumeContentObserver extends ContentObserver {
private final OnAudioVolumeChangedListener mListener;
private final AudioManager mAudioManager;
private final int mAudioStreamType;
private float mLastVolume;
AudioVolumeContentObserver(
@NonNull Handler handler,
@NonNull AudioManager audioManager,
int audioStreamType,
@NonNull OnAudioVolumeChangedListener listener) {
super(handler);
mAudioManager = audioManager;
mAudioStreamType = audioStreamType;
mListener = listener;
mLastVolume = audioManager.getStreamVolume(mAudioStreamType);
}
/** Depending on the handler this method may be executed on the UI thread */
@Override
public void onChange(boolean selfChange, Uri uri) {
if (mAudioManager != null && mListener != null) {
int maxVolume = mAudioManager.getStreamMaxVolume(mAudioStreamType);
int currentVolume = mAudioManager.getStreamVolume(mAudioStreamType);
if (currentVolume != mLastVolume) {
mLastVolume = currentVolume;
mListener.onAudioVolumeChanged(currentVolume, maxVolume);
}
}
}
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.volume
import android.database.ContentObserver
import android.media.AudioManager
import android.net.Uri
import android.os.Handler
class AudioVolumeContentObserver internal constructor(
handler: Handler,
audioManager: AudioManager,
audioStreamType: Int,
listener: OnAudioVolumeChangedListener
) : ContentObserver(handler) {
private val mListener: OnAudioVolumeChangedListener?
private val mAudioManager: AudioManager?
private val mAudioStreamType: Int
private var mLastVolume: Float
/** Depending on the handler this method may be executed on the UI thread */
override fun onChange(selfChange: Boolean, uri: Uri?) {
if (mAudioManager != null && mListener != null) {
val maxVolume = mAudioManager.getStreamMaxVolume(mAudioStreamType)
val currentVolume = mAudioManager.getStreamVolume(mAudioStreamType)
if (currentVolume.toFloat() != mLastVolume) {
mLastVolume = currentVolume.toFloat()
mListener.onAudioVolumeChanged(currentVolume, maxVolume)
}
}
}
init {
mAudioManager = audioManager
mAudioStreamType = audioStreamType
mListener = listener
mLastVolume = audioManager.getStreamVolume(mAudioStreamType).toFloat()
}
}

View file

@ -27,7 +27,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="56dp"
android:layout_marginLeft="56dp"
android:orientation="vertical"
android:paddingTop="8dp"
android:paddingBottom="8dp">
@ -54,9 +53,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="72dp"
android:paddingLeft="72dp"
android:paddingEnd="16dp"
android:paddingRight="16dp">
android:paddingEnd="16dp">
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
@ -166,7 +163,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="56dp"
android:layout_marginLeft="56dp"
android:orientation="vertical"
android:paddingTop="8dp"
android:paddingBottom="8dp">

View file

@ -74,7 +74,6 @@
<string name="app_shortcut_top_tracks_short">Canciones más reproducidas</string>
<string name="app_widget_big_name">Imagen completa</string>
<string name="app_widget_card_name">Tarjeta</string>
<string name="app_widget_circle_name">@cadena/círculo</string>
<string name="app_widget_classic_name">Clásico</string>
<string name="app_widget_md3_name">MD3</string>
<string name="app_widget_small_name">Pequeño</string>

View file

@ -8,6 +8,7 @@
<item>@string/horizontal_flip</item>
<item>@string/hinge</item>
<item>@string/stack</item>
<item>@string/classic</item>
</array>
<string-array name="pref_album_cover_transform_values">
@ -18,6 +19,7 @@
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
</string-array>
<string-array name="pref_lyrics_type_values">
@ -125,6 +127,7 @@
<item>Arabic</item>
<item>Basque</item>
<item>Bengali</item>
<item>Burmese</item>
<item>Catalan</item>
<item>Simplified Chinese</item>
<item>Traditional Chinese(Hong Kong)</item>
@ -135,6 +138,7 @@
<item>Dutch</item>
<item>English</item>
<item>Finnish</item>
<item>Filipino</item>
<item>French</item>
<item>German</item>
<item>Greek</item>
@ -152,15 +156,18 @@
<item>Oriya</item>
<item>Persian</item>
<item>Polish</item>
<item>Portuguese</item>
<item>Portuguese(Brazil)</item>
<item>Portuguese(Portugal)</item>
<item>Romanian</item>
<item>Russian</item>
<item>Serbian</item>
<item>Slovak</item>
<item>Spain</item>
<item>Spanish</item>
<item>Spanish(Latin America)</item>
<item>Swedish</item>
<item>Tamil</item>
<item>Telugu</item>
<item>Thai</item>
<item>Turkish</item>
<item>Ukrainian</item>
<item>Urdu</item>
@ -172,6 +179,7 @@
<item>ar-SA</item>
<item>eu-ES</item>
<item>bn-IN</item>
<item>my-MM</item>
<item>ca-ES</item>
<item>zh-CN</item>
<item>zh-HK</item>
@ -182,6 +190,7 @@
<item>nl-NL</item>
<item>en</item>
<item>fi-FI</item>
<item>fil-PH</item>
<item>fr</item>
<item>de</item>
<item>el</item>
@ -199,16 +208,19 @@
<item>or</item>
<item>fa</item>
<item>pl</item>
<item>pt</item>
<item>pt-BR</item>
<item>pt-PT</item>
<item>ro</item>
<item>ru</item>
<item>sr</item>
<item>sk</item>
<item>es</item>
<item>es-419</item>
<item>sv</item>
<item>ta</item>
<item>te</item>
<item>tr</item>
<item>th-TH</item>
<item>uk</item>
<item>ur</item>
<item>vi</item>

View file

@ -533,4 +533,5 @@
<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="bug_report_success">Bug report successful</string>
</resources>

View file

@ -48,7 +48,8 @@
android:key="wallpaper_accent"
android:layout="@layout/list_item_view_switch"
android:summary="@string/pref_summary_wallpaper_accent"
android:title="@string/pref_title_wallpaper_accent" />
android:title="@string/pref_title_wallpaper_accent"
app:isPreferenceVisible="@bool/wallpaper_accent_visible" />
<code.name.monkey.appthemehelper.common.prefs.supportv7.ATEColorPreference
android:dependency="material_you"

View file

@ -2,8 +2,8 @@
buildscript {
ext {
kotlin_version = '1.6.10'
navigation_version = '2.4.1'
kotlin_version = '1.6.20'
navigation_version = '2.4.2'
mdc_version = '1.6.0-beta01'
preference_version = '1.2.0'
appcompat_version = '1.4.1'