Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccea7674bd | ||
|
|
7f332c26ad | ||
|
|
206a7f38ca | ||
|
|
16e0a5e12e | ||
|
|
c6896939e2 | ||
|
|
526253723b | ||
|
|
9350a9cc2e | ||
|
|
e2ec2e4602 | ||
|
|
bca2e8fcae | ||
|
|
43674ea1f9 | ||
|
|
373a1f87a1 | ||
|
|
e14a595fba | ||
|
|
727e137008 | ||
|
|
883d853129 | ||
|
|
0d329aff64 | ||
|
|
94cb6fa279 | ||
|
|
257d80ecac | ||
|
|
d0f77fe0fc | ||
|
|
e95b504dbb | ||
|
|
0b68799507 | ||
|
|
9167be2cf2 | ||
|
|
c6df43da9c | ||
|
|
475ed3e7c8 | ||
|
|
fb4c762655 | ||
|
|
213a0d5293 |
20
CHANGELOG.md
20
CHANGELOG.md
@@ -2,11 +2,31 @@
|
||||
|
||||
## Pending release...
|
||||
|
||||
## [4.6.0](https://github.com/eddyizm/tempo/releases/tag/v4.6.0) (2025-12-22)
|
||||
* chore: Update description_empty_title in English and Polish by @tyren234 in https://github.com/eddyizm/tempus/pull/307
|
||||
* chore(i18n): Update Polish translation by @skajmer in https://github.com/eddyizm/tempus/pull/310
|
||||
* fix: checks preference and writes files externally, updates the ui by @eddyizm in https://github.com/eddyizm/tempus/pull/312
|
||||
* chore: Update description_empty_title in Italian by @pochopsp in https://github.com/eddyizm/tempus/pull/314
|
||||
* chore: Update description_empty_title in French and Spanish by @pochopsp in https://github.com/eddyizm/tempus/pull/315
|
||||
* feat: added regular playlist to home view by @eddyizm in https://github.com/eddyizm/tempus/pull/322
|
||||
|
||||
## New Contributors
|
||||
* @tyren234 made their first contribution in https://github.com/eddyizm/tempus/pull/307
|
||||
* @pochopsp made their first contribution in https://github.com/eddyizm/tempus/pull/314
|
||||
|
||||
|
||||
## [4.5.0](https://github.com/eddyizm/tempo/releases/tag/v4.5.0) (2025-12-12)
|
||||
## What's Changed
|
||||
* fix: updates starred syncing downloads to user defined directory by @eddyizm in https://github.com/eddyizm/tempus/pull/298
|
||||
* fix: handle empty albums and null mappings by @eddyizm in https://github.com/eddyizm/tempus/pull/301
|
||||
* feat: integrate sort recent searches chronologically by @J4mm3ris in https://github.com/eddyizm/tempus/pull/300
|
||||
* feat: add heart to artist/album pages, fixed artist cover art failing by @eddyizm in https://github.com/eddyizm/tempus/pull/303
|
||||
|
||||
## New Contributors
|
||||
* @J4mm3ris made their first contribution in https://github.com/eddyizm/tempus/pull/300
|
||||
|
||||
**Full Changelog**: https://github.com/eddyizm/tempus/compare/v4.4.0...v4.5.0
|
||||
|
||||
## [4.4.0](https://github.com/eddyizm/tempo/releases/tag/v4.4.0) (2025-11-29)
|
||||
## What's Changed
|
||||
* chore: bringing in media service refactor previously reverted after more testing by @eddyizm in https://github.com/eddyizm/tempus/pull/286
|
||||
|
||||
@@ -10,8 +10,8 @@ android {
|
||||
minSdkVersion 24
|
||||
targetSdk 35
|
||||
|
||||
versionCode 10
|
||||
versionName '4.5.0'
|
||||
versionCode 11
|
||||
versionName '4.6.0'
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
|
||||
javaCompileOptions {
|
||||
|
||||
@@ -22,6 +22,7 @@ open class Playlist(
|
||||
var name: String? = null,
|
||||
@ColumnInfo(name = "duration")
|
||||
var duration: Long = 0,
|
||||
@SerializedName("coverArt")
|
||||
@ColumnInfo(name = "coverArt")
|
||||
var coverArtId: String? = null,
|
||||
) : Parcelable {
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.cappielloantonio.tempo.service.MediaManager;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.ExternalAudioReader;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
@@ -31,7 +32,9 @@ import com.google.common.util.concurrent.MoreExecutors;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class PlayerSongQueueAdapter extends RecyclerView.Adapter<PlayerSongQueueAdapter.ViewHolder> {
|
||||
private static final String TAG = "PlayerSongQueueAdapter";
|
||||
@@ -39,7 +42,7 @@ public class PlayerSongQueueAdapter extends RecyclerView.Adapter<PlayerSongQueue
|
||||
|
||||
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
||||
private List<Child> songs;
|
||||
|
||||
private final Map<String, Boolean> downloadStatusCache = new ConcurrentHashMap<>();
|
||||
private String currentPlayingId;
|
||||
private boolean isPlaying;
|
||||
private List<Integer> currentPlayingPositions = Collections.emptyList();
|
||||
@@ -80,7 +83,6 @@ public class PlayerSongQueueAdapter extends RecyclerView.Adapter<PlayerSongQueue
|
||||
.build()
|
||||
.thumbnail(thumbnail)
|
||||
.into(holder.item.queueSongCoverImageView);
|
||||
|
||||
MediaManager.getCurrentIndex(mediaBrowserListenableFuture, new MediaIndexCallback() {
|
||||
@Override
|
||||
public void onRecovery(int index) {
|
||||
@@ -96,16 +98,19 @@ public class PlayerSongQueueAdapter extends RecyclerView.Adapter<PlayerSongQueue
|
||||
}
|
||||
});
|
||||
|
||||
DownloaderManager downloaderManager = DownloadUtil.getDownloadTracker(holder.itemView.getContext());
|
||||
boolean isDownloaded = false;
|
||||
|
||||
if (downloaderManager != null) {
|
||||
boolean isDownloaded = downloaderManager.isDownloaded(song.getId());
|
||||
|
||||
if (isDownloaded) {
|
||||
holder.item.downloadIndicatorIcon.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.item.downloadIndicatorIcon.setVisibility(View.GONE);
|
||||
if (Preferences.getDownloadDirectoryUri() == null) {
|
||||
DownloaderManager downloaderManager = DownloadUtil.getDownloadTracker(holder.itemView.getContext());
|
||||
if (downloaderManager != null) {
|
||||
isDownloaded = downloaderManager.isDownloaded(song.getId());
|
||||
}
|
||||
} else {
|
||||
isDownloaded = ExternalAudioReader.getUri(song) != null;
|
||||
}
|
||||
|
||||
if (isDownloaded) {
|
||||
holder.item.downloadIndicatorIcon.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.item.downloadIndicatorIcon.setVisibility(View.GONE);
|
||||
}
|
||||
@@ -169,7 +174,7 @@ public class PlayerSongQueueAdapter extends RecyclerView.Adapter<PlayerSongQueue
|
||||
holder.item.coverArtOverlay.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<Child> getItems() {
|
||||
return this.songs;
|
||||
}
|
||||
|
||||
@@ -228,6 +228,12 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
activity.navController.navigate(R.id.action_homeFragment_to_albumListPageFragment, bundle);
|
||||
});
|
||||
|
||||
bind.playlistCatalogueTextViewClickable.setOnClickListener(v -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(Constants.PLAYLIST_ALL, Constants.PLAYLIST_ALL);
|
||||
activity.navController.navigate(R.id.action_homeFragment_to_playlistCatalogueFragment, bundle);
|
||||
});
|
||||
|
||||
bind.recentlyPlayedAlbumsTextViewClickable.setOnClickListener(v -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(Constants.ALBUM_RECENTLY_PLAYED, Constants.ALBUM_RECENTLY_PLAYED);
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.databinding.InnerFragmentPlayerQueueBinding;
|
||||
import com.cappielloantonio.tempo.interfaces.ClickCallback;
|
||||
import com.cappielloantonio.tempo.service.DownloaderManager;
|
||||
@@ -32,6 +33,8 @@ import com.cappielloantonio.tempo.ui.adapter.PlayerSongQueueAdapter;
|
||||
import com.cappielloantonio.tempo.ui.dialog.PlaylistChooserDialog;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.ExternalAudioReader;
|
||||
import com.cappielloantonio.tempo.util.ExternalAudioWriter;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.cappielloantonio.tempo.viewmodel.PlaybackViewModel;
|
||||
@@ -384,28 +387,62 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||
return;
|
||||
}
|
||||
|
||||
List<MediaItem> mediaItemsToDownload = MappingUtil.mapMediaItems(queueSongs);
|
||||
int downloadCount = 0;
|
||||
|
||||
if (Preferences.getDownloadDirectoryUri() == null) {
|
||||
List<MediaItem> mediaItemsToDownload = MappingUtil.mapMediaItems(queueSongs);
|
||||
List<com.cappielloantonio.tempo.model.Download> downloadModels = new ArrayList<>();
|
||||
|
||||
List<com.cappielloantonio.tempo.model.Download> downloadModels = new ArrayList<>();
|
||||
for (Child child : queueSongs) {
|
||||
com.cappielloantonio.tempo.model.Download downloadModel =
|
||||
new com.cappielloantonio.tempo.model.Download(child);
|
||||
downloadModel.setArtist(child.getArtist());
|
||||
downloadModel.setAlbum(child.getAlbum());
|
||||
downloadModel.setCoverArtId(child.getCoverArtId());
|
||||
downloadModels.add(downloadModel);
|
||||
}
|
||||
|
||||
for (Child child : queueSongs) {
|
||||
com.cappielloantonio.tempo.model.Download downloadModel =
|
||||
new com.cappielloantonio.tempo.model.Download(child);
|
||||
downloadModel.setArtist(child.getArtist());
|
||||
downloadModel.setAlbum(child.getAlbum());
|
||||
downloadModel.setCoverArtId(child.getCoverArtId());
|
||||
downloadModels.add(downloadModel);
|
||||
}
|
||||
DownloaderManager downloaderManager = DownloadUtil.getDownloadTracker(requireContext());
|
||||
|
||||
DownloaderManager downloaderManager = DownloadUtil.getDownloadTracker(requireContext());
|
||||
|
||||
if (downloaderManager != null) {
|
||||
downloaderManager.download(mediaItemsToDownload, downloadModels);
|
||||
Toast.makeText(requireContext(), "Starting download of " + queueSongs.size() + " songs in the background.", Toast.LENGTH_SHORT).show();
|
||||
if (downloaderManager != null) {
|
||||
downloaderManager.download(mediaItemsToDownload, downloadModels);
|
||||
downloadCount = queueSongs.size();
|
||||
Toast.makeText(requireContext(),
|
||||
getResources().getQuantityString(R.plurals.songs_download_started, downloadCount, downloadCount),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
|
||||
new Handler().postDelayed(() -> {
|
||||
if (playerSongQueueAdapter != null) {
|
||||
playerSongQueueAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
Log.e(TAG, "DownloaderManager not initialized. Check DownloadUtil.");
|
||||
Toast.makeText(requireContext(), "Download service unavailable.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "DownloaderManager not initialized. Check DownloadUtil.");
|
||||
Toast.makeText(requireContext(), "Download service unavailable.", Toast.LENGTH_SHORT).show();
|
||||
for (Child song : queueSongs) {
|
||||
if (ExternalAudioReader.getUri(song) == null) {
|
||||
ExternalAudioWriter.downloadToUserDirectory(requireContext(), song);
|
||||
downloadCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadCount > 0) {
|
||||
Toast.makeText(requireContext(),
|
||||
getResources().getQuantityString(R.plurals.songs_download_started, downloadCount, downloadCount),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
|
||||
new Handler().postDelayed(() -> {
|
||||
if (playerSongQueueAdapter != null) {
|
||||
playerSongQueueAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}, 2000);
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "All songs already downloaded", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
toggleFabMenu();
|
||||
}
|
||||
|
||||
|
||||
@@ -248,15 +248,15 @@ public class HomeViewModel extends AndroidViewModel {
|
||||
pinnedPlaylists.setValue(Collections.emptyList());
|
||||
|
||||
playlistRepository.getPlaylists(false, -1).observe(owner, remotes -> {
|
||||
playlistRepository.getPinnedPlaylists().observe(owner, locals -> {
|
||||
if (remotes != null && locals != null) {
|
||||
List<Playlist> toReturn = remotes.stream()
|
||||
.filter(remote -> locals.stream().anyMatch(local -> local.getId().equals(remote.getId())))
|
||||
.collect(Collectors.toList());
|
||||
if (remotes != null && !remotes.isEmpty()) {
|
||||
List<Playlist> playlists = new ArrayList<>(remotes);
|
||||
Collections.shuffle(playlists);
|
||||
List<Playlist> randomPlaylists = playlists.size() > 5
|
||||
? playlists.subList(0, 5)
|
||||
: playlists;
|
||||
|
||||
pinnedPlaylists.setValue(toReturn);
|
||||
}
|
||||
});
|
||||
pinnedPlaylists.setValue(randomPlaylists);
|
||||
}
|
||||
});
|
||||
|
||||
return pinnedPlaylists;
|
||||
|
||||
@@ -379,16 +379,6 @@
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Best of -->
|
||||
<LinearLayout
|
||||
android:id="@+id/home_best_of_artist_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/most_streamed_song_pre_text_view"
|
||||
@@ -400,6 +390,16 @@
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_subtitle_best_of"
|
||||
android:textAllCaps="true" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Best of -->
|
||||
<LinearLayout
|
||||
android:id="@+id/home_best_of_artist_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/best_of_artist_text_view_refreshable"
|
||||
@@ -913,16 +913,36 @@
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pinned_playlists_text_view"
|
||||
style="@style/TitleLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_pinned_playlists" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/playlist_catalogue_text_view_clickable"
|
||||
style="@style/TitleMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/library_title_playlist_see_all_button" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/pinned_playlists_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -65,6 +65,9 @@
|
||||
<action
|
||||
android:id="@+id/action_homeFragment_to_playlistPageFragment"
|
||||
app:destination="@id/playlistPageFragment" />
|
||||
<action
|
||||
android:id="@+id/action_homeFragment_to_playlistCatalogueFragment"
|
||||
app:destination="@id/playlistCatalogueFragment" />
|
||||
<action
|
||||
android:id="@+id/action_homeFragment_to_podcastChannelCatalogueFragment"
|
||||
app:destination="@id/podcastChannelCatalogueFragment" />
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<string name="delete_download_storage_dialog_positive_button">Continuar</string>
|
||||
<string name="delete_download_storage_dialog_summary">Por favor, sea consciente de que si continúa, todos los elementos descargados de todos los servidores se eliminarán.</string>
|
||||
<string name="delete_download_storage_dialog_title">Eliminar elementos guardados</string>
|
||||
<string name="description_empty_title">Descripción no disponible</string>
|
||||
<string name="description_empty_title">Letra no disponible</string>
|
||||
<string name="disc_titlefull">Disco %1$s - %2$s</string>
|
||||
<string name="disc_titleless">Disco %1$s</string>
|
||||
<string name="download_directory_dialog_negative_button">Cancelar</string>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<string name="delete_download_storage_dialog_positive_button">Continuer</string>
|
||||
<string name="delete_download_storage_dialog_summary">Attention, la poursuite de cette action entraînera la suppression définitive de tous les éléments sauvegardés et téléchargés à partir de tous les serveurs</string>
|
||||
<string name="delete_download_storage_dialog_title">Supprimer les éléments téléchargés</string>
|
||||
<string name="description_empty_title">Aucune description disponible</string>
|
||||
<string name="description_empty_title">Paroles non disponibles</string>
|
||||
<string name="disc_titlefull">Disque %1$s - %2$s</string>
|
||||
<string name="disc_titleless">Disque %1$s</string>
|
||||
<string name="download_directory_dialog_negative_button">Annuler</string>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<string name="delete_download_storage_dialog_positive_button">Continua</string>
|
||||
<string name="delete_download_storage_dialog_summary">Attenzione, procedendo questa azione eliminerà definitivamente tutti gli elementi scaricati da tutti i server.</string>
|
||||
<string name="delete_download_storage_dialog_title">Elimina elementi salvati</string>
|
||||
<string name="description_empty_title">Descrizione non disponibile</string>
|
||||
<string name="description_empty_title">Testo non disponibile</string>
|
||||
<string name="disc_titlefull">Disco %1$s - %2$s</string>
|
||||
<string name="disc_titleless">Disco %1$s</string>
|
||||
<string name="download_directory_dialog_negative_button">Annulla</string>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<string name="delete_download_storage_dialog_positive_button">Kontynuuj</string>
|
||||
<string name="delete_download_storage_dialog_summary">Miej na uwadze to że kontynuowanie tej operacji spowoduje usunięcie wszystkich pobranych plików z wszystkich serwerów.</string>
|
||||
<string name="delete_download_storage_dialog_title">Usuwanie zapisanych plików</string>
|
||||
<string name="description_empty_title">Brak opisu</string>
|
||||
<string name="description_empty_title">Brak tekstu</string>
|
||||
<string name="disc_titlefull">Płyta %1$s - %2$s</string>
|
||||
<string name="disc_titleless">Płyta %1$s</string>
|
||||
<string name="download_directory_dialog_negative_button">Anuluj</string>
|
||||
@@ -124,6 +124,10 @@
|
||||
<string name="home_sync_starred_albums_subtitle">Albumy oznaczone gwiazdką będą dostępne offline</string>
|
||||
<string name="home_sync_starred_artists_title">Synchronizacja wykonawców oznaczonych gwiazdką</string>
|
||||
<string name="home_sync_starred_artists_subtitle">Masz wykonawców oznaczonych gwiazdką, bez pobranej muzyki</string>
|
||||
<plurals name="home_sync_starred_songs_count">
|
||||
<item quantity="one">%d piosenka wymaga synchronizacji</item>
|
||||
<item quantity="other">%d piosenek wymaga synchronizacji</item>
|
||||
</plurals>
|
||||
<string name="home_title_best_of">Najlepsze</string>
|
||||
<string name="home_title_discovery">Odkrywanie</string>
|
||||
<string name="home_title_discovery_shuffle_all_button">Odtwórz wszystkie losowo</string>
|
||||
@@ -527,4 +531,6 @@
|
||||
<string name="folder_play_collecting">Zbieranie piosenek z folderu…</string>
|
||||
<string name="folder_play_playing">Odtwarzanie %d piosenek</string>
|
||||
<string name="folder_play_no_songs">Nie znaleziono piosenek w folderze</string>
|
||||
<string name="search_sort_title">Sortuj ostatnie wyszukiwania chronologicznie</string>
|
||||
<string name="search_sort_summary">Jeżeli włączone, sortuje wyszukiwania chronologicznie. Sortuje po naziwe jeżeli wyłączone.</string>
|
||||
</resources>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<string name="delete_download_storage_dialog_positive_button">Continue</string>
|
||||
<string name="delete_download_storage_dialog_summary">Please be aware that continuing with this action will result in the permanent deletion of all saved items downloaded from all servers.</string>
|
||||
<string name="delete_download_storage_dialog_title">Delete saved items</string>
|
||||
<string name="description_empty_title">No description available</string>
|
||||
<string name="description_empty_title">No lyrics available</string>
|
||||
<string name="disc_titlefull">Disc %1$s - %2$s</string>
|
||||
<string name="disc_titleless">Disc %1$s</string>
|
||||
<string name="download_directory_dialog_negative_button">Cancel</string>
|
||||
|
||||
3
fastlane/metadata/android/en-US/changelogs/11.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/11.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
* fix: checks preference and writes files externally, updates the ui when downloading from the directories
|
||||
* chore: Update description_empty_title in English, Italian, French, Polish and Spanish
|
||||
* feat: added regular playlist to home view
|
||||
Reference in New Issue
Block a user