mirror of
https://github.com/antebudimir/tempus.git
synced 2025-12-31 09:33:33 +00:00
v3.14.1 release (#74)
This commit is contained in:
commit
cc61d1cd48
26 changed files with 581 additions and 22 deletions
|
|
@ -10,8 +10,8 @@ android {
|
|||
minSdkVersion 24
|
||||
targetSdk 35
|
||||
|
||||
versionCode 29
|
||||
versionName '3.13.0'
|
||||
versionCode 30
|
||||
versionName '3.14.1'
|
||||
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
|
||||
|
|
|
|||
|
|
@ -316,6 +316,7 @@ public class MainActivity extends BaseActivity {
|
|||
Preferences.setSkipSilenceMode(false);
|
||||
Preferences.setDataSavingMode(false);
|
||||
Preferences.setStarredSyncEnabled(false);
|
||||
Preferences.setStarredAlbumsSyncEnabled(false);
|
||||
}
|
||||
|
||||
private void resetMusicSession() {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.cappielloantonio.tempo.ui.dialog;
|
|||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
|
@ -97,8 +98,12 @@ public class PlaylistChooserDialog extends DialogFragment implements ClickCallba
|
|||
|
||||
@Override
|
||||
public void onPlaylistClick(Bundle bundle) {
|
||||
Playlist playlist = bundle.getParcelable(Constants.PLAYLIST_OBJECT);
|
||||
playlistChooserViewModel.addSongsToPlaylist(playlist.getId());
|
||||
dismiss();
|
||||
if (playlistChooserViewModel.getSongsToAdd() != null && !playlistChooserViewModel.getSongsToAdd().isEmpty()) {
|
||||
Playlist playlist = bundle.getParcelable(Constants.PLAYLIST_OBJECT);
|
||||
playlistChooserViewModel.addSongsToPlaylist(playlist.getId());
|
||||
dismiss();
|
||||
} else {
|
||||
Toast.makeText(requireContext(), R.string.playlist_chooser_dialog_toast_add_failure, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,11 @@ public class RatingDialog extends DialogFragment {
|
|||
bind.ratingBar.setRating(song.getUserRating() != null ? song.getUserRating() : 0);
|
||||
});
|
||||
} else if (ratingViewModel.getAlbum() != null) {
|
||||
ratingViewModel.getLiveAlbum().observe(this, album -> bind.ratingBar.setRating(/*album.getRating()*/ 0));
|
||||
ratingViewModel.getLiveAlbum().observe(this, album -> {
|
||||
if (album != null) {
|
||||
bind.ratingBar.setRating(album.getUserRating() != null ? album.getUserRating() : 0);
|
||||
}
|
||||
});
|
||||
} else if (ratingViewModel.getArtist() != null) {
|
||||
ratingViewModel.getLiveArtist().observe(this, artist -> bind.ratingBar.setRating(/*artist.getRating()*/ 0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
package com.cappielloantonio.tempo.ui.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.databinding.DialogStarredSyncBinding;
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.cappielloantonio.tempo.viewmodel.StarredAlbumsSyncViewModel;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public class StarredAlbumSyncDialog extends DialogFragment {
|
||||
private StarredAlbumsSyncViewModel starredAlbumsSyncViewModel;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
DialogStarredSyncBinding bind = DialogStarredSyncBinding.inflate(getLayoutInflater());
|
||||
|
||||
starredAlbumsSyncViewModel = new ViewModelProvider(requireActivity()).get(StarredAlbumsSyncViewModel.class);
|
||||
|
||||
return new MaterialAlertDialogBuilder(getActivity())
|
||||
.setView(bind.getRoot())
|
||||
.setTitle(R.string.starred_album_sync_dialog_title)
|
||||
.setPositiveButton(R.string.starred_sync_dialog_positive_button, null)
|
||||
.setNeutralButton(R.string.starred_sync_dialog_neutral_button, null)
|
||||
.setNegativeButton(R.string.starred_sync_dialog_negative_button, null)
|
||||
.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setButtonAction(requireContext());
|
||||
}
|
||||
|
||||
private void setButtonAction(Context context) {
|
||||
androidx.appcompat.app.AlertDialog dialog = (androidx.appcompat.app.AlertDialog) getDialog();
|
||||
|
||||
if (dialog != null) {
|
||||
Button positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE);
|
||||
positiveButton.setOnClickListener(v -> {
|
||||
starredAlbumsSyncViewModel.getStarredAlbumSongs(requireActivity()).observe(this, allSongs -> {
|
||||
if (allSongs != null && !allSongs.isEmpty()) {
|
||||
DownloadUtil.getDownloadTracker(context).download(
|
||||
MappingUtil.mapDownloads(allSongs),
|
||||
allSongs.stream().map(Download::new).collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
dialog.dismiss();
|
||||
});
|
||||
});
|
||||
|
||||
Button neutralButton = dialog.getButton(Dialog.BUTTON_NEUTRAL);
|
||||
neutralButton.setOnClickListener(v -> {
|
||||
Preferences.setStarredAlbumsSyncEnabled(true);
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
Button negativeButton = dialog.getButton(Dialog.BUTTON_NEGATIVE);
|
||||
negativeButton.setOnClickListener(v -> {
|
||||
Preferences.setStarredAlbumsSyncEnabled(false);
|
||||
dialog.dismiss();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ public class AlbumListPageFragment extends Fragment implements ClickCallback {
|
|||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.toolbar_menu, menu);
|
||||
inflater.inflate(R.menu.artist_list_menu, menu);
|
||||
|
||||
MenuItem searchItem = menu.findItem(R.id.action_search);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.ComponentName;
|
|||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
|
@ -27,11 +28,13 @@ import com.cappielloantonio.tempo.databinding.FragmentAlbumPageBinding;
|
|||
import com.cappielloantonio.tempo.glide.CustomGlideRequest;
|
||||
import com.cappielloantonio.tempo.interfaces.ClickCallback;
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
||||
import com.cappielloantonio.tempo.service.MediaManager;
|
||||
import com.cappielloantonio.tempo.service.MediaService;
|
||||
import com.cappielloantonio.tempo.ui.activity.MainActivity;
|
||||
import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.ui.dialog.PlaylistChooserDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.RatingDialog;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
|
|
@ -104,6 +107,16 @@ public class AlbumPageFragment extends Fragment implements ClickCallback {
|
|||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
if (item.getItemId() == R.id.action_rate_album) {
|
||||
Bundle bundle = new Bundle();
|
||||
AlbumID3 album = albumPageViewModel.getAlbum().getValue();
|
||||
bundle.putParcelable(Constants.ALBUM_OBJECT, (Parcelable) album);
|
||||
RatingDialog dialog = new RatingDialog();
|
||||
dialog.setArguments(bundle);
|
||||
dialog.show(requireActivity().getSupportFragmentManager(), null);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.getItemId() == R.id.action_download_album) {
|
||||
albumPageViewModel.getAlbumSongLiveList().observe(getViewLifecycleOwner(), songs -> {
|
||||
DownloadUtil.getDownloadTracker(requireContext()).download(MappingUtil.mapDownloads(songs), songs.stream().map(Download::new).collect(Collectors.toList()));
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import android.view.inputmethod.EditorInfo;
|
|||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.SearchView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
|
@ -24,6 +25,8 @@ import androidx.navigation.Navigation;
|
|||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.databinding.FragmentArtistCatalogueBinding;
|
||||
import com.cappielloantonio.tempo.helper.recyclerview.GridItemDecoration;
|
||||
|
|
@ -32,6 +35,10 @@ import com.cappielloantonio.tempo.ui.activity.MainActivity;
|
|||
import com.cappielloantonio.tempo.ui.adapter.ArtistCatalogueAdapter;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.viewmodel.ArtistCatalogueViewModel;
|
||||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@UnstableApi
|
||||
public class ArtistCatalogueFragment extends Fragment implements ClickCallback {
|
||||
|
|
@ -125,23 +132,50 @@ public class ArtistCatalogueFragment extends Fragment implements ClickCallback {
|
|||
|
||||
SearchView searchView = (SearchView) searchItem.getActionView();
|
||||
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||
|
||||
searchView.setQueryHint(getString(R.string.filter_artist));
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
searchView.clearFocus();
|
||||
return false;
|
||||
// this toast may be overkill...
|
||||
Toast.makeText(requireContext(), "Search: " + query, Toast.LENGTH_SHORT).show();
|
||||
filterArtists(query);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
artistAdapter.getFilter().filter(newText);
|
||||
return false;
|
||||
filterArtists(newText);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
searchView.setPadding(-32, 0, 0, 0);
|
||||
}
|
||||
|
||||
private void filterArtists(String query) {
|
||||
List<ArtistID3> allArtists = artistCatalogueViewModel.getArtistList().getValue();
|
||||
|
||||
if (allArtists == null || allArtists.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (query == null || query.trim().isEmpty()) {
|
||||
artistAdapter.setItems(allArtists);
|
||||
} else {
|
||||
String searchQuery = query.toLowerCase().trim();
|
||||
List<ArtistID3> filteredArtists = new ArrayList<>();
|
||||
|
||||
for (ArtistID3 artist : allArtists) {
|
||||
if (artist.getName() != null &&
|
||||
artist.getName().toLowerCase().contains(searchQuery)) {
|
||||
filteredArtists.add(artist);
|
||||
}
|
||||
}
|
||||
artistAdapter.setItems(filteredArtists);
|
||||
}
|
||||
}
|
||||
|
||||
private void hideKeyboard(View view) {
|
||||
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import com.cappielloantonio.tempo.service.MediaManager;
|
|||
import com.cappielloantonio.tempo.service.MediaService;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Share;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
||||
import com.cappielloantonio.tempo.ui.activity.MainActivity;
|
||||
import com.cappielloantonio.tempo.ui.adapter.AlbumAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.AlbumHorizontalAdapter;
|
||||
|
|
@ -111,6 +112,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
initSyncStarredView();
|
||||
initSyncStarredAlbumsView();
|
||||
initDiscoverSongSlideView();
|
||||
initSimilarSongView();
|
||||
initArtistRadio();
|
||||
|
|
@ -314,6 +316,63 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
});
|
||||
}
|
||||
|
||||
private void initSyncStarredAlbumsView() {
|
||||
if (Preferences.isStarredAlbumsSyncEnabled()) {
|
||||
homeViewModel.getStarredAlbums(getViewLifecycleOwner()).observeForever(new Observer<List<AlbumID3>>() {
|
||||
@Override
|
||||
public void onChanged(List<AlbumID3> albums) {
|
||||
if (albums != null) {
|
||||
DownloaderManager manager = DownloadUtil.getDownloadTracker(requireContext());
|
||||
List<String> albumsToSync = new ArrayList<>();
|
||||
int albumCount = 0;
|
||||
|
||||
for (AlbumID3 album : albums) {
|
||||
boolean needsSync = false;
|
||||
albumCount++;
|
||||
albumsToSync.add(album.getName());
|
||||
}
|
||||
|
||||
if (albumCount > 0) {
|
||||
bind.homeSyncStarredAlbumsCard.setVisibility(View.VISIBLE);
|
||||
String message = getResources().getQuantityString(
|
||||
R.plurals.home_sync_starred_albums_count,
|
||||
albumCount,
|
||||
albumCount
|
||||
);
|
||||
bind.homeSyncStarredAlbumsToSync.setText(message);
|
||||
}
|
||||
}
|
||||
|
||||
homeViewModel.getStarredAlbums(getViewLifecycleOwner()).removeObserver(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bind.homeSyncStarredAlbumsCancel.setOnClickListener(v -> {
|
||||
bind.homeSyncStarredAlbumsCard.setVisibility(View.GONE);
|
||||
});
|
||||
|
||||
bind.homeSyncStarredAlbumsDownload.setOnClickListener(v -> {
|
||||
homeViewModel.getAllStarredAlbumSongs().observeForever(new Observer<List<Child>>() {
|
||||
@Override
|
||||
public void onChanged(List<Child> allSongs) {
|
||||
if (allSongs != null) {
|
||||
DownloaderManager manager = DownloadUtil.getDownloadTracker(requireContext());
|
||||
|
||||
for (Child song : allSongs) {
|
||||
if (!manager.isDownloaded(song.getId())) {
|
||||
manager.download(MappingUtil.mapDownload(song), new Download(song));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
homeViewModel.getAllStarredAlbumSongs().removeObserver(this);
|
||||
bind.homeSyncStarredAlbumsCard.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void initDiscoverSongSlideView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_DISCOVERY)) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
import android.widget.RatingBar;
|
||||
|
|
@ -66,6 +67,7 @@ public class PlayerControllerFragment extends Fragment {
|
|||
private ConstraintLayout playerQuickActionView;
|
||||
private ImageButton playerOpenQueueButton;
|
||||
private ImageButton playerTrackInfo;
|
||||
private LinearLayout ratingContainer;
|
||||
|
||||
private MainActivity activity;
|
||||
private PlayerBottomSheetViewModel playerBottomSheetViewModel;
|
||||
|
|
@ -123,6 +125,8 @@ public class PlayerControllerFragment extends Fragment {
|
|||
playerOpenQueueButton = bind.getRoot().findViewById(R.id.player_open_queue_button);
|
||||
playerTrackInfo = bind.getRoot().findViewById(R.id.player_info_track);
|
||||
songRatingBar = bind.getRoot().findViewById(R.id.song_rating_bar);
|
||||
ratingContainer = bind.getRoot().findViewById(R.id.rating_container);
|
||||
checkAndSetRatingContainerVisibility();
|
||||
}
|
||||
|
||||
private void initQuickActionView() {
|
||||
|
|
@ -430,6 +434,17 @@ public class PlayerControllerFragment extends Fragment {
|
|||
playerMediaCoverViewPager.setCurrentItem(1, true);
|
||||
}
|
||||
|
||||
private void checkAndSetRatingContainerVisibility() {
|
||||
if (ratingContainer == null) return;
|
||||
|
||||
if (Preferences.showItemStarRating()) {
|
||||
ratingContainer.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
ratingContainer.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void setPlaybackParameters(MediaBrowser mediaBrowser) {
|
||||
Button playbackSpeedButton = bind.getRoot().findViewById(R.id.player_playback_speed_button);
|
||||
float currentSpeed = Preferences.getPlaybackSpeed();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import android.transition.TransitionManager;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
|
@ -31,6 +32,7 @@ import com.cappielloantonio.tempo.util.DownloadUtil;
|
|||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.cappielloantonio.tempo.viewmodel.PlayerBottomSheetViewModel;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
|
@ -120,8 +122,10 @@ public class PlayerCoverFragment extends Fragment {
|
|||
});
|
||||
|
||||
bind.innerButtonTopRight.setOnClickListener(view -> {
|
||||
ArrayList<Child> tracks = new ArrayList<>();
|
||||
tracks.add(song);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(Constants.TRACK_OBJECT, song);
|
||||
bundle.putParcelableArrayList(Constants.TRACKS_OBJECT, tracks);
|
||||
|
||||
PlaylistChooserDialog dialog = new PlaylistChooserDialog();
|
||||
dialog.setArguments(bundle);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import com.cappielloantonio.tempo.ui.activity.MainActivity;
|
|||
import com.cappielloantonio.tempo.ui.dialog.DeleteDownloadStorageDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.DownloadStorageDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StarredSyncDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StarredAlbumSyncDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StreamingCacheStorageDialog;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
|
|
@ -94,6 +95,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
|
||||
actionLogout();
|
||||
actionScan();
|
||||
actionSyncStarredAlbums();
|
||||
actionSyncStarredTracks();
|
||||
actionChangeStreamingCacheStorage();
|
||||
actionChangeDownloadStorage();
|
||||
|
|
@ -263,6 +265,18 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
});
|
||||
}
|
||||
|
||||
private void actionSyncStarredAlbums() {
|
||||
findPreference("sync_starred_albums_for_offline_use").setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
if ((Boolean) newValue) {
|
||||
StarredAlbumSyncDialog dialog = new StarredAlbumSyncDialog();
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionChangeStreamingCacheStorage() {
|
||||
findPreference("streaming_cache_storage").setOnPreferenceClickListener(preference -> {
|
||||
StreamingCacheStorageDialog dialog = new StreamingCacheStorageDialog(new DialogClickCallback() {
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ public class AlbumBottomSheetDialog extends BottomSheetDialogFragment implements
|
|||
ToggleButton favoriteToggle = view.findViewById(R.id.button_favorite);
|
||||
favoriteToggle.setChecked(albumBottomSheetViewModel.getAlbum().getStarred() != null);
|
||||
favoriteToggle.setOnClickListener(v -> {
|
||||
albumBottomSheetViewModel.setFavorite();
|
||||
albumBottomSheetViewModel.setFavorite(requireContext());
|
||||
});
|
||||
|
||||
TextView playRadio = view.findViewById(R.id.play_radio_text_view);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ object Preferences {
|
|||
private const val WIFI_ONLY = "wifi_only"
|
||||
private const val DATA_SAVING_MODE = "data_saving_mode"
|
||||
private const val SERVER_UNREACHABLE = "server_unreachable"
|
||||
private const val SYNC_STARRED_ALBUMS_FOR_OFFLINE_USE = "sync_starred_albums_for_offline_use"
|
||||
private const val SYNC_STARRED_TRACKS_FOR_OFFLINE_USE = "sync_starred_tracks_for_offline_use"
|
||||
private const val QUEUE_SYNCING = "queue_syncing"
|
||||
private const val QUEUE_SYNCING_COUNTDOWN = "queue_syncing_countdown"
|
||||
|
|
@ -63,6 +64,7 @@ object Preferences {
|
|||
private const val ALWAYS_ON_DISPLAY = "always_on_display"
|
||||
private const val AUDIO_QUALITY_PER_ITEM = "audio_quality_per_item"
|
||||
private const val HOME_SECTOR_LIST = "home_sector_list"
|
||||
private const val SONG_RATING_PER_ITEM = "song_rating_per_item"
|
||||
private const val RATING_PER_ITEM = "rating_per_item"
|
||||
private const val NEXT_UPDATE_CHECK = "next_update_check"
|
||||
private const val CONTINUOUS_PLAY = "continuous_play"
|
||||
|
|
@ -300,6 +302,18 @@ object Preferences {
|
|||
.apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isStarredAlbumsSyncEnabled(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(SYNC_STARRED_ALBUMS_FOR_OFFLINE_USE, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setStarredAlbumsSyncEnabled(isStarredSyncEnabled: Boolean) {
|
||||
App.getInstance().preferences.edit().putBoolean(
|
||||
SYNC_STARRED_ALBUMS_FOR_OFFLINE_USE, isStarredSyncEnabled
|
||||
).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isStarredSyncEnabled(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(SYNC_STARRED_TRACKS_FOR_OFFLINE_USE, false)
|
||||
|
|
@ -486,6 +500,11 @@ object Preferences {
|
|||
App.getInstance().preferences.edit().putString(HOME_SECTOR_LIST, Gson().toJson(extension)).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showItemStarRating(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(SONG_RATING_PER_ITEM, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showItemRating(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(RATING_PER_ITEM, false)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
package com.cappielloantonio.tempo.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.interfaces.StarCallback;
|
||||
import com.cappielloantonio.tempo.repository.AlbumRepository;
|
||||
import com.cappielloantonio.tempo.repository.ArtistRepository;
|
||||
|
|
@ -16,10 +19,14 @@ import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
|||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Share;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.NetworkUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AlbumBottomSheetViewModel extends AndroidViewModel {
|
||||
private final AlbumRepository albumRepository;
|
||||
|
|
@ -54,7 +61,7 @@ public class AlbumBottomSheetViewModel extends AndroidViewModel {
|
|||
return albumRepository.getAlbumTracks(album.getId());
|
||||
}
|
||||
|
||||
public void setFavorite() {
|
||||
public void setFavorite(Context context) {
|
||||
if (album.getStarred() != null) {
|
||||
if (NetworkUtil.isOffline()) {
|
||||
removeFavoriteOffline();
|
||||
|
|
@ -65,7 +72,7 @@ public class AlbumBottomSheetViewModel extends AndroidViewModel {
|
|||
if (NetworkUtil.isOffline()) {
|
||||
setFavoriteOffline();
|
||||
} else {
|
||||
setFavoriteOnline();
|
||||
setFavoriteOnline(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -83,7 +90,6 @@ public class AlbumBottomSheetViewModel extends AndroidViewModel {
|
|||
favoriteRepository.unstar(null, album.getId(), null, new StarCallback() {
|
||||
@Override
|
||||
public void onError() {
|
||||
// album.setStarred(new Date());
|
||||
favoriteRepository.starLater(null, album.getId(), null, false);
|
||||
}
|
||||
});
|
||||
|
|
@ -96,15 +102,31 @@ public class AlbumBottomSheetViewModel extends AndroidViewModel {
|
|||
album.setStarred(new Date());
|
||||
}
|
||||
|
||||
private void setFavoriteOnline() {
|
||||
private void setFavoriteOnline(Context context) {
|
||||
favoriteRepository.star(null, album.getId(), null, new StarCallback() {
|
||||
@Override
|
||||
public void onError() {
|
||||
// album.setStarred(null);
|
||||
favoriteRepository.starLater(null, album.getId(), null, true);
|
||||
}
|
||||
});
|
||||
|
||||
album.setStarred(new Date());
|
||||
if (Preferences.isStarredAlbumsSyncEnabled()) {
|
||||
AlbumRepository albumRepository = new AlbumRepository();
|
||||
MutableLiveData<List<Child>> tracksLiveData = albumRepository.getAlbumTracks(album.getId());
|
||||
|
||||
tracksLiveData.observeForever(new Observer<List<Child>>() {
|
||||
@Override
|
||||
public void onChanged(List<Child> songs) {
|
||||
if (songs != null && !songs.isEmpty()) {
|
||||
DownloadUtil.getDownloadTracker(context).download(
|
||||
MappingUtil.mapDownloads(songs),
|
||||
songs.stream().map(Download::new).collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
tracksLiveData.removeObserver(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
private final PlaylistRepository playlistRepository;
|
||||
private final SharingRepository sharingRepository;
|
||||
|
||||
private final StarredAlbumsSyncViewModel albumsSyncViewModel;
|
||||
|
||||
private final MutableLiveData<List<Child>> dicoverSongSample = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<AlbumID3>> newReleasedAlbum = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Child>> starredTracksSample = new MutableLiveData<>(null);
|
||||
|
|
@ -82,6 +84,8 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
playlistRepository = new PlaylistRepository();
|
||||
sharingRepository = new SharingRepository();
|
||||
|
||||
albumsSyncViewModel = new StarredAlbumsSyncViewModel(application);
|
||||
|
||||
setOfflineFavorite();
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +170,10 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
return starredAlbums;
|
||||
}
|
||||
|
||||
public LiveData<List<Child>> getAllStarredAlbumSongs() {
|
||||
return albumsSyncViewModel.getAllStarredAlbumSongs();
|
||||
}
|
||||
|
||||
public LiveData<List<ArtistID3>> getStarredArtists(LifecycleOwner owner) {
|
||||
if (starredArtists.getValue() == null) {
|
||||
artistRepository.getStarredArtists(true, 20).observe(owner, starredArtists::postValue);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public class PlaylistChooserViewModel extends AndroidViewModel {
|
|||
private final PlaylistRepository playlistRepository;
|
||||
|
||||
private final MutableLiveData<List<Playlist>> playlists = new MutableLiveData<>(null);
|
||||
private ArrayList<Child> toAdd;
|
||||
private ArrayList<Child> toAdd = new ArrayList<>();
|
||||
|
||||
public PlaylistChooserViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
package com.cappielloantonio.tempo.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.cappielloantonio.tempo.repository.AlbumRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class StarredAlbumsSyncViewModel extends AndroidViewModel {
|
||||
private final AlbumRepository albumRepository;
|
||||
|
||||
private final MutableLiveData<List<AlbumID3>> starredAlbums = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Child>> starredAlbumSongs = new MutableLiveData<>(null);
|
||||
|
||||
public StarredAlbumsSyncViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
albumRepository = new AlbumRepository();
|
||||
}
|
||||
|
||||
public LiveData<List<AlbumID3>> getStarredAlbums(LifecycleOwner owner) {
|
||||
albumRepository.getStarredAlbums(false, -1).observe(owner, starredAlbums::postValue);
|
||||
return starredAlbums;
|
||||
}
|
||||
|
||||
public LiveData<List<Child>> getAllStarredAlbumSongs() {
|
||||
albumRepository.getStarredAlbums(false, -1).observeForever(new Observer<List<AlbumID3>>() {
|
||||
@Override
|
||||
public void onChanged(List<AlbumID3> albums) {
|
||||
if (albums != null && !albums.isEmpty()) {
|
||||
collectAllAlbumSongs(albums, starredAlbumSongs::postValue);
|
||||
} else {
|
||||
starredAlbumSongs.postValue(new ArrayList<>());
|
||||
}
|
||||
albumRepository.getStarredAlbums(false, -1).removeObserver(this);
|
||||
}
|
||||
});
|
||||
|
||||
return starredAlbumSongs;
|
||||
}
|
||||
|
||||
public LiveData<List<Child>> getStarredAlbumSongs(Activity activity) {
|
||||
albumRepository.getStarredAlbums(false, -1).observe((LifecycleOwner) activity, albums -> {
|
||||
if (albums != null && !albums.isEmpty()) {
|
||||
collectAllAlbumSongs(albums, starredAlbumSongs::postValue);
|
||||
} else {
|
||||
starredAlbumSongs.postValue(new ArrayList<>());
|
||||
}
|
||||
});
|
||||
return starredAlbumSongs;
|
||||
}
|
||||
|
||||
private void collectAllAlbumSongs(List<AlbumID3> albums, AlbumSongsCallback callback) {
|
||||
List<Child> allSongs = new ArrayList<>();
|
||||
CountDownLatch latch = new CountDownLatch(albums.size());
|
||||
|
||||
for (AlbumID3 album : albums) {
|
||||
LiveData<List<Child>> albumTracks = albumRepository.getAlbumTracks(album.getId());
|
||||
albumTracks.observeForever(new Observer<List<Child>>() {
|
||||
@Override
|
||||
public void onChanged(List<Child> songs) {
|
||||
if (songs != null) {
|
||||
allSongs.addAll(songs);
|
||||
}
|
||||
latch.countDown();
|
||||
|
||||
if (latch.getCount() == 0) {
|
||||
callback.onSongsCollected(allSongs);
|
||||
albumTracks.removeObserver(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private interface AlbumSongsCallback {
|
||||
void onSongsCollected(List<Child> songs);
|
||||
}
|
||||
}
|
||||
|
|
@ -75,6 +75,39 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rating_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="0dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:scaleX="0.8"
|
||||
android:scaleY="0.8"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/vertical_guideline"
|
||||
app:layout_constraintTop_toBottomOf="@+id/player_media_quality_sector">
|
||||
|
||||
<RatingBar
|
||||
android:id="@+id/song_rating_bar"
|
||||
style="?android:attr/ratingBarStyleIndicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:numStars="5"
|
||||
android:stepSize="1"
|
||||
android:rating="0"
|
||||
android:isIndicator="false" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/rating_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:textSize="12sp"
|
||||
android:textColor="?attr/colorOnSurfaceVariant"
|
||||
android:text=""/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_media_title_label"
|
||||
style="@style/HeadlineLarge"
|
||||
|
|
|
|||
14
app/src/main/res/layout/dialog_starred_album_sync.xml
Normal file
14
app/src/main/res/layout/dialog_starred_album_sync.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/starred_album_sync_dialog_summary" />
|
||||
</LinearLayout>
|
||||
|
|
@ -106,6 +106,98 @@
|
|||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Download/Sync starred albums -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/home_sync_starred_albums_card"
|
||||
style="?attr/materialCardViewOutlinedStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingVertical="12dp">
|
||||
|
||||
<!-- Title, secondary and supporting text -->
|
||||
<TextView
|
||||
android:id="@+id/home_sync_starred_albums_title"
|
||||
style="@style/TitleLarge"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/home_sync_starred_albums_title"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
android:textFontWeight="600"
|
||||
app:layout_constraintEnd_toStartOf="@id/vertical_guideline_albums"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_sync_starred_albums_subtitle"
|
||||
style="@style/TitleMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/home_sync_starred_albums_subtitle"
|
||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_sync_starred_albums_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_sync_starred_albums_to_sync"
|
||||
style="@style/TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:text="@string/home_sync_starred_albums_subtitle"
|
||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_sync_starred_albums_subtitle" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="end"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_sync_starred_albums_to_sync">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/home_sync_starred_albums_cancel"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/home_sync_starred_cancel" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/home_sync_starred_albums_download"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/home_sync_starred_download" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/vertical_guideline_albums"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.90" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Discover music -->
|
||||
<LinearLayout
|
||||
android:id="@+id/home_discover_sector"
|
||||
|
|
|
|||
|
|
@ -11,4 +11,9 @@
|
|||
android:icon="@drawable/ic_add"
|
||||
android:title="@string/menu_add_to_playlist_button"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_rate_album"
|
||||
android:icon="@drawable/ic_add"
|
||||
android:title="@string/menu_rate_album"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
12
app/src/main/res/menu/artist_list_menu.xml
Normal file
12
app/src/main/res/menu/artist_list_menu.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_search"
|
||||
android:title="@string/search_title_artist"
|
||||
android:icon="@drawable/ic_search"
|
||||
app:showAsAction="ifRoom|collapseActionView"
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView" />
|
||||
|
||||
</menu>
|
||||
|
|
@ -90,6 +90,7 @@
|
|||
<string name="exo_download_notification_channel_name">Téléchargements</string>
|
||||
<string name="filter_info_selection">Sélectionnez deux filtres ou plus</string>
|
||||
<string name="filter_title">Filtrer</string>
|
||||
<string name="filter_artist">Filtrer par artiste</string>
|
||||
<string name="filter_title_expanded">Filtrer par genre</string>
|
||||
<string name="generic_list_page_count">(%1$d)</string>
|
||||
<string name="generic_list_page_count_unknown">(+%1$d)</string>
|
||||
|
|
@ -162,6 +163,7 @@
|
|||
<string name="menu_add_button">Ajouter</string>
|
||||
<string name="menu_add_to_playlist_button">Ajouter à une playlist</string>
|
||||
<string name="menu_download_all_button">Télécharger tout</string>
|
||||
<string name="menu_rate_album">Noter l\'album</string>
|
||||
<string name="menu_download_label">Téléchargé</string>
|
||||
<string name="menu_filter_all">Tout</string>
|
||||
<string name="menu_filter_download">Téléchargé</string>
|
||||
|
|
@ -190,7 +192,11 @@
|
|||
<string name="menu_sort_year">Année</string>
|
||||
<string name="player_playback_speed">%1$.2fx</string>
|
||||
<string name="player_queue_clean_all_button">Vider la file d\'attente</string>
|
||||
<string name="player_queue_save_queue_success">File d\'attente sauvegardée</string>
|
||||
<string name="player_server_priority">Priorité serveur</string>
|
||||
<string name="player_unknown_format">Format inconnu</string>
|
||||
<string name="player_transcoding">Transcodage</string>
|
||||
<string name="player_transcoding_requested">demandé</string>
|
||||
<string name="playlist_catalogue_title">Catalogue des Playlists</string>
|
||||
<string name="playlist_catalogue_title_expanded">Parcourir les playlists</string>
|
||||
<string name="playlist_chooser_dialog_empty">Pas de playlist</string>
|
||||
|
|
@ -299,13 +305,15 @@
|
|||
<string name="settings_max_bitrate_download">Débit binaire pour les téléchargements</string>
|
||||
<string name="settings_max_bitrate_mobile">Débit binaire en données mobile</string>
|
||||
<string name="settings_max_bitrate_wifi">Débit binaire en Wi-Fi</string>
|
||||
<string name="settings_media_cache">Taille du cache des fichiers audios</string>
|
||||
<string name="settings_media_cache">Taille du cache des fichiers audio</string>
|
||||
<string name="settings_music_directory">Afficher les dossiers</string>
|
||||
<string name="settings_music_directory_summary">Si activé, rend possible la navigation dans les répertoires. À noter que pour que la navigation dans les dossiers fonctionne correctement, le serveur doit supporter cette fonctionnalité.</string>
|
||||
<string name="settings_podcast">Voir les podcasts</string>
|
||||
<string name="settings_podcast_summary">Si activé, rend visible la section Podcast</string>
|
||||
<string name="settings_podcast_summary">Si activé, rend visible la section Podcast. Redémarrez l\'application pour appliquer ce paramètre.</string>
|
||||
<string name="settings_audio_quality">Afficher la qualité audio</string>
|
||||
<string name="settings_audio_quality_summary">Le débit binaire et le format audio seront affichés pour chaque piste.</string>
|
||||
<string name="settings_song_rating">Afficher la note de la piste</string>
|
||||
<string name="settings_song_rating_summary">Si activé, rend visible la note de la piste sur sa page\n\n*Nécessite le redémarrage de l\'application</string>
|
||||
<string name="settings_item_rating">Afficher la note</string>
|
||||
<string name="settings_item_rating_summary">Si activé, la note et le statut de mise en favori de l\'élément seront affichés.</string>
|
||||
<string name="settings_queue_syncing_countdown">Minuteur de synchronisation</string>
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@
|
|||
<string name="exo_download_notification_channel_name">Downloads</string>
|
||||
<string name="filter_info_selection">Select two or more filters</string>
|
||||
<string name="filter_title">Filter</string>
|
||||
<string name="filter_artist">Filter artists</string>
|
||||
<string name="filter_title_expanded">Filter Genres</string>
|
||||
<string name="generic_list_page_count">(%1$d)</string>
|
||||
<string name="generic_list_page_count_unknown">(+%1$d)</string>
|
||||
|
|
@ -116,6 +117,8 @@
|
|||
<string name="home_sync_starred_download">Download</string>
|
||||
<string name="home_sync_starred_subtitle">Downloading these tracks may involve significant data usage</string>
|
||||
<string name="home_sync_starred_title">Looks like there are some starred tracks to sync</string>
|
||||
<string name="home_sync_starred_albums_title">Sync Starred Albums</string>
|
||||
<string name="home_sync_starred_albums_subtitle">Albums marked with a star will be available offline</string>
|
||||
<string name="home_title_best_of">Best of</string>
|
||||
<string name="home_title_discovery">Discovery</string>
|
||||
<string name="home_title_discovery_shuffle_all_button">Shuffle all</string>
|
||||
|
|
@ -164,6 +167,7 @@
|
|||
<string name="menu_add_button">Add</string>
|
||||
<string name="menu_add_to_playlist_button">Add to playlist</string>
|
||||
<string name="menu_download_all_button">Download all</string>
|
||||
<string name="menu_rate_album">Rate album</string>
|
||||
<string name="menu_download_label">Download</string>
|
||||
<string name="menu_filter_all">All</string>
|
||||
<string name="menu_filter_download">Downloaded</string>
|
||||
|
|
@ -312,6 +316,8 @@
|
|||
<string name="settings_podcast_summary">If enabled, show the podcast section. Restart the app for it to take full effect.</string>
|
||||
<string name="settings_audio_quality">Show audio quality</string>
|
||||
<string name="settings_audio_quality_summary">The bitrate and audio format will be shown for each audio track.</string>
|
||||
<string name="settings_song_rating">Show song star rating</string>
|
||||
<string name="settings_song_rating_summary">If enabled, hides 5 star rating for track on song page\n\n*Requires App restart</string>
|
||||
<string name="settings_item_rating">Show item rating</string>
|
||||
<string name="settings_item_rating_summary">If enabled, the item\'s rating and whether it is marked as a favorite will be displayed.</string>
|
||||
<string name="settings_queue_syncing_countdown">Sync timer</string>
|
||||
|
|
@ -340,6 +346,8 @@
|
|||
<string name="settings_summary_transcoding">Priority given to the transcoding mode. If set to \"Direct play\" the bitrate of the file will not be changed.</string>
|
||||
<string name="settings_summary_transcoding_download">Download transcoded media. If enabled, the download endpoint will not be used, but the following settings. \n\n If \"Transcode format for donwloads\" is set to \"Direct download\" the bitrate of the file will not be changed.</string>
|
||||
<string name="settings_summary_transcoding_estimate_content_length">When the file is transcoded on the fly, the client usually does not show the track length. It is possible to request the servers that support the functionality to estimate the duration of the track being played, but the response times may take longer.</string>
|
||||
<string name="settings_sync_starred_albums_for_offline_use_summary">If enabled, starred albums will be downloaded for offline use.</string>
|
||||
<string name="settings_sync_starred_albums_for_offline_use_title">Sync starred albums for offline use</string>
|
||||
<string name="settings_sync_starred_tracks_for_offline_use_summary">If enabled, starred tracks will be downloaded for offline use.</string>
|
||||
<string name="settings_sync_starred_tracks_for_offline_use_title">Sync starred tracks for offline use</string>
|
||||
<string name="settings_theme">Theme</string>
|
||||
|
|
@ -393,8 +401,10 @@
|
|||
<string name="starred_sync_dialog_negative_button">Cancel</string>
|
||||
<string name="starred_sync_dialog_neutral_button">Continue</string>
|
||||
<string name="starred_sync_dialog_positive_button">Continue and download</string>
|
||||
<string name="starred_sync_dialog_summary">Downloading starry tracks may require a large amount of data.</string>
|
||||
<string name="starred_sync_dialog_summary">Downloading starred tracks may require a large amount of data.</string>
|
||||
<string name="starred_sync_dialog_title">Sync starred tracks</string>
|
||||
<string name="starred_album_sync_dialog_summary">Downloading starred albums may require a large amount of data.</string>
|
||||
<string name="starred_album_sync_dialog_title">Sync starred albums</string>
|
||||
<string name="streaming_cache_storage_dialog_sub_summary">For the changes to take effect, restart the app.</string>
|
||||
<string name="streaming_cache_storage_dialog_summary">Changing the destination of cached files from one storage to another may result in the deletion of any previously cached files in the other storage.</string>
|
||||
<string name="streaming_cache_storage_dialog_title">Select storage option</string>
|
||||
|
|
@ -429,4 +439,8 @@
|
|||
<string name="undraw_page">unDraw</string>
|
||||
<string name="undraw_thanks">A special thanks goes to unDraw without whose illustrations we could not have made this application more beautiful.</string>
|
||||
<string name="undraw_url">https://undraw.co/</string>
|
||||
<plurals name="home_sync_starred_albums_count">
|
||||
<item quantity="one">%d album to sync</item>
|
||||
<item quantity="other">%d albums to sync</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -57,6 +57,12 @@
|
|||
android:summary="@string/settings_audio_quality_summary"
|
||||
android:key="audio_quality_per_item" />
|
||||
|
||||
<SwitchPreference
|
||||
android:title="@string/settings_song_rating"
|
||||
android:defaultValue="false"
|
||||
android:summary="@string/settings_song_rating_summary"
|
||||
android:key="song_rating_per_item" />
|
||||
|
||||
<SwitchPreference
|
||||
android:title="@string/settings_item_rating"
|
||||
android:defaultValue="false"
|
||||
|
|
@ -133,6 +139,12 @@
|
|||
android:summary="@string/settings_sync_starred_tracks_for_offline_use_summary"
|
||||
android:key="sync_starred_tracks_for_offline_use" />
|
||||
|
||||
<SwitchPreference
|
||||
android:title="@string/settings_sync_starred_albums_for_offline_use_title"
|
||||
android:defaultValue="false"
|
||||
android:summary="@string/settings_sync_starred_albums_for_offline_use_summary"
|
||||
android:key="sync_starred_albums_for_offline_use" />
|
||||
|
||||
<ListPreference
|
||||
app:defaultValue="1"
|
||||
app:dialogTitle="@string/settings_buffering_strategy"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue