Added Chooser to choose what to restore
This commit is contained in:
parent
2e16994276
commit
5a41a07b76
9 changed files with 315 additions and 61 deletions
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
|
@ -262,3 +317,11 @@ fun CharSequence.sanitize(): String {
|
|||
.replace("\\", "_")
|
||||
.replace("&", "_")
|
||||
}
|
||||
|
||||
enum class BackupContent {
|
||||
SETTINGS,
|
||||
USER_IMAGES,
|
||||
CUSTOM_ARTIST_IMAGES,
|
||||
PLAYLISTS,
|
||||
QUEUE
|
||||
}
|
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>
|
|
@ -1,8 +1,83 @@
|
|||
<?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:inputType="none"/>
|
||||
</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>
|
|
@ -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,9 +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>
|
||||
<string name="disc_hint">Disc Number</string>
|
||||
</resources>
|
||||
|
|
|
@ -236,4 +236,13 @@
|
|||
<item name="colorAccent">@color/md_deep_purple_A400</item>
|
||||
<item name="colorPrimary">@color/md_deep_purple_500</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.RetroMusic.Dialog" parent="Theme.Material3.DayNight.Dialog">
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowBackground">@drawable/rounded_drawable</item>
|
||||
<item name="android:windowFrame">@null</item>
|
||||
<item name="background">@color/transparent</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue