Merge pull request #1211 from prathameshmm02/dev
Fixed some crashes and bugs
This commit is contained in:
commit
afc309a296
89 changed files with 519 additions and 419 deletions
|
@ -57,6 +57,8 @@ android {
|
||||||
abortOnError false
|
abortOnError false
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
coreLibraryDesugaringEnabled true
|
||||||
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
@ -149,6 +151,8 @@ dependencies {
|
||||||
kapt 'com.github.bumptech.glide:compiler:4.12.0'
|
kapt 'com.github.bumptech.glide:compiler:4.12.0'
|
||||||
implementation 'com.github.bumptech.glide:okhttp3-integration:4.12.0'
|
implementation 'com.github.bumptech.glide:okhttp3-integration:4.12.0'
|
||||||
|
|
||||||
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||||
|
|
||||||
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
|
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
|
||||||
|
|
||||||
implementation 'com.github.bosphere.android-fadingedgelayout:fadingedgelayout:1.0.0'
|
implementation 'com.github.bosphere.android-fadingedgelayout:fadingedgelayout:1.0.0'
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
<string name="app_name" translatable="false">Retro Music-Debug</string>
|
||||||
|
|
||||||
<bool name="md3_available">true</bool>
|
<bool name="md3_available">true</bool>
|
||||||
<bool name="allowBackup">false</bool>
|
<bool name="allowBackup">false</bool>
|
||||||
</resources>
|
</resources>
|
|
@ -135,6 +135,7 @@ const val LOCK_SCREEN = "lock_screen"
|
||||||
const val ALBUM_ARTISTS_ONLY = "album_artists_only"
|
const val ALBUM_ARTISTS_ONLY = "album_artists_only"
|
||||||
const val ALBUM_ARTIST = "album_artist"
|
const val ALBUM_ARTIST = "album_artist"
|
||||||
const val ALBUM_DETAIL_SONG_SORT_ORDER = "album_detail_song_sort_order"
|
const val ALBUM_DETAIL_SONG_SORT_ORDER = "album_detail_song_sort_order"
|
||||||
|
const val ARTIST_DETAIL_SONG_SORT_ORDER = "artist_detail_song_sort_order"
|
||||||
const val LYRICS_OPTIONS = "lyrics_tab_position"
|
const val LYRICS_OPTIONS = "lyrics_tab_position"
|
||||||
const val CHOOSE_EQUALIZER = "choose_equalizer"
|
const val CHOOSE_EQUALIZER = "choose_equalizer"
|
||||||
const val EQUALIZER = "equalizer"
|
const val EQUALIZER = "equalizer"
|
||||||
|
|
|
@ -62,7 +62,7 @@ class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
|
||||||
if (!hasPermissions()) {
|
if (!hasPermissions()) {
|
||||||
findNavController(R.id.fragment_container).navigate(R.id.permissionFragment)
|
findNavController(R.id.fragment_container).navigate(R.id.permissionFragment)
|
||||||
}
|
}
|
||||||
if (BuildConfig.VERSION_CODE > PreferenceUtil.lastVersion){
|
if (BuildConfig.VERSION_CODE > PreferenceUtil.lastVersion && !BuildConfig.DEBUG){
|
||||||
NavigationUtil.gotoWhatNews(this)
|
NavigationUtil.gotoWhatNews(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,144 +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.adapter;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.google.android.material.checkbox.MaterialCheckBox;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import code.name.monkey.appthemehelper.ThemeStore;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.model.CategoryInfo;
|
|
||||||
import code.name.monkey.retromusic.util.SwipeAndDragHelper;
|
|
||||||
|
|
||||||
public class CategoryInfoAdapter extends RecyclerView.Adapter<CategoryInfoAdapter.ViewHolder>
|
|
||||||
implements SwipeAndDragHelper.ActionCompletionContract {
|
|
||||||
|
|
||||||
private List<CategoryInfo> categoryInfos;
|
|
||||||
private final ItemTouchHelper touchHelper;
|
|
||||||
|
|
||||||
public CategoryInfoAdapter() {
|
|
||||||
SwipeAndDragHelper swipeAndDragHelper = new SwipeAndDragHelper(this);
|
|
||||||
touchHelper = new ItemTouchHelper(swipeAndDragHelper);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void attachToRecyclerView(RecyclerView recyclerView) {
|
|
||||||
touchHelper.attachToRecyclerView(recyclerView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public List<CategoryInfo> getCategoryInfos() {
|
|
||||||
return categoryInfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCategoryInfos(@NonNull List<CategoryInfo> categoryInfos) {
|
|
||||||
this.categoryInfos = categoryInfos;
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return categoryInfos.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
|
|
||||||
CategoryInfo categoryInfo = categoryInfos.get(position);
|
|
||||||
|
|
||||||
holder.checkBox.setChecked(categoryInfo.isVisible());
|
|
||||||
holder.title.setText(
|
|
||||||
holder.title.getResources().getString(categoryInfo.getCategory().getStringRes()));
|
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(
|
|
||||||
v -> {
|
|
||||||
if (!(categoryInfo.isVisible() && isLastCheckedCategory(categoryInfo))) {
|
|
||||||
categoryInfo.setVisible(!categoryInfo.isVisible());
|
|
||||||
holder.checkBox.setChecked(categoryInfo.isVisible());
|
|
||||||
} else {
|
|
||||||
Toast.makeText(
|
|
||||||
holder.itemView.getContext(),
|
|
||||||
R.string.you_have_to_select_at_least_one_category,
|
|
||||||
Toast.LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
holder.dragView.setOnTouchListener(
|
|
||||||
(view, event) -> {
|
|
||||||
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
|
||||||
touchHelper.startDrag(holder);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public CategoryInfoAdapter.ViewHolder onCreateViewHolder(
|
|
||||||
@NonNull ViewGroup parent, int viewType) {
|
|
||||||
View view =
|
|
||||||
LayoutInflater.from(parent.getContext())
|
|
||||||
.inflate(R.layout.preference_dialog_library_categories_listitem, parent, false);
|
|
||||||
return new ViewHolder(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewMoved(int oldPosition, int newPosition) {
|
|
||||||
CategoryInfo categoryInfo = categoryInfos.get(oldPosition);
|
|
||||||
categoryInfos.remove(oldPosition);
|
|
||||||
categoryInfos.add(newPosition, categoryInfo);
|
|
||||||
notifyItemMoved(oldPosition, newPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isLastCheckedCategory(CategoryInfo categoryInfo) {
|
|
||||||
if (categoryInfo.isVisible()) {
|
|
||||||
for (CategoryInfo c : categoryInfos) {
|
|
||||||
if (c != categoryInfo && c.isVisible()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
private final MaterialCheckBox checkBox;
|
|
||||||
private final View dragView;
|
|
||||||
private final TextView title;
|
|
||||||
|
|
||||||
ViewHolder(View view) {
|
|
||||||
super(view);
|
|
||||||
checkBox = view.findViewById(R.id.checkbox);
|
|
||||||
checkBox.setButtonTintList(
|
|
||||||
ColorStateList.valueOf(ThemeStore.Companion.accentColor(checkBox.getContext())));
|
|
||||||
title = view.findViewById(R.id.title);
|
|
||||||
dragView = view.findViewById(R.id.drag_view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* 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.adapter
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.databinding.PreferenceDialogLibraryCategoriesListitemBinding
|
||||||
|
import code.name.monkey.retromusic.model.CategoryInfo
|
||||||
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import code.name.monkey.retromusic.util.SwipeAndDragHelper
|
||||||
|
import code.name.monkey.retromusic.util.SwipeAndDragHelper.ActionCompletionContract
|
||||||
|
|
||||||
|
class CategoryInfoAdapter : RecyclerView.Adapter<CategoryInfoAdapter.ViewHolder>(),
|
||||||
|
ActionCompletionContract {
|
||||||
|
var categoryInfos: MutableList<CategoryInfo> =
|
||||||
|
PreferenceUtil.libraryCategory.toMutableList()
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
private val touchHelper: ItemTouchHelper
|
||||||
|
fun attachToRecyclerView(recyclerView: RecyclerView?) {
|
||||||
|
touchHelper.attachToRecyclerView(recyclerView)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return categoryInfos.size
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val categoryInfo = categoryInfos[position]
|
||||||
|
holder.binding.checkbox.isChecked = categoryInfo.visible
|
||||||
|
holder.binding.title.text =
|
||||||
|
holder.binding.title.resources.getString(categoryInfo.category.stringRes)
|
||||||
|
holder.itemView.setOnClickListener {
|
||||||
|
if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) {
|
||||||
|
categoryInfo.visible = !categoryInfo.visible
|
||||||
|
holder.binding.checkbox.isChecked = categoryInfo.visible
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
holder.itemView.context,
|
||||||
|
R.string.you_have_to_select_at_least_one_category,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
holder.binding.dragView.setOnTouchListener { _: View?, event: MotionEvent ->
|
||||||
|
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||||
|
touchHelper.startDrag(holder)
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(
|
||||||
|
parent: ViewGroup, viewType: Int
|
||||||
|
): ViewHolder {
|
||||||
|
return ViewHolder(
|
||||||
|
PreferenceDialogLibraryCategoriesListitemBinding.inflate(
|
||||||
|
LayoutInflater.from(
|
||||||
|
parent.context
|
||||||
|
), parent, false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewMoved(oldPosition: Int, newPosition: Int) {
|
||||||
|
val categoryInfo = categoryInfos[oldPosition]
|
||||||
|
categoryInfos.removeAt(oldPosition)
|
||||||
|
categoryInfos.add(newPosition, categoryInfo)
|
||||||
|
notifyItemMoved(oldPosition, newPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isLastCheckedCategory(categoryInfo: CategoryInfo): Boolean {
|
||||||
|
if (categoryInfo.visible) {
|
||||||
|
for (c in categoryInfos) {
|
||||||
|
if (c !== categoryInfo && c.visible) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(val binding: PreferenceDialogLibraryCategoriesListitemBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
binding.checkbox.buttonTintList =
|
||||||
|
ColorStateList.valueOf(accentColor(binding.checkbox.context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val swipeAndDragHelper = SwipeAndDragHelper(this)
|
||||||
|
touchHelper = ItemTouchHelper(swipeAndDragHelper)
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@
|
||||||
*/
|
*/
|
||||||
package code.name.monkey.retromusic.adapter
|
package code.name.monkey.retromusic.adapter
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -21,7 +22,7 @@ import android.view.ViewOutlineProvider
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
|
import code.name.monkey.retromusic.databinding.ItemGenreBinding
|
||||||
import code.name.monkey.retromusic.glide.GlideApp
|
import code.name.monkey.retromusic.glide.GlideApp
|
||||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
||||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||||
|
@ -38,7 +39,6 @@ import java.util.*
|
||||||
class GenreAdapter(
|
class GenreAdapter(
|
||||||
private val activity: FragmentActivity,
|
private val activity: FragmentActivity,
|
||||||
var dataSet: List<Genre>,
|
var dataSet: List<Genre>,
|
||||||
private val mItemLayoutRes: Int,
|
|
||||||
private val listener: IGenreClickListener
|
private val listener: IGenreClickListener
|
||||||
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
|
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
@ -51,13 +51,13 @@ class GenreAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
|
return ViewHolder(ItemGenreBinding.inflate(LayoutInflater.from(activity), parent, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val genre = dataSet[position]
|
val genre = dataSet[position]
|
||||||
holder.title?.text = genre.name
|
holder.binding.title.text = genre.name
|
||||||
holder.text?.text = String.format(
|
holder.binding.text.text = String.format(
|
||||||
Locale.getDefault(),
|
Locale.getDefault(),
|
||||||
"%d %s",
|
"%d %s",
|
||||||
genre.songCount,
|
genre.songCount,
|
||||||
|
@ -72,33 +72,39 @@ class GenreAdapter(
|
||||||
.asBitmapPalette()
|
.asBitmapPalette()
|
||||||
.load(RetroGlideExtension.getSongModel(genreSong))
|
.load(RetroGlideExtension.getSongModel(genreSong))
|
||||||
.songCoverOptions(genreSong)
|
.songCoverOptions(genreSong)
|
||||||
.into(object : RetroMusicColoredTarget(holder.image!!) {
|
.into(object : RetroMusicColoredTarget(holder.binding.image) {
|
||||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||||
setColors(holder, colors)
|
setColors(holder, colors)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Just for a bit of shadow around image
|
// Just for a bit of shadow around image
|
||||||
holder.image?.outlineProvider = ViewOutlineProvider.BOUNDS
|
holder.binding.image.outlineProvider = ViewOutlineProvider.BOUNDS
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setColors(holder: ViewHolder, color: MediaNotificationProcessor) {
|
private fun setColors(holder: ViewHolder, color: MediaNotificationProcessor) {
|
||||||
holder.imageContainerCard?.setCardBackgroundColor(color.backgroundColor)
|
holder.binding.imageContainerCard.setCardBackgroundColor(color.backgroundColor)
|
||||||
holder.title?.setTextColor(color.primaryTextColor)
|
holder.binding.title.setTextColor(color.primaryTextColor)
|
||||||
holder.text?.setTextColor(color.secondaryTextColor)
|
holder.binding.text.setTextColor(color.secondaryTextColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return dataSet.size
|
return dataSet.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
fun swapDataSet(list: List<Genre>) {
|
fun swapDataSet(list: List<Genre>) {
|
||||||
dataSet = list
|
dataSet = list
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
inner class ViewHolder(val binding: ItemGenreBinding) : RecyclerView.ViewHolder(binding.root),
|
||||||
|
View.OnClickListener {
|
||||||
override fun onClick(v: View?) {
|
override fun onClick(v: View?) {
|
||||||
listener.onClickGenre(dataSet[layoutPosition], itemView)
|
listener.onClickGenre(dataSet[layoutPosition], itemView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
itemView.setOnClickListener(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,7 +248,6 @@ class HomeAdapter(
|
||||||
val genreAdapter = GenreAdapter(
|
val genreAdapter = GenreAdapter(
|
||||||
activity,
|
activity,
|
||||||
home.arrayList as List<Genre>,
|
home.arrayList as List<Genre>,
|
||||||
R.layout.item_grid_genre,
|
|
||||||
this@HomeAdapter
|
this@HomeAdapter
|
||||||
)
|
)
|
||||||
recyclerView.apply {
|
recyclerView.apply {
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
package code.name.monkey.retromusic.adapter.backup
|
package code.name.monkey.retromusic.adapter.backup
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.widget.AppCompatImageView
|
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.databinding.ItemListBackupBinding
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,27 +20,27 @@ class BackupAdapter(
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
return ViewHolder(
|
return ViewHolder(
|
||||||
LayoutInflater.from(activity).inflate(R.layout.item_list_card, parent, false)
|
ItemListBackupBinding.inflate(LayoutInflater.from(activity), parent, false)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
holder.title.text = dataSet[position].nameWithoutExtension
|
holder.binding.title.text = dataSet[position].nameWithoutExtension
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = dataSet.size
|
override fun getItemCount(): Int = dataSet.size
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
fun swapDataset(dataSet: List<File>) {
|
fun swapDataset(dataSet: List<File>) {
|
||||||
this.dataSet = ArrayList(dataSet)
|
this.dataSet = ArrayList(dataSet)
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
inner class ViewHolder(val binding: ItemListBackupBinding) :
|
||||||
val title: TextView = itemView.findViewById(R.id.title)
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
val menu: AppCompatImageView = itemView.findViewById(R.id.menu)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
menu.setOnClickListener { view ->
|
binding.menu.setOnClickListener { view ->
|
||||||
val popupMenu = PopupMenu(activity, view)
|
val popupMenu = PopupMenu(activity, view)
|
||||||
popupMenu.inflate(R.menu.menu_backup)
|
popupMenu.inflate(R.menu.menu_backup)
|
||||||
popupMenu.setOnMenuItemClickListener { menuItem ->
|
popupMenu.setOnMenuItemClickListener { menuItem ->
|
||||||
|
|
|
@ -255,12 +255,14 @@ class LibraryViewModel(
|
||||||
}
|
}
|
||||||
repository.insertSongs(songEntities)
|
repository.insertSongs(songEntities)
|
||||||
} else {
|
} else {
|
||||||
|
if (playlist != Playlist.empty){
|
||||||
val playListId = createPlaylist(PlaylistEntity(playlistName = playlist.name))
|
val playListId = createPlaylist(PlaylistEntity(playlistName = playlist.name))
|
||||||
val songEntities = playlist.getSongs().map {
|
val songEntities = playlist.getSongs().map {
|
||||||
it.toSongEntity(playListId)
|
it.toSongEntity(playListId)
|
||||||
}
|
}
|
||||||
repository.insertSongs(songEntities)
|
repository.insertSongs(songEntities)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
forceReload(Playlists)
|
forceReload(Playlists)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,9 @@ import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.view.Menu
|
import android.view.*
|
||||||
import android.view.MenuInflater
|
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.View
|
|
||||||
import androidx.activity.addCallback
|
import androidx.activity.addCallback
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
|
@ -32,6 +30,7 @@ import code.name.monkey.retromusic.glide.GlideApp
|
||||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
||||||
import code.name.monkey.retromusic.glide.SingleColorTarget
|
import code.name.monkey.retromusic.glide.SingleColorTarget
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
|
import code.name.monkey.retromusic.helper.SortOrder
|
||||||
import code.name.monkey.retromusic.interfaces.IAlbumClickListener
|
import code.name.monkey.retromusic.interfaces.IAlbumClickListener
|
||||||
import code.name.monkey.retromusic.interfaces.ICabCallback
|
import code.name.monkey.retromusic.interfaces.ICabCallback
|
||||||
import code.name.monkey.retromusic.interfaces.ICabHolder
|
import code.name.monkey.retromusic.interfaces.ICabHolder
|
||||||
|
@ -39,10 +38,7 @@ import code.name.monkey.retromusic.model.Artist
|
||||||
import code.name.monkey.retromusic.network.Result
|
import code.name.monkey.retromusic.network.Result
|
||||||
import code.name.monkey.retromusic.network.model.LastFmArtist
|
import code.name.monkey.retromusic.network.model.LastFmArtist
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import code.name.monkey.retromusic.util.CustomArtistImageUtil
|
import code.name.monkey.retromusic.util.*
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
|
||||||
import code.name.monkey.retromusic.util.RetroColorUtil
|
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
|
||||||
import com.afollestad.materialcab.attached.AttachedCab
|
import com.afollestad.materialcab.attached.AttachedCab
|
||||||
import com.afollestad.materialcab.attached.destroy
|
import com.afollestad.materialcab.attached.destroy
|
||||||
import com.afollestad.materialcab.attached.isActive
|
import com.afollestad.materialcab.attached.isActive
|
||||||
|
@ -71,6 +67,9 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
|
||||||
private var lang: String? = null
|
private var lang: String? = null
|
||||||
private var biography: Spanned? = null
|
private var biography: Spanned? = null
|
||||||
|
|
||||||
|
private val savedSongSortOrder: String
|
||||||
|
get() = PreferenceUtil.artistDetailSongSortOrder
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
sharedElementEnterTransition = MaterialContainerTransform().apply {
|
sharedElementEnterTransition = MaterialContainerTransform().apply {
|
||||||
|
@ -101,7 +100,7 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
|
|
||||||
binding.fragmentArtistContent.playAction.apply {
|
binding.fragmentArtistContent.playAction.apply {
|
||||||
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
|
setOnClickListener { MusicPlayerRemote.openQueue(artist.sortedSongs, 0, true) }
|
||||||
}
|
}
|
||||||
binding.fragmentArtistContent.shuffleAction.apply {
|
binding.fragmentArtistContent.shuffleAction.apply {
|
||||||
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
|
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
|
||||||
|
@ -121,6 +120,7 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
|
||||||
requireActivity().onBackPressed()
|
requireActivity().onBackPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setupSongSortButton()
|
||||||
binding.appBarLayout?.statusBarForeground =
|
binding.appBarLayout?.statusBarForeground =
|
||||||
MaterialShapeDrawable.createWithElevationOverlay(requireContext())
|
MaterialShapeDrawable.createWithElevationOverlay(requireContext())
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
|
||||||
)
|
)
|
||||||
binding.fragmentArtistContent.songTitle.text = songText
|
binding.fragmentArtistContent.songTitle.text = songText
|
||||||
binding.fragmentArtistContent.albumTitle.text = albumText
|
binding.fragmentArtistContent.albumTitle.text = albumText
|
||||||
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
|
songAdapter.swapDataSet(artist.sortedSongs)
|
||||||
albumAdapter.swapDataSet(artist.albums)
|
albumAdapter.swapDataSet(artist.albums)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +289,53 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupSongSortButton() {
|
||||||
|
binding.fragmentArtistContent.songSortOrder.setOnClickListener {
|
||||||
|
PopupMenu(requireContext(), binding.fragmentArtistContent.songSortOrder).apply {
|
||||||
|
inflate(R.menu.menu_artist_song_sort_order)
|
||||||
|
setUpSortOrderMenu(menu)
|
||||||
|
setOnMenuItemClickListener { menuItem ->
|
||||||
|
val sortOrder = when (menuItem.itemId) {
|
||||||
|
R.id.action_sort_order_title -> SortOrder.ArtistSongSortOrder.SONG_A_Z
|
||||||
|
R.id.action_sort_order_title_desc -> SortOrder.ArtistSongSortOrder.SONG_Z_A
|
||||||
|
R.id.action_sort_order_album -> SortOrder.ArtistSongSortOrder.SONG_ALBUM
|
||||||
|
R.id.action_sort_order_year -> SortOrder.ArtistSongSortOrder.SONG_YEAR
|
||||||
|
R.id.action_sort_order_song_duration -> SortOrder.ArtistSongSortOrder.SONG_DURATION
|
||||||
|
else -> {
|
||||||
|
throw IllegalArgumentException("invalid ${menuItem.title}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menuItem.isChecked = true
|
||||||
|
setSaveSortOrder(sortOrder)
|
||||||
|
return@setOnMenuItemClickListener true
|
||||||
|
}
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSaveSortOrder(sortOrder: String) {
|
||||||
|
PreferenceUtil.artistDetailSongSortOrder = sortOrder
|
||||||
|
songAdapter.swapDataSet(artist.sortedSongs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpSortOrderMenu(sortOrder: Menu) {
|
||||||
|
when (savedSongSortOrder) {
|
||||||
|
SortOrder.ArtistSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title).isChecked = true
|
||||||
|
SortOrder.ArtistSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc).isChecked = true
|
||||||
|
SortOrder.ArtistSongSortOrder.SONG_ALBUM ->
|
||||||
|
sortOrder.findItem(R.id.action_sort_order_album).isChecked = true
|
||||||
|
SortOrder.ArtistSongSortOrder.SONG_YEAR ->
|
||||||
|
sortOrder.findItem(R.id.action_sort_order_year).isChecked = true
|
||||||
|
SortOrder.ArtistSongSortOrder.SONG_DURATION ->
|
||||||
|
sortOrder.findItem(R.id.action_sort_order_song_duration).isChecked = true
|
||||||
|
else-> {
|
||||||
|
throw IllegalArgumentException("invalid $savedSongSortOrder")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
when (requestCode) {
|
when (requestCode) {
|
||||||
|
|
|
@ -17,6 +17,8 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.backup.BackupAdapter
|
import code.name.monkey.retromusic.adapter.backup.BackupAdapter
|
||||||
import code.name.monkey.retromusic.databinding.FragmentBackupBinding
|
import code.name.monkey.retromusic.databinding.FragmentBackupBinding
|
||||||
|
import code.name.monkey.retromusic.extensions.accentColor
|
||||||
|
import code.name.monkey.retromusic.extensions.accentOutlineColor
|
||||||
import code.name.monkey.retromusic.helper.BackupHelper
|
import code.name.monkey.retromusic.helper.BackupHelper
|
||||||
import code.name.monkey.retromusic.helper.sanitize
|
import code.name.monkey.retromusic.helper.sanitize
|
||||||
import code.name.monkey.retromusic.util.BackupUtil
|
import code.name.monkey.retromusic.util.BackupUtil
|
||||||
|
@ -45,7 +47,7 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
||||||
else
|
else
|
||||||
backupAdapter?.swapDataset(listOf())
|
backupAdapter?.swapDataset(listOf())
|
||||||
}
|
}
|
||||||
backupViewModel.loadBackups()
|
backupViewModel.loadBackups(requireContext())
|
||||||
val openFilePicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
val openFilePicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
it?.let {
|
it?.let {
|
||||||
|
@ -55,6 +57,8 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
binding.createBackup.accentOutlineColor()
|
||||||
|
binding.restoreBackup.accentColor()
|
||||||
binding.createBackup.setOnClickListener {
|
binding.createBackup.setOnClickListener {
|
||||||
showCreateBackupDialog()
|
showCreateBackupDialog()
|
||||||
}
|
}
|
||||||
|
@ -91,11 +95,11 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
||||||
MaterialDialog(requireContext()).show {
|
MaterialDialog(requireContext()).show {
|
||||||
cornerRadius(res = R.dimen.m3_card_corner_radius)
|
cornerRadius(res = R.dimen.m3_card_corner_radius)
|
||||||
title(res = R.string.action_rename)
|
title(res = R.string.action_rename)
|
||||||
input(prefill = System.currentTimeMillis().toString()) { _, text ->
|
input(prefill = BackupHelper.getTimeStamp()) { _, text ->
|
||||||
// Text submitted with the action button
|
// Text submitted with the action button
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
BackupHelper.createBackup(requireContext(), text.sanitize())
|
BackupHelper.createBackup(requireContext(), text.sanitize())
|
||||||
backupViewModel.loadBackups()
|
backupViewModel.loadBackups(requireContext())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
positiveButton(android.R.string.ok)
|
positiveButton(android.R.string.ok)
|
||||||
|
@ -125,7 +129,7 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
backupViewModel.loadBackups()
|
backupViewModel.loadBackups(requireContext())
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_share -> {
|
R.id.action_share -> {
|
||||||
|
@ -143,10 +147,10 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
||||||
input(prefill = file.nameWithoutExtension) { _, text ->
|
input(prefill = file.nameWithoutExtension) { _, text ->
|
||||||
// Text submitted with the action button
|
// Text submitted with the action button
|
||||||
val renamedFile =
|
val renamedFile =
|
||||||
File(file.parent + File.separator + text + BackupHelper.APPEND_EXTENSION)
|
File(file.parent, "$text${BackupHelper.APPEND_EXTENSION}")
|
||||||
if (!renamedFile.exists()) {
|
if (!renamedFile.exists()) {
|
||||||
file.renameTo(renamedFile)
|
file.renameTo(renamedFile)
|
||||||
backupViewModel.loadBackups()
|
backupViewModel.loadBackups(requireContext())
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package code.name.monkey.retromusic.fragments.backup
|
package code.name.monkey.retromusic.fragments.backup
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
@ -19,8 +20,8 @@ class BackupViewModel : ViewModel() {
|
||||||
private val backupsMutableLiveData = MutableLiveData<List<File>>()
|
private val backupsMutableLiveData = MutableLiveData<List<File>>()
|
||||||
val backupsLiveData: LiveData<List<File>> = backupsMutableLiveData
|
val backupsLiveData: LiveData<List<File>> = backupsMutableLiveData
|
||||||
|
|
||||||
fun loadBackups() {
|
fun loadBackups(context: Context) {
|
||||||
File(BackupHelper.backupRootPath).listFiles { _, name ->
|
BackupHelper.getBackupRoot(context).listFiles { _, name ->
|
||||||
return@listFiles name.endsWith(BackupHelper.BACKUP_EXTENSION)
|
return@listFiles name.endsWith(BackupHelper.BACKUP_EXTENSION)
|
||||||
}?.toList()?.let {
|
}?.toList()?.let {
|
||||||
backupsMutableLiveData.value = it
|
backupsMutableLiveData.value = it
|
||||||
|
@ -29,6 +30,8 @@ class BackupViewModel : ViewModel() {
|
||||||
|
|
||||||
suspend fun restoreBackup(activity: Activity, inputStream: InputStream?, contents: List<BackupContent>) {
|
suspend fun restoreBackup(activity: Activity, inputStream: InputStream?, contents: List<BackupContent>) {
|
||||||
BackupHelper.restoreBackup(activity, inputStream, contents)
|
BackupHelper.restoreBackup(activity, inputStream, contents)
|
||||||
|
if (contents.contains(BackupContent.SETTINGS) or contents.contains(BackupContent.CUSTOM_ARTIST_IMAGES)) {
|
||||||
|
// We have to restart App when Preferences i.e. Settings or Artist Images are to be restored
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val intent = Intent(
|
val intent = Intent(
|
||||||
activity,
|
activity,
|
||||||
|
@ -39,3 +42,4 @@ class BackupViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -3,9 +3,11 @@ package code.name.monkey.retromusic.fragments.backup
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.retromusic.databinding.ActivityRestoreBinding
|
import code.name.monkey.retromusic.databinding.ActivityRestoreBinding
|
||||||
import code.name.monkey.retromusic.helper.BackupContent
|
import code.name.monkey.retromusic.helper.BackupContent
|
||||||
|
@ -27,6 +29,7 @@ class RestoreActivity : AppCompatActivity() {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityRestoreBinding.inflate(layoutInflater)
|
binding = ActivityRestoreBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
setWidth()
|
||||||
val backupUri = intent?.data
|
val backupUri = intent?.data
|
||||||
binding.backupName.setText(getFileName(backupUri))
|
binding.backupName.setText(getFileName(backupUri))
|
||||||
binding.cancelButton.setOnClickListener {
|
binding.cancelButton.setOnClickListener {
|
||||||
|
@ -35,7 +38,6 @@ class RestoreActivity : AppCompatActivity() {
|
||||||
binding.restoreButton.setOnClickListener {
|
binding.restoreButton.setOnClickListener {
|
||||||
val backupContents = mutableListOf<BackupContent>()
|
val backupContents = mutableListOf<BackupContent>()
|
||||||
if (binding.checkSettings.isChecked) backupContents.add(SETTINGS)
|
if (binding.checkSettings.isChecked) backupContents.add(SETTINGS)
|
||||||
if (binding.checkQueue.isChecked) backupContents.add(QUEUE)
|
|
||||||
if (binding.checkDatabases.isChecked) backupContents.add(PLAYLISTS)
|
if (binding.checkDatabases.isChecked) backupContents.add(PLAYLISTS)
|
||||||
if (binding.checkArtistImages.isChecked) backupContents.add(CUSTOM_ARTIST_IMAGES)
|
if (binding.checkArtistImages.isChecked) backupContents.add(CUSTOM_ARTIST_IMAGES)
|
||||||
if (binding.checkUserImages.isChecked) backupContents.add(USER_IMAGES)
|
if (binding.checkUserImages.isChecked) backupContents.add(USER_IMAGES)
|
||||||
|
@ -67,17 +69,13 @@ class RestoreActivity : AppCompatActivity() {
|
||||||
return uri.lastPathSegment
|
return uri.lastPathSegment
|
||||||
}
|
}
|
||||||
"content" -> {
|
"content" -> {
|
||||||
val proj = arrayOf(MediaStore.Images.Media.TITLE)
|
val proj = arrayOf(MediaStore.Files.FileColumns.DISPLAY_NAME)
|
||||||
contentResolver.query(
|
contentResolver.query(
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
|
uri, proj, null, null, null
|
||||||
MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
|
|
||||||
} else {
|
|
||||||
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
|
||||||
}, proj, null, null, null
|
|
||||||
)?.use { cursor ->
|
)?.use { cursor ->
|
||||||
if (cursor.count != 0) {
|
if (cursor.count != 0) {
|
||||||
val columnIndex: Int =
|
val columnIndex: Int =
|
||||||
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.TITLE)
|
cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME)
|
||||||
cursor.moveToFirst()
|
cursor.moveToFirst()
|
||||||
return cursor.getString(columnIndex)
|
return cursor.getString(columnIndex)
|
||||||
}
|
}
|
||||||
|
@ -86,4 +84,9 @@ class RestoreActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
return "Backup"
|
return "Backup"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setWidth() {
|
||||||
|
val width = resources.displayMetrics.widthPixels * 0.8
|
||||||
|
binding.root.updateLayoutParams<ViewGroup.LayoutParams> { this.width = width.toInt() }
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -164,7 +164,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
|
||||||
if (itemCount > 0 && MusicPlayerRemote.playingQueue.isNotEmpty()) {
|
if (itemCount > 0 && MusicPlayerRemote.playingQueue.isNotEmpty()) {
|
||||||
binding.recyclerView.updatePadding(bottom = dip(R.dimen.mini_player_height_expanded))
|
binding.recyclerView.updatePadding(bottom = dip(R.dimen.mini_player_height_expanded))
|
||||||
} else {
|
} else {
|
||||||
binding.recyclerView.updatePadding(bottom = dip(R.dimen.mini_player_height))
|
binding.recyclerView.updatePadding(bottom = dip(R.dimen.bottom_nav_height))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(),
|
||||||
|
|
||||||
override fun createAdapter(): GenreAdapter {
|
override fun createAdapter(): GenreAdapter {
|
||||||
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
|
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
|
||||||
return GenreAdapter(requireActivity(), dataSet, R.layout.item_genre, this)
|
return GenreAdapter(requireActivity(), dataSet, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
|
|
@ -29,6 +29,7 @@ import android.widget.Toast
|
||||||
import androidx.core.view.doOnPreDraw
|
import androidx.core.view.doOnPreDraw
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import code.name.monkey.retromusic.Constants.USER_BANNER
|
import code.name.monkey.retromusic.Constants.USER_BANNER
|
||||||
import code.name.monkey.retromusic.Constants.USER_PROFILE
|
import code.name.monkey.retromusic.Constants.USER_PROFILE
|
||||||
|
@ -50,7 +51,6 @@ import com.bumptech.glide.request.target.Target
|
||||||
import com.github.dhaval2404.imagepicker.ImagePicker
|
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||||
import com.github.dhaval2404.imagepicker.constant.ImageProvider
|
import com.github.dhaval2404.imagepicker.constant.ImageProvider
|
||||||
import com.google.android.material.transition.MaterialContainerTransform
|
import com.google.android.material.transition.MaterialContainerTransform
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
@ -202,15 +202,15 @@ class UserInfoFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveImage(bitmap: Bitmap, fileName: String) {
|
private fun saveImage(bitmap: Bitmap, fileName: String) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val appDir = requireContext().filesDir
|
val appDir = requireContext().filesDir
|
||||||
val file = File(appDir, fileName)
|
val file = File(appDir, fileName)
|
||||||
var successful = false
|
var successful = false
|
||||||
runCatching {
|
runCatching {
|
||||||
val os = BufferedOutputStream(FileOutputStream(file))
|
BufferedOutputStream(FileOutputStream(file)).use {
|
||||||
successful = ImageUtil.resizeBitmap(bitmap, 2048)
|
successful = ImageUtil.resizeBitmap(bitmap, 2048)
|
||||||
.compress(Bitmap.CompressFormat.WEBP, 100, os)
|
.compress(Bitmap.CompressFormat.WEBP, 100, it)
|
||||||
withContext(Dispatchers.IO) { os.close() }
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
it.printStackTrace()
|
it.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,13 @@
|
||||||
*/
|
*/
|
||||||
package code.name.monkey.retromusic.fragments.player
|
package code.name.monkey.retromusic.fragments.player
|
||||||
|
|
||||||
|
import android.animation.ObjectAnimator
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.animation.doOnEnd
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
@ -34,7 +35,6 @@ import code.name.monkey.retromusic.extensions.isColorLight
|
||||||
import code.name.monkey.retromusic.extensions.surfaceColor
|
import code.name.monkey.retromusic.extensions.surfaceColor
|
||||||
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
|
||||||
import code.name.monkey.retromusic.fragments.base.goToLyrics
|
import code.name.monkey.retromusic.fragments.base.goToLyrics
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
||||||
|
@ -223,8 +223,13 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showLyrics(visible: Boolean) {
|
private fun showLyrics(visible: Boolean) {
|
||||||
|
ObjectAnimator.ofFloat(lrcView, View.ALPHA, if (visible) 1F else 0F).apply {
|
||||||
|
doOnEnd {
|
||||||
lrcView.isVisible = visible
|
lrcView.isVisible = visible
|
||||||
viewPager.isInvisible = visible
|
}
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
ObjectAnimator.ofFloat(viewPager, View.ALPHA, if (visible) 0F else 1F).start()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maybeInitLyrics() {
|
private fun maybeInitLyrics() {
|
||||||
|
@ -233,8 +238,6 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
if (lyricViewNpsList.contains(nps) && PreferenceUtil.showLyrics) {
|
if (lyricViewNpsList.contains(nps) && PreferenceUtil.showLyrics) {
|
||||||
showLyrics(true)
|
showLyrics(true)
|
||||||
progressViewUpdateHelper?.start()
|
progressViewUpdateHelper?.start()
|
||||||
lrcView.animate().alpha(1f).duration =
|
|
||||||
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
|
|
||||||
} else {
|
} else {
|
||||||
showLyrics(false)
|
showLyrics(false)
|
||||||
progressViewUpdateHelper?.stop()
|
progressViewUpdateHelper?.stop()
|
||||||
|
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.fragments.player.color
|
||||||
|
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.animation.doOnEnd
|
import androidx.core.animation.doOnEnd
|
||||||
|
@ -60,12 +61,14 @@ class ColorFragment : AbsPlayerFragment(R.layout.fragment_color_player) {
|
||||||
_binding?.root?.setBackgroundColor(color.backgroundColor)
|
_binding?.root?.setBackgroundColor(color.backgroundColor)
|
||||||
}
|
}
|
||||||
animator.start()
|
animator.start()
|
||||||
|
Handler().post {
|
||||||
ToolbarContentTintHelper.colorizeToolbar(
|
ToolbarContentTintHelper.colorizeToolbar(
|
||||||
binding.playerToolbar,
|
binding.playerToolbar,
|
||||||
color.secondaryTextColor,
|
color.secondaryTextColor,
|
||||||
requireActivity()
|
requireActivity()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onFavoriteToggled() {
|
override fun onFavoriteToggled() {
|
||||||
toggleFavorite(MusicPlayerRemote.currentSong)
|
toggleFavorite(MusicPlayerRemote.currentSong)
|
||||||
|
|
|
@ -28,9 +28,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.*
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import androidx.core.view.updatePadding
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -65,8 +63,7 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_player),
|
class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_player),
|
||||||
MusicProgressViewUpdateHelper.Callback,
|
MusicProgressViewUpdateHelper.Callback, PopupMenu.OnMenuItemClickListener {
|
||||||
View.OnLayoutChangeListener, PopupMenu.OnMenuItemClickListener {
|
|
||||||
private var lastColor: Int = 0
|
private var lastColor: Int = 0
|
||||||
private var lastPlaybackControlsColor: Int = 0
|
private var lastPlaybackControlsColor: Int = 0
|
||||||
private var lastDisabledPlaybackControlsColor: Int = 0
|
private var lastDisabledPlaybackControlsColor: Int = 0
|
||||||
|
@ -89,8 +86,8 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
binding.playerQueueSheet.updatePadding(
|
binding.playerQueueSheet.updatePadding(
|
||||||
top = (slideOffset * binding.statusBarLayout.statusBar.height).toInt()
|
top = (slideOffset * binding.statusBarLayout.statusBar.height).toInt()
|
||||||
)
|
)
|
||||||
binding.recyclerView.updatePadding(
|
binding.container.updatePadding(
|
||||||
top = ((1 - slideOffset) * navBarHeight).toInt()
|
bottom = ((1 - slideOffset) * navBarHeight).toInt()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,9 +126,9 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupPanel() {
|
private fun setupPanel() {
|
||||||
if (!ViewCompat.isLaidOut(binding.colorBackground) || binding.colorBackground.isLayoutRequested) {
|
binding.colorBackground.doOnLayout {
|
||||||
binding.colorBackground.addOnLayoutChangeListener(this)
|
val panel = getQueuePanel()
|
||||||
return
|
panel.peekHeight = binding.container.height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,9 +155,9 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
}
|
}
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(
|
ViewCompat.setOnApplyWindowInsetsListener(
|
||||||
(binding.container)
|
(binding.container)
|
||||||
) { _: View, insets: WindowInsetsCompat ->
|
) { v: View, insets: WindowInsetsCompat ->
|
||||||
navBarHeight = insets.safeGetBottomInsets()
|
navBarHeight = insets.safeGetBottomInsets()
|
||||||
binding.recyclerView.updatePadding(top = navBarHeight)
|
v.updatePadding(bottom = navBarHeight)
|
||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
binding.playbackControlsFragment.root.drawAboveSystemBars()
|
binding.playbackControlsFragment.root.drawAboveSystemBars()
|
||||||
|
@ -461,21 +458,6 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLayoutChange(
|
|
||||||
v: View?,
|
|
||||||
left: Int,
|
|
||||||
top: Int,
|
|
||||||
right: Int,
|
|
||||||
bottom: Int,
|
|
||||||
oldLeft: Int,
|
|
||||||
oldTop: Int,
|
|
||||||
oldRight: Int,
|
|
||||||
oldBottom: Int
|
|
||||||
) {
|
|
||||||
val panel = getQueuePanel()
|
|
||||||
panel.peekHeight = binding.container.height + navBarHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
playingQueueAdapter = PlayingQueueAdapter(
|
playingQueueAdapter = PlayingQueueAdapter(
|
||||||
requireActivity() as AppCompatActivity,
|
requireActivity() as AppCompatActivity,
|
||||||
|
|
|
@ -2,39 +2,49 @@ package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.util.Log
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import code.name.monkey.retromusic.App
|
import code.name.monkey.retromusic.App
|
||||||
import code.name.monkey.retromusic.BuildConfig
|
import code.name.monkey.retromusic.BuildConfig
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
|
import code.name.monkey.retromusic.db.toSongEntity
|
||||||
import code.name.monkey.retromusic.helper.BackupContent.*
|
import code.name.monkey.retromusic.helper.BackupContent.*
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import code.name.monkey.retromusic.repository.Repository
|
||||||
|
import code.name.monkey.retromusic.repository.SongRepository
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.koin.core.component.KoinComponent
|
||||||
|
import org.koin.core.component.inject
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
import java.util.zip.ZipOutputStream
|
import java.util.zip.ZipOutputStream
|
||||||
|
|
||||||
object BackupHelper {
|
object BackupHelper : KoinComponent {
|
||||||
|
private val repository by inject<Repository>()
|
||||||
|
private val songRepository by inject<SongRepository>()
|
||||||
|
|
||||||
suspend fun createBackup(context: Context, name: String) {
|
suspend fun createBackup(context: Context, name: String) {
|
||||||
val backupFile =
|
val backupFile =
|
||||||
File(backupRootPath + File.separator + name + APPEND_EXTENSION)
|
File(getBackupRoot(context), name + APPEND_EXTENSION)
|
||||||
if (backupFile.parentFile?.exists() != true) {
|
if (backupFile.parentFile?.exists() != true) {
|
||||||
backupFile.parentFile?.mkdirs()
|
backupFile.parentFile?.mkdirs()
|
||||||
}
|
}
|
||||||
val zipItems = mutableListOf<ZipItem>()
|
val zipItems = mutableListOf<ZipItem>()
|
||||||
zipItems.addAll(getDatabaseZipItems(context))
|
zipItems.addAll(getPlaylistZipItems(context))
|
||||||
zipItems.addAll(getSettingsZipItems(context))
|
zipItems.addAll(getSettingsZipItems(context))
|
||||||
getUserImageZipItems(context)?.let { zipItems.addAll(it) }
|
getUserImageZipItems(context)?.let { zipItems.addAll(it) }
|
||||||
zipItems.addAll(getCustomArtistZipItems(context))
|
zipItems.addAll(getCustomArtistZipItems(context))
|
||||||
zipItems.addAll(getQueueZipItems(context))
|
|
||||||
zipAll(zipItems, backupFile)
|
zipAll(zipItems, backupFile)
|
||||||
|
// Clean Cache Playlist Directory
|
||||||
|
File(context.filesDir, PLAYLISTS_PATH).deleteRecursively()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun zipAll(zipItems: List<ZipItem>, backupFile: File) =
|
private suspend fun zipAll(zipItems: List<ZipItem>, backupFile: File) =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
kotlin.runCatching {
|
runCatching {
|
||||||
ZipOutputStream(BufferedOutputStream(FileOutputStream(backupFile))).use { out ->
|
ZipOutputStream(BufferedOutputStream(FileOutputStream(backupFile))).use { out ->
|
||||||
for (zipItem in zipItems) {
|
for (zipItem in zipItems) {
|
||||||
FileInputStream(zipItem.filePath).use { fi ->
|
FileInputStream(zipItem.filePath).use { fi ->
|
||||||
|
@ -51,7 +61,6 @@ object BackupHelper {
|
||||||
Toast.makeText(App.getContext(), "Couldn't create backup", Toast.LENGTH_SHORT)
|
Toast.makeText(App.getContext(), "Couldn't create backup", Toast.LENGTH_SHORT)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
throw Exception(it)
|
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
|
@ -62,34 +71,39 @@ object BackupHelper {
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDatabaseZipItems(context: Context): List<ZipItem> {
|
private suspend fun getPlaylistZipItems(context: Context): List<ZipItem> {
|
||||||
return context.databaseList().filter {
|
val playlistZipItems = mutableListOf<ZipItem>()
|
||||||
it.endsWith(".db") && it != queueDatabase
|
// Cache Playlist files in App storage
|
||||||
}.map {
|
val playlistFolder = File(context.filesDir, PLAYLISTS_PATH)
|
||||||
ZipItem(context.getDatabasePath(it).absolutePath, "$DATABASES_PATH${File.separator}$it")
|
if (!playlistFolder.exists()) {
|
||||||
|
playlistFolder.mkdirs()
|
||||||
}
|
}
|
||||||
}
|
for (playlist in repository.fetchPlaylistWithSongs()) {
|
||||||
|
runCatching {
|
||||||
private fun getQueueZipItems(context: Context): List<ZipItem> {
|
M3UWriter.writeIO(playlistFolder, playlist)
|
||||||
Log.d("RetroMusic", context.getDatabasePath(queueDatabase).absolutePath)
|
}.onSuccess { playlistFile ->
|
||||||
return listOf(
|
if (playlistFile.exists()) {
|
||||||
|
playlistZipItems.add(
|
||||||
ZipItem(
|
ZipItem(
|
||||||
context.getDatabasePath(queueDatabase).absolutePath,
|
playlistFile.absolutePath,
|
||||||
"$QUEUE_PATH${File.separator}$queueDatabase"
|
PLAYLISTS_PATH.child(playlistFile.name)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return playlistZipItems
|
||||||
|
}
|
||||||
|
|
||||||
private fun getSettingsZipItems(context: Context): List<ZipItem> {
|
private fun getSettingsZipItems(context: Context): List<ZipItem> {
|
||||||
val sharedPrefPath = context.filesDir.parentFile?.absolutePath + "/shared_prefs/"
|
val sharedPrefPath = File(context.filesDir.parentFile, "shared_prefs")
|
||||||
return listOf(
|
return listOf(
|
||||||
"${BuildConfig.APPLICATION_ID}_preferences.xml", // App settings pref path
|
"${BuildConfig.APPLICATION_ID}_preferences.xml", // App settings pref path
|
||||||
"$THEME_PREFS_KEY_DEFAULT.xml" // appthemehelper pref path
|
"$THEME_PREFS_KEY_DEFAULT.xml" // appthemehelper pref path
|
||||||
).map {
|
).map {
|
||||||
ZipItem(sharedPrefPath + it, "$SETTINGS_PATH${File.separator}$it")
|
ZipItem(File(sharedPrefPath, it).absolutePath, SETTINGS_PATH.child(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,35 +111,33 @@ object BackupHelper {
|
||||||
return context.filesDir.listFiles { _, name ->
|
return context.filesDir.listFiles { _, name ->
|
||||||
name.endsWith(".jpg")
|
name.endsWith(".jpg")
|
||||||
}?.map {
|
}?.map {
|
||||||
ZipItem(it.absolutePath, "$IMAGES_PATH${File.separator}${it.name}")
|
ZipItem(it.absolutePath, IMAGES_PATH.child(it.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCustomArtistZipItems(context: Context): List<ZipItem> {
|
private fun getCustomArtistZipItems(context: Context): List<ZipItem> {
|
||||||
val zipItemList = mutableListOf<ZipItem>()
|
val zipItemList = mutableListOf<ZipItem>()
|
||||||
val sharedPrefPath = context.filesDir.parentFile?.absolutePath + "/shared_prefs/"
|
val sharedPrefPath = File(context.filesDir.parentFile, "shared_prefs")
|
||||||
|
|
||||||
zipItemList.addAll(
|
zipItemList.addAll(
|
||||||
File(context.filesDir, "custom_artist_images")
|
File(context.filesDir, "custom_artist_images")
|
||||||
.listFiles()?.map {
|
.listFiles()?.map {
|
||||||
ZipItem(
|
ZipItem(
|
||||||
it.absolutePath,
|
it.absolutePath,
|
||||||
"$CUSTOM_ARTISTS_PATH${File.separator}custom_artist_images${File.separator}${it.name}"
|
CUSTOM_ARTISTS_PATH.child("custom_artist_images").child(it.name)
|
||||||
)
|
)
|
||||||
}?.toList() ?: listOf()
|
}?.toList() ?: listOf()
|
||||||
)
|
)
|
||||||
File(sharedPrefPath + File.separator + "custom_artist_image.xml").let {
|
File(sharedPrefPath, "custom_artist_image.xml").let {
|
||||||
if (it.exists()) {
|
if (it.exists()) {
|
||||||
zipItemList.add(
|
zipItemList.add(
|
||||||
ZipItem(
|
ZipItem(
|
||||||
it.absolutePath,
|
it.absolutePath,
|
||||||
"$CUSTOM_ARTISTS_PATH${File.separator}prefs${File.separator}custom_artist_image.xml"
|
CUSTOM_ARTISTS_PATH.child("prefs").child("custom_artist_image.xml")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return zipItemList
|
return zipItemList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,23 +150,19 @@ object BackupHelper {
|
||||||
ZipInputStream(inputStream).use {
|
ZipInputStream(inputStream).use {
|
||||||
var entry = it.nextEntry
|
var entry = it.nextEntry
|
||||||
while (entry != null) {
|
while (entry != null) {
|
||||||
if (entry.isDatabaseEntry() && contents.contains(PLAYLISTS)) {
|
if (entry.isPlaylistEntry() && contents.contains(PLAYLISTS)) {
|
||||||
restoreDatabase(context, it, entry)
|
restorePlaylists(it, entry)
|
||||||
} else if (entry.isPreferenceEntry() && contents.contains(SETTINGS)) {
|
} else if (entry.isPreferenceEntry() && contents.contains(SETTINGS)) {
|
||||||
restorePreferences(context, it, entry)
|
restorePreferences(context, it, entry)
|
||||||
} else if (entry.isImageEntry() && contents.contains(USER_IMAGES)) {
|
} else if (entry.isImageEntry() && contents.contains(USER_IMAGES)) {
|
||||||
restoreImages(context, it, entry)
|
restoreImages(context, it, entry)
|
||||||
|
} else if (entry.isCustomArtistEntry() && contents.contains(CUSTOM_ARTIST_IMAGES)) {
|
||||||
} else if (entry.isCustomArtistImageEntry() && contents.contains(
|
if (entry.isCustomArtistPrefEntry()) {
|
||||||
CUSTOM_ARTIST_IMAGES
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
restoreCustomArtistImages(context, it, entry)
|
|
||||||
restoreCustomArtistPrefs(context, it, entry)
|
restoreCustomArtistPrefs(context, it, entry)
|
||||||
} else if (entry.isQueueEntry() && contents.contains(QUEUE)) {
|
} else if (entry.isCustomArtistImageEntry()) {
|
||||||
restoreQueueDatabase(context, it, entry)
|
restoreCustomArtistImages(context, it, entry)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = it.nextEntry
|
entry = it.nextEntry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,14 +173,11 @@ object BackupHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreImages(context: Context, zipIn: ZipInputStream, zipEntry: ZipEntry) {
|
private fun restoreImages(context: Context, zipIn: ZipInputStream, zipEntry: ZipEntry) {
|
||||||
val filePath =
|
val file = File(
|
||||||
context.filesDir.path + File.separator + zipEntry.getFileName()
|
context.filesDir.path, zipEntry.getFileName()
|
||||||
BufferedOutputStream(FileOutputStream(filePath)).use { bos ->
|
)
|
||||||
val bytesIn = ByteArray(DEFAULT_BUFFER_SIZE)
|
BufferedOutputStream(FileOutputStream(file)).use { bos ->
|
||||||
var read: Int
|
zipIn.copyTo(bos)
|
||||||
while (zipIn.read(bytesIn).also { read = it } != -1) {
|
|
||||||
bos.write(bytesIn, 0, read)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,39 +189,38 @@ object BackupHelper {
|
||||||
file.delete()
|
file.delete()
|
||||||
}
|
}
|
||||||
BufferedOutputStream(FileOutputStream(file)).use { bos ->
|
BufferedOutputStream(FileOutputStream(file)).use { bos ->
|
||||||
val bytesIn = ByteArray(DEFAULT_BUFFER_SIZE)
|
zipIn.copyTo(bos)
|
||||||
var read: Int
|
|
||||||
while (zipIn.read(bytesIn).also { read = it } != -1) {
|
|
||||||
bos.write(bytesIn, 0, read)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreDatabase(context: Context, zipIn: ZipInputStream, zipEntry: ZipEntry) {
|
private suspend fun restorePlaylists(
|
||||||
val filePath =
|
zipIn: ZipInputStream,
|
||||||
context.filesDir.parent!! + File.separator + DATABASES_PATH + File.separator + zipEntry.getFileName()
|
zipEntry: ZipEntry
|
||||||
BufferedOutputStream(FileOutputStream(filePath)).use { bos ->
|
) {
|
||||||
val bytesIn = ByteArray(DEFAULT_BUFFER_SIZE)
|
val playlistName = zipEntry.getFileName().substringBeforeLast(".")
|
||||||
var read: Int
|
val songs = mutableListOf<Song>()
|
||||||
while (zipIn.read(bytesIn).also { read = it } != -1) {
|
|
||||||
bos.write(bytesIn, 0, read)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun restoreQueueDatabase(context: Context, zipIn: ZipInputStream, zipEntry: ZipEntry) {
|
// Get songs from m3u playlist files
|
||||||
PreferenceManager.getDefaultSharedPreferences(context).edit(commit = true) {
|
zipIn.bufferedReader().lineSequence().forEach { line ->
|
||||||
putInt("POSITION", 0)
|
if (line.startsWith(File.separator)) {
|
||||||
|
if (File(line).exists()) {
|
||||||
|
songs.addAll(songRepository.songsByFilePath(line))
|
||||||
}
|
}
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val playlistEntity = repository.checkPlaylistExists(playlistName).firstOrNull()
|
||||||
|
if (playlistEntity != null) {
|
||||||
|
val songEntities = songs.map {
|
||||||
|
it.toSongEntity(playlistEntity.playListId)
|
||||||
|
}
|
||||||
|
repository.insertSongs(songEntities)
|
||||||
|
} else {
|
||||||
|
val playListId = repository.createPlaylist(PlaylistEntity(playlistName = playlistName))
|
||||||
|
val songEntities = songs.map {
|
||||||
|
it.toSongEntity(playListId)
|
||||||
|
}
|
||||||
|
repository.insertSongs(songEntities)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreCustomArtistImages(
|
private fun restoreCustomArtistImages(
|
||||||
|
@ -237,11 +241,7 @@ object BackupHelper {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).use { bos ->
|
).use { bos ->
|
||||||
val bytesIn = ByteArray(DEFAULT_BUFFER_SIZE)
|
zipIn.copyTo(bos)
|
||||||
var read: Int
|
|
||||||
while (zipIn.read(bytesIn).also { read = it } != -1) {
|
|
||||||
bos.write(bytesIn, 0, read)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,32 +250,30 @@ object BackupHelper {
|
||||||
zipIn: ZipInputStream,
|
zipIn: ZipInputStream,
|
||||||
zipEntry: ZipEntry
|
zipEntry: ZipEntry
|
||||||
) {
|
) {
|
||||||
val filePath =
|
val file =
|
||||||
context.filesDir.parentFile?.absolutePath + "/shared_prefs/" + zipEntry.getFileName()
|
File(context.filesDir.parentFile, "shared_prefs".child(zipEntry.getFileName()))
|
||||||
BufferedOutputStream(FileOutputStream(filePath)).use { bos ->
|
BufferedOutputStream(FileOutputStream(file)).use { bos ->
|
||||||
val bytesIn = ByteArray(DEFAULT_BUFFER_SIZE)
|
zipIn.copyTo(bos)
|
||||||
var read: Int
|
|
||||||
while (zipIn.read(bytesIn).also { read = it } != -1) {
|
|
||||||
bos.write(bytesIn, 0, read)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val backupRootPath =
|
fun getBackupRoot(context: Context): File {
|
||||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
|
return File(
|
||||||
.toString() + "/RetroMusic/Backups/"
|
context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS),
|
||||||
|
"RetroMusic/Backups"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const val BACKUP_EXTENSION = "rmbak"
|
const val BACKUP_EXTENSION = "rmbak"
|
||||||
const val APPEND_EXTENSION = ".$BACKUP_EXTENSION"
|
const val APPEND_EXTENSION = ".$BACKUP_EXTENSION"
|
||||||
private const val DATABASES_PATH = "databases"
|
private const val PLAYLISTS_PATH = "Playlists"
|
||||||
private const val QUEUE_PATH = "queue"
|
|
||||||
private const val SETTINGS_PATH = "prefs"
|
private const val SETTINGS_PATH = "prefs"
|
||||||
private const val IMAGES_PATH = "userImages"
|
private const val IMAGES_PATH = "userImages"
|
||||||
private const val CUSTOM_ARTISTS_PATH = "artistImages"
|
private const val CUSTOM_ARTISTS_PATH = "artistImages"
|
||||||
private const val THEME_PREFS_KEY_DEFAULT = "[[kabouzeid_app-theme-helper]]"
|
private const val THEME_PREFS_KEY_DEFAULT = "[[kabouzeid_app-theme-helper]]"
|
||||||
private const val queueDatabase = "music_playback_state.db"
|
|
||||||
|
|
||||||
private fun ZipEntry.isDatabaseEntry(): Boolean {
|
private fun ZipEntry.isPlaylistEntry(): Boolean {
|
||||||
return name.startsWith(DATABASES_PATH)
|
return name.startsWith(PLAYLISTS_PATH)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ZipEntry.isPreferenceEntry(): Boolean {
|
private fun ZipEntry.isPreferenceEntry(): Boolean {
|
||||||
|
@ -286,6 +284,10 @@ object BackupHelper {
|
||||||
return name.startsWith(IMAGES_PATH)
|
return name.startsWith(IMAGES_PATH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun ZipEntry.isCustomArtistEntry(): Boolean {
|
||||||
|
return name.startsWith(CUSTOM_ARTISTS_PATH)
|
||||||
|
}
|
||||||
|
|
||||||
private fun ZipEntry.isCustomArtistImageEntry(): Boolean {
|
private fun ZipEntry.isCustomArtistImageEntry(): Boolean {
|
||||||
return name.startsWith(CUSTOM_ARTISTS_PATH) && name.contains("custom_artist_images")
|
return name.startsWith(CUSTOM_ARTISTS_PATH) && name.contains("custom_artist_images")
|
||||||
}
|
}
|
||||||
|
@ -294,12 +296,12 @@ object BackupHelper {
|
||||||
return name.startsWith(CUSTOM_ARTISTS_PATH) && name.contains("prefs")
|
return name.startsWith(CUSTOM_ARTISTS_PATH) && name.contains("prefs")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ZipEntry.isQueueEntry(): Boolean {
|
private fun ZipEntry.getFileName(): String {
|
||||||
return name.startsWith(QUEUE_PATH)
|
return name.substring(name.lastIndexOf(File.separator) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ZipEntry.getFileName(): String {
|
fun getTimeStamp(): String {
|
||||||
return name.substring(name.lastIndexOf(File.separator))
|
return SimpleDateFormat("dd-MMM yyyy HHmmss", Locale.getDefault()).format(Date())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,10 +320,13 @@ fun CharSequence.sanitize(): String {
|
||||||
.replace("&", "_")
|
.replace("&", "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.child(child: String): String {
|
||||||
|
return this + File.separator + child
|
||||||
|
}
|
||||||
|
|
||||||
enum class BackupContent {
|
enum class BackupContent {
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
USER_IMAGES,
|
USER_IMAGES,
|
||||||
CUSTOM_ARTIST_IMAGES,
|
CUSTOM_ARTIST_IMAGES,
|
||||||
PLAYLISTS,
|
PLAYLISTS
|
||||||
QUEUE
|
|
||||||
}
|
}
|
|
@ -459,7 +459,7 @@ object MusicPlayerRemote : KoinComponent {
|
||||||
songFile = File(path)
|
songFile = File(path)
|
||||||
}
|
}
|
||||||
if (songFile == null && uri.path != null) {
|
if (songFile == null && uri.path != null) {
|
||||||
songFile = File(uri.path)
|
songFile = File(uri.path!!)
|
||||||
}
|
}
|
||||||
if (songFile != null) {
|
if (songFile != null) {
|
||||||
songs = songRepository.songsByFilePath(songFile.absolutePath)
|
songs = songRepository.songsByFilePath(songFile.absolutePath)
|
||||||
|
|
|
@ -134,7 +134,7 @@ class SortOrder {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
/* Artist song sort order A-Z */
|
/* Artist song sort order A-Z */
|
||||||
private const val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
|
const val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
/* Artist song sort order Z-A */
|
/* Artist song sort order Z-A */
|
||||||
const val SONG_Z_A = "$SONG_A_Z DESC"
|
const val SONG_Z_A = "$SONG_A_Z DESC"
|
||||||
|
|
|
@ -169,11 +169,11 @@ class CoverLrcView @JvmOverloads constructor(
|
||||||
mCurrentLine = centerLine
|
mCurrentLine = centerLine
|
||||||
invalidate()
|
invalidate()
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
callOnClick()
|
callOnClick()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return super.onSingleTapConfirmed(e)
|
return super.onSingleTapConfirmed(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
|
|
||||||
package code.name.monkey.retromusic.model
|
package code.name.monkey.retromusic.model
|
||||||
|
|
||||||
|
import code.name.monkey.retromusic.helper.SortOrder
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
|
||||||
data class Artist(
|
data class Artist(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
|
@ -29,7 +31,7 @@ data class Artist(
|
||||||
name = artistName
|
name = artistName
|
||||||
}
|
}
|
||||||
|
|
||||||
var name: String = ""
|
var name: String = "-"
|
||||||
get() {
|
get() {
|
||||||
val name = if (isAlbumArtist) getAlbumArtistName()
|
val name = if (isAlbumArtist) getAlbumArtistName()
|
||||||
else getArtistName()
|
else getArtistName()
|
||||||
|
@ -57,6 +59,39 @@ data class Artist(
|
||||||
val songs: List<Song>
|
val songs: List<Song>
|
||||||
get() = albums.flatMap { it.songs }
|
get() = albums.flatMap { it.songs }
|
||||||
|
|
||||||
|
val sortedSongs: List<Song>
|
||||||
|
get() = songs.sortedWith(
|
||||||
|
when (PreferenceUtil.artistDetailSongSortOrder) {
|
||||||
|
SortOrder.ArtistSongSortOrder.SONG_A_Z -> { o1, o2 ->
|
||||||
|
o1.title.compareTo(
|
||||||
|
o2.title
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SortOrder.ArtistSongSortOrder.SONG_Z_A -> { o1, o2 ->
|
||||||
|
o2.title.compareTo(
|
||||||
|
o1.title
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SortOrder.ArtistSongSortOrder.SONG_ALBUM -> { o1, o2 ->
|
||||||
|
o1.albumName.compareTo(
|
||||||
|
o2.albumName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SortOrder.ArtistSongSortOrder.SONG_YEAR -> { o1, o2 ->
|
||||||
|
o2.year.compareTo(
|
||||||
|
o1.year
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SortOrder.ArtistSongSortOrder.SONG_DURATION -> { o1, o2 ->
|
||||||
|
o1.duration.compareTo(
|
||||||
|
o2.duration
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
throw IllegalArgumentException("invalid ${PreferenceUtil.artistDetailSongSortOrder}")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
fun safeGetFirstAlbum(): Album {
|
fun safeGetFirstAlbum(): Album {
|
||||||
return albums.firstOrNull() ?: Album.empty
|
return albums.firstOrNull() ?: Album.empty
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,4 @@ open class Playlist(
|
||||||
result = 31 * result + name.hashCode()
|
result = 31 * result + name.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -55,7 +55,6 @@ class LibraryPreferenceDialog : DialogFragment() {
|
||||||
.inflate(R.layout.preference_dialog_library_categories, null)
|
.inflate(R.layout.preference_dialog_library_categories, null)
|
||||||
|
|
||||||
val categoryAdapter = CategoryInfoAdapter()
|
val categoryAdapter = CategoryInfoAdapter()
|
||||||
categoryAdapter.categoryInfos = PreferenceUtil.libraryCategory
|
|
||||||
val recyclerView = view.findViewById<RecyclerView>(R.id.recycler_view)
|
val recyclerView = view.findViewById<RecyclerView>(R.id.recycler_view)
|
||||||
recyclerView.layoutManager = LinearLayoutManager(activity)
|
recyclerView.layoutManager = LinearLayoutManager(activity)
|
||||||
recyclerView.adapter = categoryAdapter
|
recyclerView.adapter = categoryAdapter
|
||||||
|
|
|
@ -17,7 +17,6 @@ package code.name.monkey.retromusic.repository
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.provider.BaseColumns
|
import android.provider.BaseColumns
|
||||||
import android.provider.MediaStore
|
|
||||||
import android.provider.MediaStore.Audio.AudioColumns
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
import android.provider.MediaStore.Audio.Playlists.*
|
import android.provider.MediaStore.Audio.Playlists.*
|
||||||
import android.provider.MediaStore.Audio.PlaylistsColumns
|
import android.provider.MediaStore.Audio.PlaylistsColumns
|
||||||
|
@ -120,13 +119,18 @@ class RealPlaylistRepository(
|
||||||
private fun getPlaylistFromCursorImpl(
|
private fun getPlaylistFromCursorImpl(
|
||||||
cursor: Cursor
|
cursor: Cursor
|
||||||
): Playlist {
|
): Playlist {
|
||||||
val id = cursor.getLong(MediaStore.MediaColumns._ID)
|
val id = cursor.getLong(0)
|
||||||
val name = cursor.getString(NAME)
|
val name = cursor.getString(1)
|
||||||
return Playlist(id, name)
|
return if (name != null) {
|
||||||
|
Playlist(id, name)
|
||||||
|
} else {
|
||||||
|
Playlist.empty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun playlistSongs(playlistId: Long): List<Song> {
|
override fun playlistSongs(playlistId: Long): List<Song> {
|
||||||
val songs = arrayListOf<Song>()
|
val songs = arrayListOf<Song>()
|
||||||
|
if (playlistId == -1L) return songs
|
||||||
val cursor = makePlaylistSongCursor(playlistId)
|
val cursor = makePlaylistSongCursor(playlistId)
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
|
|
@ -130,6 +130,13 @@ object PreferenceUtil {
|
||||||
)
|
)
|
||||||
set(value) = sharedPreferences.edit { putString(ALBUM_DETAIL_SONG_SORT_ORDER, value) }
|
set(value) = sharedPreferences.edit { putString(ALBUM_DETAIL_SONG_SORT_ORDER, value) }
|
||||||
|
|
||||||
|
var artistDetailSongSortOrder
|
||||||
|
get() = sharedPreferences.getStringOrDefault(
|
||||||
|
ARTIST_DETAIL_SONG_SORT_ORDER,
|
||||||
|
ArtistSongSortOrder.SONG_A_Z
|
||||||
|
)
|
||||||
|
set(value) = sharedPreferences.edit { putString(ARTIST_DETAIL_SONG_SORT_ORDER, value) }
|
||||||
|
|
||||||
var songSortOrder
|
var songSortOrder
|
||||||
get() = sharedPreferences.getStringOrDefault(
|
get() = sharedPreferences.getStringOrDefault(
|
||||||
SONG_SORT_ORDER,
|
SONG_SORT_ORDER,
|
||||||
|
|
|
@ -181,6 +181,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="8"
|
android:layout_weight="8"
|
||||||
android:maxHeight="3dp"
|
android:maxHeight="3dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
android:progressTint="@color/md_white_1000"
|
android:progressTint="@color/md_white_1000"
|
||||||
android:splitTrack="false"
|
android:splitTrack="false"
|
||||||
|
|
|
@ -181,6 +181,7 @@
|
||||||
android:id="@+id/progressSlider"
|
android:id="@+id/progressSlider"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
app:layout_constraintBottom_toTopOf="@id/songInfo"
|
app:layout_constraintBottom_toTopOf="@id/songInfo"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
|
|
|
@ -188,6 +188,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="8"
|
android:layout_weight="8"
|
||||||
android:maxHeight="3dp"
|
android:maxHeight="3dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
android:progressTint="@color/md_white_1000"
|
android:progressTint="@color/md_white_1000"
|
||||||
android:splitTrack="false"
|
android:splitTrack="false"
|
||||||
|
|
|
@ -38,14 +38,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minHeight="48dp"
|
android:minHeight="48dp"
|
||||||
android:text="@string/databases_description" />
|
android:text="@string/playlists" />
|
||||||
|
|
||||||
<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
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
android:id="@+id/check_user_images"
|
android:id="@+id/check_user_images"
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:maxHeight="3dp"
|
android:maxHeight="3dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:splitTrack="false"
|
android:splitTrack="false"
|
||||||
tools:progress="20" />
|
tools:progress="20" />
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:maxHeight="2dp"
|
android:maxHeight="2dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<code.name.monkey.retromusic.views.insets.InsetsConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -79,10 +79,23 @@
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@id/song_sort_order"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/albumRecyclerView"/>
|
app:layout_constraintTop_toBottomOf="@id/albumRecyclerView"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/song_sort_order"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:background="@null"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_sort"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/songTitle"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/songTitle"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/songTitle" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -193,4 +206,4 @@
|
||||||
android:layout_height="72dp"
|
android:layout_height="72dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/listeners" />
|
app:layout_constraintTop_toBottomOf="@id/listeners" />
|
||||||
</code.name.monkey.retromusic.views.insets.InsetsConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -41,6 +41,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:maxHeight="2dp"
|
android:maxHeight="2dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
android:splitTrack="false"
|
android:splitTrack="false"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:maxHeight="2dp"
|
android:maxHeight="2dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:paddingStart="20dp"
|
android:paddingStart="20dp"
|
||||||
android:paddingEnd="20dp"
|
android:paddingEnd="20dp"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
|
|
|
@ -28,10 +28,11 @@
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatSeekBar
|
<androidx.appcompat.widget.AppCompatSeekBar
|
||||||
android:id="@+id/progressSlider"
|
android:id="@+id/progressSlider"
|
||||||
android:layout_width="0dp"
|
|
||||||
style="@style/MusicProgressSlider"
|
style="@style/MusicProgressSlider"
|
||||||
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1"/>
|
android:layout_weight="1"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/songTotalTime"
|
android:id="@+id/songTotalTime"
|
||||||
|
|
|
@ -172,6 +172,7 @@
|
||||||
android:id="@+id/progressSlider"
|
android:id="@+id/progressSlider"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/songInfo"
|
app:layout_constraintBottom_toTopOf="@+id/songInfo"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_toLeftOf="@id/songTotalTime"
|
android:layout_toLeftOf="@id/songTotalTime"
|
||||||
android:layout_toRightOf="@id/songCurrentProgress"
|
android:layout_toRightOf="@id/songCurrentProgress"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
tools:ignore="RtlHardcoded,UnusedAttribute" />
|
tools:ignore="RtlHardcoded,UnusedAttribute" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:maxHeight="2dp"
|
android:maxHeight="2dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
style="@style/MusicProgressSlider"
|
style="@style/MusicProgressSlider"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
tools:ignore="RtlHardcoded,UnusedAttribute" />
|
tools:ignore="RtlHardcoded,UnusedAttribute" />
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="8"
|
android:layout_weight="8"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:splitTrack="false"
|
android:splitTrack="false"
|
||||||
android:thumb="@drawable/switch_square"
|
android:thumb="@drawable/switch_square"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
|
|
|
@ -99,6 +99,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:maxHeight="2dp"
|
android:maxHeight="2dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
|
|
|
@ -101,6 +101,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
app:layout_constraintTop_toBottomOf="@id/titleContainer"
|
app:layout_constraintTop_toBottomOf="@id/titleContainer"
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:maxHeight="2dp"
|
android:maxHeight="2dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:maxHeight="2dp"
|
android:maxHeight="2dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:maxHeight="2dp"
|
android:maxHeight="2dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:ignore="RtlHardcoded,UnusedAttribute"
|
tools:ignore="RtlHardcoded,UnusedAttribute"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
tools:progress="20" />
|
tools:progress="20" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:maxHeight="2dp"
|
android:maxHeight="2dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
|
||||||
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:maxHeight="2dp"
|
android:maxHeight="2dp"
|
||||||
|
android:paddingVertical="@dimen/seekbar_padding"
|
||||||
android:progressDrawable="@drawable/color_progress_seek"
|
android:progressDrawable="@drawable/color_progress_seek"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/volumeDown"
|
app:layout_constraintBottom_toBottomOf="@+id/volumeDown"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/volumeUp"
|
app:layout_constraintEnd_toStartOf="@+id/volumeUp"
|
||||||
|
|
|
@ -20,13 +20,14 @@
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
|
android:padding="8dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
|
android:src="@drawable/ic_restore"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/title"
|
app:layout_constraintEnd_toStartOf="@id/title"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
20
app/src/main/res/menu/menu_artist_song_sort_order.xml
Normal file
20
app/src/main/res/menu/menu_artist_song_sort_order.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<group android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort_order_title"
|
||||||
|
android:title="@string/sort_order_a_z" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort_order_title_desc"
|
||||||
|
android:title="@string/sort_order_z_a" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort_order_album"
|
||||||
|
android:title="@string/sort_order_album" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort_order_year"
|
||||||
|
android:title="@string/sort_order_year" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort_order_song_duration"
|
||||||
|
android:title="@string/song_duration" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
|
@ -146,7 +146,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">يستمع حالياً إلى %1$s لـ %2$s</string>
|
<string name="currently_listening_to_x_by_x">يستمع حالياً إلى %1$s لـ %2$s</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">أسود قليلاً</string>
|
<string name="dark_theme_name">أسود قليلاً</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">حذف قائمة التشغيل</string>
|
<string name="delete_playlist_title">حذف قائمة التشغيل</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[حذف قائمة التشغيل <b>%1$s</b>؟]]></string>
|
<string name="delete_playlist_x"><![CDATA[حذف قائمة التشغيل <b>%1$s</b>؟]]></string>
|
||||||
<string name="delete_playlists_title">حذف قوائم التشغيل</string>
|
<string name="delete_playlists_title">حذف قوائم التشغيل</string>
|
||||||
|
|
|
@ -140,7 +140,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Aktuálně posloucháš %1$s od %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Aktuálně posloucháš %1$s od %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Tmavá</string>
|
<string name="dark_theme_name">Tmavá</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Smazat seznam skladeb</string>
|
<string name="delete_playlist_title">Smazat seznam skladeb</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Smazat seznam skladeb <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Smazat seznam skladeb <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Smazat seznamy skladeb</string>
|
<string name="delete_playlists_title">Smazat seznamy skladeb</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Spielt zur Zeit %1$s von %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Spielt zur Zeit %1$s von %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Dunkel</string>
|
<string name="dark_theme_name">Dunkel</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Playlist löschen</string>
|
<string name="delete_playlist_title">Playlist löschen</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Playlist <b>%1$s</b> löschen?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Playlist <b>%1$s</b> löschen?]]></string>
|
||||||
<string name="delete_playlists_title">Playlisten löschen</string>
|
<string name="delete_playlists_title">Playlisten löschen</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Παίζει το %1$s από τους %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Παίζει το %1$s από τους %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Κάπως Σκούρο</string>
|
<string name="dark_theme_name">Κάπως Σκούρο</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Διαγραφή playlist</string>
|
<string name="delete_playlist_title">Διαγραφή playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Διαγραφή της λίστα αναπαραγωγής <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Διαγραφή της λίστα αναπαραγωγής <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Διαγραφή αυτών των λιστών αναπαραγωγής</string>
|
<string name="delete_playlists_title">Διαγραφή αυτών των λιστών αναπαραγωγής</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Actualmente estás escuchando %1$s de %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Actualmente estás escuchando %1$s de %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Un poco Oscuro</string>
|
<string name="dark_theme_name">Un poco Oscuro</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Eliminar lista de reproducción</string>
|
<string name="delete_playlist_title">Eliminar lista de reproducción</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[¿Eliminar la lista de reproducción <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[¿Eliminar la lista de reproducción <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Eliminar listas de reproducción</string>
|
<string name="delete_playlists_title">Eliminar listas de reproducción</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">در حال حاضر شما به s$1% از s$2% گوش میدهید.</string>
|
<string name="currently_listening_to_x_by_x">در حال حاضر شما به s$1% از s$2% گوش میدهید.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">تقریبا مشکی</string>
|
<string name="dark_theme_name">تقریبا مشکی</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">حذف کردن پلی لیست</string>
|
<string name="delete_playlist_title">حذف کردن پلی لیست</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[حذف پلی لیست <b>%1$s</b>?<b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[حذف پلی لیست <b>%1$s</b>?<b>?]]></string>
|
||||||
<string name="delete_playlists_title">حذف کردن پلی لیست ها</string>
|
<string name="delete_playlists_title">حذف کردن پلی لیست ها</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Kasalukuyang nakikinig sa %1$s ni %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Kasalukuyang nakikinig sa %1$s ni %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Medyo Madilim</string>
|
<string name="dark_theme_name">Medyo Madilim</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Tanggalin ang playlist</string>
|
<string name="delete_playlist_title">Tanggalin ang playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Tanggalin ang playlist na <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Tanggalin ang playlist na <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Tanggalin ang mga playlist</string>
|
<string name="delete_playlists_title">Tanggalin ang mga playlist</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Vous écoutez actuellement %1$s par %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Vous écoutez actuellement %1$s par %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Plutôt Sombre</string>
|
<string name="dark_theme_name">Plutôt Sombre</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Supprimer la liste de lecture</string>
|
<string name="delete_playlist_title">Supprimer la liste de lecture</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Supprimer la liste <b>%1$s</b> ?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Supprimer la liste <b>%1$s</b> ?]]></string>
|
||||||
<string name="delete_playlists_title">Supprimer les listes de lecture</string>
|
<string name="delete_playlists_title">Supprimer les listes de lecture</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kinda Dark</string>
|
<string name="dark_theme_name">Kinda Dark</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Delete playlist</string>
|
<string name="delete_playlist_title">Delete playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Delete playlists</string>
|
<string name="delete_playlists_title">Delete playlists</string>
|
||||||
|
|
|
@ -138,7 +138,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kinda Dark</string>
|
<string name="dark_theme_name">Kinda Dark</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Delete playlist</string>
|
<string name="delete_playlist_title">Delete playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Delete playlists</string>
|
<string name="delete_playlists_title">Delete playlists</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Jelenleg %1$s hallgatása %2$s által.</string>
|
<string name="currently_listening_to_x_by_x">Jelenleg %1$s hallgatása %2$s által.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kissé sötét</string>
|
<string name="dark_theme_name">Kissé sötét</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Lejátszási lista törlése</string>
|
<string name="delete_playlist_title">Lejátszási lista törlése</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Törli a <b>%1$s</b> lejátszási listát?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Törli a <b>%1$s</b> lejátszási listát?]]></string>
|
||||||
<string name="delete_playlists_title">Lejátszási listák törlése</string>
|
<string name="delete_playlists_title">Lejátszási listák törlése</string>
|
||||||
|
|
|
@ -137,7 +137,6 @@ https://play.google.com/store/apps/details?id=%s</string>
|
||||||
<string name="currently_listening_to_x_by_x">Ascoltando attualmente %1$s di %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Ascoltando attualmente %1$s di %2$s.</string>
|
||||||
<string name="custom_artist_images">Immagini dell\'Artista Personalizzate</string>
|
<string name="custom_artist_images">Immagini dell\'Artista Personalizzate</string>
|
||||||
<string name="dark_theme_name">Scuro</string>
|
<string name="dark_theme_name">Scuro</string>
|
||||||
<string name="databases_description">Database (Playlist, Cronologia, Più riprodotti, ecc.)</string>
|
|
||||||
<string name="delete_playlist_title">Elimina playlist</string>
|
<string name="delete_playlist_title">Elimina playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Elimina la playlist <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Elimina la playlist <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Elimina playlist</string>
|
<string name="delete_playlists_title">Elimina playlist</string>
|
||||||
|
|
|
@ -135,7 +135,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">現在、 %1$s によって %2$s で聴いています。</string>
|
<string name="currently_listening_to_x_by_x">現在、 %1$s によって %2$s で聴いています。</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">ダーク</string>
|
<string name="dark_theme_name">ダーク</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">プレイリストを削除</string>
|
<string name="delete_playlist_title">プレイリストを削除</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[プレイリスト <b>%1$s</b> を削除しますか?]]></string>
|
<string name="delete_playlist_x"><![CDATA[プレイリスト <b>%1$s</b> を削除しますか?]]></string>
|
||||||
<string name="delete_playlists_title">プレイリストを削除</string>
|
<string name="delete_playlists_title">プレイリストを削除</string>
|
||||||
|
|
|
@ -134,7 +134,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">현재 %2$s의 %1$s를 듣는 중입니다.</string>
|
<string name="currently_listening_to_x_by_x">현재 %2$s의 %1$s를 듣는 중입니다.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">카인다 다크</string>
|
<string name="dark_theme_name">카인다 다크</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">재생목록 삭제</string>
|
<string name="delete_playlist_title">재생목록 삭제</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[<b>%1$s</b> 재생목록을 삭제하시겠습니까?]]></string>
|
<string name="delete_playlist_x"><![CDATA[<b>%1$s</b> 재생목록을 삭제하시겠습니까?]]></string>
|
||||||
<string name="delete_playlists_title">재생목록 삭제</string>
|
<string name="delete_playlists_title">재생목록 삭제</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kinda Dark</string>
|
<string name="dark_theme_name">Kinda Dark</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Delete playlist</string>
|
<string name="delete_playlist_title">Delete playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Delete playlists</string>
|
<string name="delete_playlists_title">Delete playlists</string>
|
||||||
|
|
|
@ -134,7 +134,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">%2$s သီဆိုထားသော %1$s ကိုယခုနားထောင်နေသည်</string>
|
<string name="currently_listening_to_x_by_x">%2$s သီဆိုထားသော %1$s ကိုယခုနားထောင်နေသည်</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">အနက်ရောင်ဆန်ဆန်</string>
|
<string name="dark_theme_name">အနက်ရောင်ဆန်ဆန်</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Playlist ဖျက်ခြင်း</string>
|
<string name="delete_playlist_title">Playlist ဖျက်ခြင်း</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[<b>%1$s</b> Playlist ကိုဖျက်မှာလား]]></string>
|
<string name="delete_playlist_x"><![CDATA[<b>%1$s</b> Playlist ကိုဖျက်မှာလား]]></string>
|
||||||
<string name="delete_playlists_title">Playlist များဖျက်ခြင်း</string>
|
<string name="delete_playlists_title">Playlist များဖျက်ခြင်း</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Nu luisterend naar %1$s van %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Nu luisterend naar %1$s van %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Soort van donker</string>
|
<string name="dark_theme_name">Soort van donker</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Afspeellijst verwijderen</string>
|
<string name="delete_playlist_title">Afspeellijst verwijderen</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Afspellijst <b>%1$s</b> verwijderen?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Afspellijst <b>%1$s</b> verwijderen?]]></string>
|
||||||
<string name="delete_playlists_title">Afspeellijsten verwijderen</string>
|
<string name="delete_playlists_title">Afspeellijsten verwijderen</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kinda Dark</string>
|
<string name="dark_theme_name">Kinda Dark</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Delete playlist</string>
|
<string name="delete_playlist_title">Delete playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Delete playlists</string>
|
<string name="delete_playlists_title">Delete playlists</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kinda Dark</string>
|
<string name="dark_theme_name">Kinda Dark</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Delete playlist</string>
|
<string name="delete_playlist_title">Delete playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Delete playlists</string>
|
<string name="delete_playlists_title">Delete playlists</string>
|
||||||
|
|
|
@ -140,7 +140,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Aktualnie odtwarzane %1$s wykonawcy %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Aktualnie odtwarzane %1$s wykonawcy %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Dość ciemny</string>
|
<string name="dark_theme_name">Dość ciemny</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Usuń playlistę</string>
|
<string name="delete_playlist_title">Usuń playlistę</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Usunąć playlistę <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Usunąć playlistę <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Usuń playlisty</string>
|
<string name="delete_playlists_title">Usuń playlisty</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Atualmente ouvindo %1$s por %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Atualmente ouvindo %1$s por %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Meio escuro</string>
|
<string name="dark_theme_name">Meio escuro</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Excluir playlist</string>
|
<string name="delete_playlist_title">Excluir playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Excluir a playlist <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Excluir a playlist <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Excluir playlists</string>
|
<string name="delete_playlists_title">Excluir playlists</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">A ouvir %1$s de %2$s.</string>
|
<string name="currently_listening_to_x_by_x">A ouvir %1$s de %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Meio escuro</string>
|
<string name="dark_theme_name">Meio escuro</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Eliminar lista</string>
|
<string name="delete_playlist_title">Eliminar lista</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Eliminar a lista <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Eliminar a lista <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Eliminar listas</string>
|
<string name="delete_playlists_title">Eliminar listas</string>
|
||||||
|
|
|
@ -138,7 +138,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Acum ascultați %1$s de %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Acum ascultați %1$s de %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Suriu</string>
|
<string name="dark_theme_name">Suriu</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Șterge playlist</string>
|
<string name="delete_playlist_title">Șterge playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Doriți să ștergeți playlist-ul <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Doriți să ștergeți playlist-ul <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Șterge playlist-uri</string>
|
<string name="delete_playlists_title">Șterge playlist-uri</string>
|
||||||
|
|
|
@ -140,7 +140,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Сейчас играет %1$s от %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Сейчас играет %1$s от %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Тёмная</string>
|
<string name="dark_theme_name">Тёмная</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Удалить плейлист</string>
|
<string name="delete_playlist_title">Удалить плейлист</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Удалить плейлист <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Удалить плейлист <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Удалить плейлисты</string>
|
<string name="delete_playlists_title">Удалить плейлисты</string>
|
||||||
|
|
|
@ -138,7 +138,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Trenutno se reprodukuje %1$s izvodjaca %2$s</string>
|
<string name="currently_listening_to_x_by_x">Trenutno se reprodukuje %1$s izvodjaca %2$s</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kao tamno</string>
|
<string name="dark_theme_name">Kao tamno</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Izbrisi plejlistu</string>
|
<string name="delete_playlist_title">Izbrisi plejlistu</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Izbrisi <b>%1$s</b> plejlistu?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Izbrisi <b>%1$s</b> plejlistu?]]></string>
|
||||||
<string name="delete_playlists_title">Izbrisi plejlistu</string>
|
<string name="delete_playlists_title">Izbrisi plejlistu</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Lyssnar just nu på %1$s av %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Lyssnar just nu på %1$s av %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Ganska mörkt</string>
|
<string name="dark_theme_name">Ganska mörkt</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Radera spellista</string>
|
<string name="delete_playlist_title">Radera spellista</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Radera spellistan <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Radera spellistan <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Radera spellistor</string>
|
<string name="delete_playlists_title">Radera spellistor</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kinda Dark</string>
|
<string name="dark_theme_name">Kinda Dark</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Delete playlist</string>
|
<string name="delete_playlist_title">Delete playlist</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Delete the playlist <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Delete playlists</string>
|
<string name="delete_playlists_title">Delete playlists</string>
|
||||||
|
|
|
@ -134,7 +134,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">กำลังฟัง %1$s ของ %2$s</string>
|
<string name="currently_listening_to_x_by_x">กำลังฟัง %1$s ของ %2$s</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kinda Dark</string>
|
<string name="dark_theme_name">Kinda Dark</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">ลบเพลย์ลิสต์</string>
|
<string name="delete_playlist_title">ลบเพลย์ลิสต์</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[ลบเพลย์ลิสต์ <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[ลบเพลย์ลิสต์ <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">ลบเพลย์ลิสต์</string>
|
<string name="delete_playlists_title">ลบเพลย์ลิสต์</string>
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Şu anda %2$s şarkıcısından %1$s dinleniyor.</string>
|
<string name="currently_listening_to_x_by_x">Şu anda %2$s şarkıcısından %1$s dinleniyor.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Koyu</string>
|
<string name="dark_theme_name">Koyu</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Çalma listesini sil</string>
|
<string name="delete_playlist_title">Çalma listesini sil</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Oynatma listesi <b>%1$s</b> silinsin mi?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Oynatma listesi <b>%1$s</b> silinsin mi?]]></string>
|
||||||
<string name="delete_playlists_title">Çalma listelerini sil</string>
|
<string name="delete_playlists_title">Çalma listelerini sil</string>
|
||||||
|
|
|
@ -140,7 +140,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Зараз грає %1$s від %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Зараз грає %1$s від %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Майже темна</string>
|
<string name="dark_theme_name">Майже темна</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Видалити список відтворення</string>
|
<string name="delete_playlist_title">Видалити список відтворення</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Видалити список відтворення <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Видалити список відтворення <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Видалити списки відтворення</string>
|
<string name="delete_playlists_title">Видалити списки відтворення</string>
|
||||||
|
|
|
@ -135,7 +135,6 @@ tiếp tục xảy ra hãy \"Xóa dữ liệu ứng dụng\"</string>
|
||||||
<string name="currently_listening_to_x_by_x">Đang nghe %1$s bởi %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Đang nghe %1$s bởi %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Xám đen</string>
|
<string name="dark_theme_name">Xám đen</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Xoá danh sách phát</string>
|
<string name="delete_playlist_title">Xoá danh sách phát</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[Xoá danh sách phát <b>%1$s</b>?]]></string>
|
<string name="delete_playlist_x"><![CDATA[Xoá danh sách phát <b>%1$s</b>?]]></string>
|
||||||
<string name="delete_playlists_title">Xoá danh sách phát</string>
|
<string name="delete_playlists_title">Xoá danh sách phát</string>
|
||||||
|
|
|
@ -134,7 +134,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">正在收听 %2$s 的 %1$s。</string>
|
<string name="currently_listening_to_x_by_x">正在收听 %2$s 的 %1$s。</string>
|
||||||
<string name="custom_artist_images">自定义艺术家图像</string>
|
<string name="custom_artist_images">自定义艺术家图像</string>
|
||||||
<string name="dark_theme_name">深色</string>
|
<string name="dark_theme_name">深色</string>
|
||||||
<string name="databases_description">数据库(播放列表、播放历史、最多播放等)</string>
|
|
||||||
<string name="delete_playlist_title">删除播放列表</string>
|
<string name="delete_playlist_title">删除播放列表</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[确定删除播放列表 <b>%1$s</b> 吗?]]></string>
|
<string name="delete_playlist_x"><![CDATA[确定删除播放列表 <b>%1$s</b> 吗?]]></string>
|
||||||
<string name="delete_playlists_title">删除播放列表</string>
|
<string name="delete_playlists_title">删除播放列表</string>
|
||||||
|
|
|
@ -134,7 +134,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">我正在聽 %2$s 的 %1$s</string>
|
<string name="currently_listening_to_x_by_x">我正在聽 %2$s 的 %1$s</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">暗沉</string>
|
<string name="dark_theme_name">暗沉</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">刪除播放清單</string>
|
<string name="delete_playlist_title">刪除播放清單</string>
|
||||||
<string name="delete_playlist_x"><![CDATA[確定要刪除播放清單 <b>%1$s</b> 嗎?]]></string>
|
<string name="delete_playlist_x"><![CDATA[確定要刪除播放清單 <b>%1$s</b> 嗎?]]></string>
|
||||||
<string name="delete_playlists_title">刪除多個播放清單</string>
|
<string name="delete_playlists_title">刪除多個播放清單</string>
|
||||||
|
|
|
@ -64,4 +64,6 @@
|
||||||
<dimen name="m3_card_medium_radius">24dp</dimen>
|
<dimen name="m3_card_medium_radius">24dp</dimen>
|
||||||
<dimen name="m3_card_large_radius">40dp</dimen>
|
<dimen name="m3_card_large_radius">40dp</dimen>
|
||||||
<dimen name="padding_album_cover">16dp</dimen>
|
<dimen name="padding_album_cover">16dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="seekbar_padding">16dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -138,7 +138,6 @@
|
||||||
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
<string name="currently_listening_to_x_by_x">Currently listening to %1$s by %2$s.</string>
|
||||||
<string name="custom_artist_images">Custom Artist Images</string>
|
<string name="custom_artist_images">Custom Artist Images</string>
|
||||||
<string name="dark_theme_name">Kinda Dark</string>
|
<string name="dark_theme_name">Kinda Dark</string>
|
||||||
<string name="databases_description">Databases (Playlists, History, Most Played, etc.)</string>
|
|
||||||
<string name="delete_playlist_title">Delete playlist</string>
|
<string name="delete_playlist_title">Delete playlist</string>
|
||||||
<string name="delete_playlist_x">
|
<string name="delete_playlist_x">
|
||||||
<![CDATA[Delete the playlist <b>%1$s</b>?]]>
|
<![CDATA[Delete the playlist <b>%1$s</b>?]]>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue