Merge branch 'playlist-duplicates' into SinTan1729-skip-duplicates

This commit is contained in:
eddyizm 2025-10-06 21:49:05 -07:00
commit ccce01a61b
No known key found for this signature in database
GPG key ID: CF5F671829E8158A
8 changed files with 83 additions and 60 deletions

View file

@ -81,6 +81,9 @@ public class PlaylistRepository {
} }
public void addSongToPlaylist(String playlistId, ArrayList<String> songsId) { public void addSongToPlaylist(String playlistId, ArrayList<String> songsId) {
if (songsId.isEmpty()) {
Toast.makeText(App.getContext(), App.getContext().getString(R.string.playlist_chooser_dialog_toast_all_skipped), Toast.LENGTH_SHORT).show();
} else{
App.getSubsonicClientInstance(false) App.getSubsonicClientInstance(false)
.getPlaylistClient() .getPlaylistClient()
.updatePlaylist(playlistId, null, true, songsId, null) .updatePlaylist(playlistId, null, true, songsId, null)
@ -96,6 +99,7 @@ public class PlaylistRepository {
} }
}); });
} }
}
public void createPlaylist(String playlistId, String name, ArrayList<String> songsId) { public void createPlaylist(String playlistId, String name, ArrayList<String> songsId) {
App.getSubsonicClientInstance(false) App.getSubsonicClientInstance(false)
@ -131,23 +135,6 @@ public class PlaylistRepository {
}); });
} }
public void updatePlaylist(String playlistId, String name, boolean isPublic, ArrayList<String> songIdToAdd, ArrayList<Integer> songIndexToRemove) {
App.getSubsonicClientInstance(false)
.getPlaylistClient()
.updatePlaylist(playlistId, name, isPublic, songIdToAdd, songIndexToRemove)
.enqueue(new Callback<ApiResponse>() {
@Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
}
@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
}
});
}
public void deletePlaylist(String playlistId) { public void deletePlaylist(String playlistId) {
App.getSubsonicClientInstance(false) App.getSubsonicClientInstance(false)
.getPlaylistClient() .getPlaylistClient()

View file

@ -27,6 +27,7 @@ public class PlaylistChooserDialog extends DialogFragment implements ClickCallba
private PlaylistDialogHorizontalAdapter playlistDialogHorizontalAdapter; private PlaylistDialogHorizontalAdapter playlistDialogHorizontalAdapter;
@NonNull @NonNull
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
@ -100,8 +101,7 @@ public class PlaylistChooserDialog extends DialogFragment implements ClickCallba
public void onPlaylistClick(Bundle bundle) { public void onPlaylistClick(Bundle bundle) {
if (playlistChooserViewModel.getSongsToAdd() != null && !playlistChooserViewModel.getSongsToAdd().isEmpty()) { if (playlistChooserViewModel.getSongsToAdd() != null && !playlistChooserViewModel.getSongsToAdd().isEmpty()) {
Playlist playlist = bundle.getParcelable(Constants.PLAYLIST_OBJECT); Playlist playlist = bundle.getParcelable(Constants.PLAYLIST_OBJECT);
playlistChooserViewModel.addSongsToPlaylist(playlist.getId()); playlistChooserViewModel.addSongsToPlaylist(this, getDialog(), playlist.getId());
dismiss();
} else { } else {
Toast.makeText(requireContext(), R.string.playlist_chooser_dialog_toast_add_failure, Toast.LENGTH_SHORT).show(); Toast.makeText(requireContext(), R.string.playlist_chooser_dialog_toast_add_failure, Toast.LENGTH_SHORT).show();
} }

View file

@ -71,6 +71,7 @@ object Preferences {
private const val NEXT_UPDATE_CHECK = "next_update_check" private const val NEXT_UPDATE_CHECK = "next_update_check"
private const val CONTINUOUS_PLAY = "continuous_play" private const val CONTINUOUS_PLAY = "continuous_play"
private const val LAST_INSTANT_MIX = "last_instant_mix" private const val LAST_INSTANT_MIX = "last_instant_mix"
private const val ALLOW_PLAYLIST_DUPLICATES = "allow_playlist_duplicates"
private const val EQUALIZER_ENABLED = "equalizer_enabled" private const val EQUALIZER_ENABLED = "equalizer_enabled"
private const val EQUALIZER_BAND_LEVELS = "equalizer_band_levels" private const val EQUALIZER_BAND_LEVELS = "equalizer_band_levels"
private const val MINI_SHUFFLE_BUTTON_VISIBILITY = "mini_shuffle_button_visibility" private const val MINI_SHUFFLE_BUTTON_VISIBILITY = "mini_shuffle_button_visibility"
@ -583,6 +584,19 @@ object Preferences {
) + 5000 < System.currentTimeMillis() ) + 5000 < System.currentTimeMillis()
} }
@JvmStatic
fun setAllowPlaylistDuplicates(allowDuplicates: Boolean) {
return App.getInstance().preferences.edit().putString(
ALLOW_PLAYLIST_DUPLICATES,
allowDuplicates.toString()
).apply()
}
@JvmStatic
fun allowPlaylistDuplicates(): Boolean {
return App.getInstance().preferences.getBoolean(ALLOW_PLAYLIST_DUPLICATES, false)
}
@JvmStatic @JvmStatic
fun setEqualizerEnabled(enabled: Boolean) { fun setEqualizerEnabled(enabled: Boolean) {
App.getInstance().preferences.edit().putBoolean(EQUALIZER_ENABLED, enabled).apply() App.getInstance().preferences.edit().putBoolean(EQUALIZER_ENABLED, enabled).apply()

View file

@ -1,6 +1,8 @@
package com.cappielloantonio.tempo.viewmodel; package com.cappielloantonio.tempo.viewmodel;
import android.app.Application; import android.app.Application;
import android.app.Dialog;
import android.content.SharedPreferences;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.AndroidViewModel;
@ -11,10 +13,10 @@ import androidx.lifecycle.MutableLiveData;
import com.cappielloantonio.tempo.repository.PlaylistRepository; import com.cappielloantonio.tempo.repository.PlaylistRepository;
import com.cappielloantonio.tempo.subsonic.models.Child; import com.cappielloantonio.tempo.subsonic.models.Child;
import com.cappielloantonio.tempo.subsonic.models.Playlist; import com.cappielloantonio.tempo.subsonic.models.Playlist;
import com.cappielloantonio.tempo.util.Preferences;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
public class PlaylistChooserViewModel extends AndroidViewModel { public class PlaylistChooserViewModel extends AndroidViewModel {
@ -34,8 +36,21 @@ public class PlaylistChooserViewModel extends AndroidViewModel {
return playlists; return playlists;
} }
public void addSongsToPlaylist(String playlistId) { public void addSongsToPlaylist(LifecycleOwner owner, Dialog dialog, String playlistId) {
playlistRepository.addSongToPlaylist(playlistId, new ArrayList<>(Lists.transform(toAdd, Child::getId))); List<String> songIds = Lists.transform(toAdd, Child::getId);
if (Preferences.allowPlaylistDuplicates()) {
playlistRepository.addSongToPlaylist(playlistId, new ArrayList<>(songIds));
dialog.dismiss();
} else {
playlistRepository.getPlaylistSongs(playlistId).observe(owner, playlistSongs -> {
if (playlistSongs != null) {
List<String> playlistSongIds = Lists.transform(playlistSongs, Child::getId);
songIds.removeAll(playlistSongIds);
}
playlistRepository.addSongToPlaylist(playlistId, new ArrayList<>(songIds));
dialog.dismiss();
});
}
} }
public void setSongsToAdd(ArrayList<Child> songs) { public void setSongsToAdd(ArrayList<Child> songs) {

View file

@ -19,7 +19,8 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/playlist_dialog_recycler_view" android:id="@+id/playlist_dialog_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:clipToPadding="false" /> android:clipToPadding="false" />
</LinearLayout> </LinearLayout>

View file

@ -304,8 +304,8 @@
<string name="settings_delete_download_storage_summary">Zatwierdzenie nieodwracalnie usunie wszystkie zapisane elementy</string> <string name="settings_delete_download_storage_summary">Zatwierdzenie nieodwracalnie usunie wszystkie zapisane elementy</string>
<string name="settings_delete_download_storage_title">Usuń zapisane elementy</string> <string name="settings_delete_download_storage_title">Usuń zapisane elementy</string>
<string name="settings_download_storage_title">Pamięć do pobierania</string> <string name="settings_download_storage_title">Pamięć do pobierania</string>
<string name="settings_equalizer_summary">Zmień ustawienia audio</string> <string name="settings_system_equalizer_summary">Zmień ustawienia audio</string>
<string name="settings_equalizer_title">Korektor systemowy</string> <string name="settings_system_equalizer_title">Korektor systemowy</string>
<string name="settings_github_link">https://github.com/eddyizm/tempo</string> <string name="settings_github_link">https://github.com/eddyizm/tempo</string>
<string name="settings_github_summary">Śledź tworzenie aplikacji</string> <string name="settings_github_summary">Śledź tworzenie aplikacji</string>
<string name="settings_github_title">GitHub</string> <string name="settings_github_title">GitHub</string>

View file

@ -216,8 +216,9 @@
<string name="playlist_chooser_dialog_negative_button">Cancel</string> <string name="playlist_chooser_dialog_negative_button">Cancel</string>
<string name="playlist_chooser_dialog_neutral_button">Create</string> <string name="playlist_chooser_dialog_neutral_button">Create</string>
<string name="playlist_chooser_dialog_title">Add to a playlist</string> <string name="playlist_chooser_dialog_title">Add to a playlist</string>
<string name="playlist_chooser_dialog_toast_add_success">Added song to playlist</string> <string name="playlist_chooser_dialog_toast_add_success">Added song(s) to playlist</string>
<string name="playlist_chooser_dialog_toast_add_failure">Failed to add song to playlist</string> <string name="playlist_chooser_dialog_toast_add_failure">Failed to add song(s) to playlist</string>
<string name="playlist_chooser_dialog_toast_all_skipped">All songs were skipped as duplicates</string>
<string name="playlist_counted_tracks">%1$d tracks • %2$s</string> <string name="playlist_counted_tracks">%1$d tracks • %2$s</string>
<string name="playlist_duration">Duration • %1$s</string> <string name="playlist_duration">Duration • %1$s</string>
<string name="playlist_editor_dialog_action_delete_toast">Long press to delete</string> <string name="playlist_editor_dialog_action_delete_toast">Long press to delete</string>
@ -284,6 +285,8 @@
<string name="settings_about_summary">Tempo is an open source and lightweight music client for Subsonic, designed and built natively for Android.</string> <string name="settings_about_summary">Tempo is an open source and lightweight music client for Subsonic, designed and built natively for Android.</string>
<string name="settings_about_title">About</string> <string name="settings_about_title">About</string>
<string name="settings_always_on_display">Always on display</string> <string name="settings_always_on_display">Always on display</string>
<string name="settings_allow_playlist_duplicates">Allow adding duplicates to playlist</string>
<string name="settings_allow_playlist_duplicates_summary">If enabled, duplicates won\'t be checked while adding to a playlist.</string>
<string name="settings_audio_transcode_download_format">Transcode format</string> <string name="settings_audio_transcode_download_format">Transcode format</string>
<string name="settings_audio_transcode_download_priority_summary">If enabled, Tempo will not force download the track with the transcode settings below.</string> <string name="settings_audio_transcode_download_priority_summary">If enabled, Tempo will not force download the track with the transcode settings below.</string>
<string name="settings_audio_transcode_download_priority_title">Prioritize server settings used for streaming in downloads</string> <string name="settings_audio_transcode_download_priority_title">Prioritize server settings used for streaming in downloads</string>
@ -371,6 +374,7 @@
<string name="settings_theme">Theme</string> <string name="settings_theme">Theme</string>
<string name="settings_title_data">Data</string> <string name="settings_title_data">Data</string>
<string name="settings_title_general">General</string> <string name="settings_title_general">General</string>
<string name="settings_title_playlist">Playlist</string>
<string name="settings_title_rating">Rating</string> <string name="settings_title_rating">Rating</string>
<string name="settings_title_replay_gain">Replay Gain</string> <string name="settings_title_replay_gain">Replay Gain</string>
<string name="settings_title_scrobble">Scrobble</string> <string name="settings_title_scrobble">Scrobble</string>

View file

@ -2,14 +2,10 @@
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="@string/settings_title_general"> <PreferenceCategory app:title="@string/settings_title_general">
<Preference <Preference
android:key="system_equalizer" android:layout_height="match_parent"
android:title="@string/settings_system_equalizer_title" android:key="equalizer"
android:summary="@string/settings_system_equalizer_summary" /> android:summary="@string/settings_system_equalizer_summary"
android:title="@string/settings_system_equalizer_title" />
<Preference
android:key="app_equalizer"
android:title="@string/settings_app_equalizer"
android:summary="@string/settings_app_equalizer_summary" />
<Preference <Preference
android:key="scan_library" android:key="scan_library"
@ -22,12 +18,14 @@
<PreferenceCategory app:title="@string/settings_title_ui"> <PreferenceCategory app:title="@string/settings_title_ui">
<ListPreference <ListPreference
android:layout_height="match_parent"
app:defaultValue="default" app:defaultValue="default"
app:dialogTitle="@string/settings_language" app:dialogTitle="@string/settings_language"
app:key="language" app:key="language"
app:title="@string/settings_language"/> app:title="@string/settings_language" />
<ListPreference <ListPreference
android:layout_height="wrap_content"
app:defaultValue="default" app:defaultValue="default"
app:dialogTitle="@string/settings_theme" app:dialogTitle="@string/settings_theme"
app:entries="@array/theme_list_titles" app:entries="@array/theme_list_titles"
@ -42,10 +40,11 @@
android:key="always_on_display" /> android:key="always_on_display" />
<SwitchPreference <SwitchPreference
android:title="@string/settings_rounded_corner" android:layout_height="match_parent"
android:defaultValue="true" android:defaultValue="true"
android:key="rounded_corner"
android:summary="@string/settings_rounded_corner_summary" android:summary="@string/settings_rounded_corner_summary"
android:key="rounded_corner" /> android:title="@string/settings_rounded_corner" />
<ListPreference <ListPreference
app:defaultValue="6" app:defaultValue="6"
@ -57,10 +56,11 @@
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<SwitchPreference <SwitchPreference
android:title="@string/settings_audio_quality" android:layout_height="wrap_content"
android:defaultValue="false" android:defaultValue="false"
android:key="audio_quality_per_item"
android:summary="@string/settings_audio_quality_summary" android:summary="@string/settings_audio_quality_summary"
android:key="audio_quality_per_item" /> android:title="@string/settings_audio_quality" />
<SwitchPreference <SwitchPreference
android:title="@string/settings_song_rating" android:title="@string/settings_song_rating"
@ -97,15 +97,17 @@
android:defaultValue="true" android:defaultValue="true"
android:summary="@string/settings_music_directory_summary" android:summary="@string/settings_music_directory_summary"
android:key="music_directory_section_visibility" /> android:key="music_directory_section_visibility" />
<SwitchPreference
android:title="@string/settings_show_mini_shuffle_button"
android:defaultValue="false"
android:summary="@string/settings_show_mini_shuffle_button_summary"
android:key="mini_shuffle_button_visibility" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory app:title="@string/settings_title_playlist">
<SwitchPreference
android:title="@string/settings_allow_playlist_duplicates"
android:defaultValue="false"
android:summary="@string/settings_allow_playlist_duplicates_summary"
android:key="allow_playlist_duplicates" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/settings_title_data"> <PreferenceCategory app:title="@string/settings_title_data">
<ListPreference <ListPreference
app:defaultValue="256" app:defaultValue="256"