mirror of
https://github.com/antebudimir/tempus.git
synced 2026-04-15 16:27:26 +00:00
feat: implemented load queue, adding logging
This commit is contained in:
parent
27f5a47cc9
commit
1ff0b83a19
4 changed files with 92 additions and 25 deletions
|
|
@ -1,8 +1,11 @@
|
||||||
package com.cappielloantonio.tempo.repository;
|
package com.cappielloantonio.tempo.repository;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
import androidx.lifecycle.Observer;
|
||||||
|
|
||||||
import com.cappielloantonio.tempo.App;
|
import com.cappielloantonio.tempo.App;
|
||||||
import com.cappielloantonio.tempo.database.AppDatabase;
|
import com.cappielloantonio.tempo.database.AppDatabase;
|
||||||
|
|
@ -52,6 +55,8 @@ public class QueueRepository {
|
||||||
public MutableLiveData<PlayQueue> getPlayQueue() {
|
public MutableLiveData<PlayQueue> getPlayQueue() {
|
||||||
MutableLiveData<PlayQueue> playQueue = new MutableLiveData<>();
|
MutableLiveData<PlayQueue> playQueue = new MutableLiveData<>();
|
||||||
|
|
||||||
|
Log.d(TAG, "Getting play queue from server...");
|
||||||
|
|
||||||
App.getSubsonicClientInstance(false)
|
App.getSubsonicClientInstance(false)
|
||||||
.getBookmarksClient()
|
.getBookmarksClient()
|
||||||
.getPlayQueue()
|
.getPlayQueue()
|
||||||
|
|
@ -59,12 +64,19 @@ public class QueueRepository {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||||
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getPlayQueue() != null) {
|
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getPlayQueue() != null) {
|
||||||
playQueue.setValue(response.body().getSubsonicResponse().getPlayQueue());
|
PlayQueue serverQueue = response.body().getSubsonicResponse().getPlayQueue();
|
||||||
|
Log.d(TAG, "Server returned play queue with " +
|
||||||
|
(serverQueue.getEntries() != null ? serverQueue.getEntries().size() : 0) + " items");
|
||||||
|
playQueue.setValue(serverQueue);
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Server returned no play queue");
|
||||||
|
playQueue.setValue(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||||
|
Log.e(TAG, "Failed to get play queue", t);
|
||||||
playQueue.setValue(null);
|
playQueue.setValue(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -73,18 +85,24 @@ public class QueueRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void savePlayQueue(List<String> ids, String current, long position) {
|
public void savePlayQueue(List<String> ids, String current, long position) {
|
||||||
|
Log.d(TAG, "Saving play queue to server - Items: " + ids.size() + ", Current: " + current);
|
||||||
|
|
||||||
App.getSubsonicClientInstance(false)
|
App.getSubsonicClientInstance(false)
|
||||||
.getBookmarksClient()
|
.getBookmarksClient()
|
||||||
.savePlayQueue(ids, current, position)
|
.savePlayQueue(ids, current, position)
|
||||||
.enqueue(new Callback<ApiResponse>() {
|
.enqueue(new Callback<ApiResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
Log.d(TAG, "Play queue saved successfully");
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Play queue save failed with code: " + response.code());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||||
|
Log.e(TAG, "Play queue save failed", t);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -123,10 +141,9 @@ public class QueueRepository {
|
||||||
|
|
||||||
private boolean isMediaInQueue(List<Queue> queue, Child media) {
|
private boolean isMediaInQueue(List<Queue> queue, Child media) {
|
||||||
if (queue == null || media == null) return false;
|
if (queue == null || media == null) return false;
|
||||||
|
return queue.stream().anyMatch(queueItem ->
|
||||||
return queue.stream().anyMatch(queueItem ->
|
queueItem != null && media.getId() != null &&
|
||||||
queueItem != null && media.getId() != null &&
|
queueItem.getId().equals(media.getId())
|
||||||
queueItem.getId().equals(media.getId())
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,8 +163,8 @@ public class QueueRepository {
|
||||||
List<Child> filteredToAdd = toAdd;
|
List<Child> filteredToAdd = toAdd;
|
||||||
final List<Queue> finalMedia = media;
|
final List<Queue> finalMedia = media;
|
||||||
filteredToAdd = toAdd.stream()
|
filteredToAdd = toAdd.stream()
|
||||||
.filter(child -> !isMediaInQueue(finalMedia, child))
|
.filter(child -> !isMediaInQueue(finalMedia, child))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
for (int i = 0; i < filteredToAdd.size(); i++) {
|
for (int i = 0; i < filteredToAdd.size(); i++) {
|
||||||
Queue queueItem = new Queue(filteredToAdd.get(i));
|
Queue queueItem = new Queue(filteredToAdd.get(i));
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.cappielloantonio.tempo.ui.fragment;
|
||||||
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
@ -11,6 +12,7 @@ import android.widget.Toast;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
import androidx.lifecycle.Observer;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.session.MediaBrowser;
|
import androidx.media3.session.MediaBrowser;
|
||||||
import androidx.media3.session.SessionToken;
|
import androidx.media3.session.SessionToken;
|
||||||
|
|
@ -23,9 +25,11 @@ import com.cappielloantonio.tempo.interfaces.ClickCallback;
|
||||||
import com.cappielloantonio.tempo.service.MediaManager;
|
import com.cappielloantonio.tempo.service.MediaManager;
|
||||||
import com.cappielloantonio.tempo.service.MediaService;
|
import com.cappielloantonio.tempo.service.MediaService;
|
||||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||||
|
import com.cappielloantonio.tempo.subsonic.models.PlayQueue;
|
||||||
import com.cappielloantonio.tempo.ui.adapter.PlayerSongQueueAdapter;
|
import com.cappielloantonio.tempo.ui.adapter.PlayerSongQueueAdapter;
|
||||||
import com.cappielloantonio.tempo.ui.dialog.PlaylistChooserDialog;
|
import com.cappielloantonio.tempo.ui.dialog.PlaylistChooserDialog;
|
||||||
import com.cappielloantonio.tempo.util.Constants;
|
import com.cappielloantonio.tempo.util.Constants;
|
||||||
|
import com.cappielloantonio.tempo.util.Preferences;
|
||||||
import com.cappielloantonio.tempo.viewmodel.PlaybackViewModel;
|
import com.cappielloantonio.tempo.viewmodel.PlaybackViewModel;
|
||||||
import com.cappielloantonio.tempo.viewmodel.PlayerBottomSheetViewModel;
|
import com.cappielloantonio.tempo.viewmodel.PlayerBottomSheetViewModel;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
@ -46,7 +50,6 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||||
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabClearQueue;
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabClearQueue;
|
||||||
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabShuffleQueue;
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabShuffleQueue;
|
||||||
|
|
||||||
|
|
||||||
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabSaveToPlaylist;
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabSaveToPlaylist;
|
||||||
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabDownloadAll;
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabDownloadAll;
|
||||||
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabLoadQueue;
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabLoadQueue;
|
||||||
|
|
@ -85,6 +88,11 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||||
fabDownloadAll.setOnClickListener(v -> handleDownloadAllClick());
|
fabDownloadAll.setOnClickListener(v -> handleDownloadAllClick());
|
||||||
fabLoadQueue.setOnClickListener(v -> handleLoadQueueClick());
|
fabLoadQueue.setOnClickListener(v -> handleLoadQueueClick());
|
||||||
|
|
||||||
|
// Hide Load Queue FAB if sync is disabled
|
||||||
|
if (!Preferences.isSyncronizationEnabled()) {
|
||||||
|
fabLoadQueue.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
initQueueRecyclerView();
|
initQueueRecyclerView();
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
|
|
@ -244,9 +252,12 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||||
private void toggleFabMenu() {
|
private void toggleFabMenu() {
|
||||||
if (isMenuOpen) {
|
if (isMenuOpen) {
|
||||||
// CLOSE MENU (Reverse order for visual effect)
|
// CLOSE MENU (Reverse order for visual effect)
|
||||||
closeFab(fabSaveToPlaylist, 5);
|
if (Preferences.isSyncronizationEnabled()) {
|
||||||
closeFab(fabDownloadAll, 4);
|
closeFab(fabLoadQueue, 4);
|
||||||
closeFab(fabLoadQueue, 2);
|
}
|
||||||
|
closeFab(fabSaveToPlaylist, 3);
|
||||||
|
closeFab(fabDownloadAll, 2);
|
||||||
|
|
||||||
closeFab(fabClearQueue, 1);
|
closeFab(fabClearQueue, 1);
|
||||||
closeFab(fabShuffleQueue, 0);
|
closeFab(fabShuffleQueue, 0);
|
||||||
|
|
||||||
|
|
@ -255,10 +266,11 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||||
// OPEN MENU (lowest index at bottom)
|
// OPEN MENU (lowest index at bottom)
|
||||||
openFab(fabShuffleQueue, 0);
|
openFab(fabShuffleQueue, 0);
|
||||||
openFab(fabClearQueue, 1);
|
openFab(fabClearQueue, 1);
|
||||||
openFab(fabLoadQueue, 2);
|
openFab(fabDownloadAll, 2);
|
||||||
openFab(fabDownloadAll, 4);
|
openFab(fabSaveToPlaylist, 3);
|
||||||
openFab(fabSaveToPlaylist, 5);
|
if (Preferences.isSyncronizationEnabled()) {
|
||||||
|
openFab(fabLoadQueue, 4);
|
||||||
|
}
|
||||||
fabMenuToggle.animate().rotation(45f).setDuration(ANIMATION_DURATION).start();
|
fabMenuToggle.animate().rotation(45f).setDuration(ANIMATION_DURATION).start();
|
||||||
}
|
}
|
||||||
isMenuOpen = !isMenuOpen;
|
isMenuOpen = !isMenuOpen;
|
||||||
|
|
@ -375,10 +387,46 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||||
toggleFabMenu();
|
toggleFabMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void handleLoadQueueClick() {
|
private void handleLoadQueueClick() {
|
||||||
Log.d(TAG, "Load Queue Clicked! (Placeholder)");
|
Log.d(TAG, "Load Queue Clicked!");
|
||||||
toggleFabMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Double-check that sync is enabled (shouldn't be visible if disabled, but just in case)
|
||||||
|
if (!Preferences.isSyncronizationEnabled()) {
|
||||||
|
toggleFabMenu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerBottomSheetViewModel playerBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(PlayerBottomSheetViewModel.class);
|
||||||
|
|
||||||
|
playerBottomSheetViewModel.getPlayQueue().observe(getViewLifecycleOwner(), new Observer<PlayQueue>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(PlayQueue playQueue) {
|
||||||
|
playerBottomSheetViewModel.getPlayQueue().removeObserver(this);
|
||||||
|
|
||||||
|
if (playQueue != null && playQueue.getEntries() != null && !playQueue.getEntries().isEmpty()) {
|
||||||
|
int currentIndex = 0;
|
||||||
|
for (int i = 0; i < playQueue.getEntries().size(); i++) {
|
||||||
|
if (playQueue.getEntries().get(i).getId().equals(playQueue.getCurrent())) {
|
||||||
|
currentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaManager.startQueue(mediaBrowserListenableFuture, playQueue.getEntries(), currentIndex);
|
||||||
|
|
||||||
|
Toast.makeText(requireContext(), "Queue loaded", Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(requireContext(), "No saved queue found", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleFabMenu();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
new Handler().postDelayed(() -> {
|
||||||
|
if (isMenuOpen) {
|
||||||
|
toggleFabMenu();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package com.cappielloantonio.tempo.viewmodel;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.OptIn;
|
import androidx.annotation.OptIn;
|
||||||
|
|
@ -12,6 +13,7 @@ import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.lifecycle.Observer;
|
import androidx.lifecycle.Observer;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
import androidx.media3.session.MediaBrowser;
|
||||||
|
|
||||||
import com.cappielloantonio.tempo.interfaces.StarCallback;
|
import com.cappielloantonio.tempo.interfaces.StarCallback;
|
||||||
import com.cappielloantonio.tempo.model.Download;
|
import com.cappielloantonio.tempo.model.Download;
|
||||||
|
|
@ -291,13 +293,13 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
||||||
List<String> ids = queue.stream().map(Child::getId).collect(Collectors.toList());
|
List<String> ids = queue.stream().map(Child::getId).collect(Collectors.toList());
|
||||||
|
|
||||||
if (media != null) {
|
if (media != null) {
|
||||||
queueRepository.savePlayQueue(ids, media.getId(), 0);
|
// TODO: We need to get the actual playback position here
|
||||||
|
Log.d(TAG, "Saving play queue - Current: " + media.getId() + ", Items: " + ids.size());
|
||||||
|
queueRepository.savePlayQueue(ids, media.getId(), 0); // Still hardcoded to 0 for now
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void observeCachedLyrics(LifecycleOwner owner, String songId) {
|
private void observeCachedLyrics(LifecycleOwner owner, String songId) {
|
||||||
if (TextUtils.isEmpty(songId)) {
|
if (TextUtils.isEmpty(songId)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:text="Load Queue (TODO)"
|
android:text="Load Queue"
|
||||||
tools:ignore="HardcodedText"
|
tools:ignore="HardcodedText"
|
||||||
app:icon="@android:drawable/ic_menu_revert" />
|
app:icon="@android:drawable/ic_menu_revert" />
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue