mirror of
https://github.com/antebudimir/tempus.git
synced 2026-04-15 16:27:26 +00:00
wip: added fab, need to implement actions
This commit is contained in:
parent
97d1b408e1
commit
38fb2c69f1
2 changed files with 228 additions and 40 deletions
|
|
@ -39,6 +39,20 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||||
|
|
||||||
private InnerFragmentPlayerQueueBinding bind;
|
private InnerFragmentPlayerQueueBinding bind;
|
||||||
|
|
||||||
|
private com.google.android.material.floatingactionbutton.FloatingActionButton fabMenuToggle;
|
||||||
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabClearQueue;
|
||||||
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabShuffleQueue;
|
||||||
|
|
||||||
|
|
||||||
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabSaveToPlaylist;
|
||||||
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabDownloadAll;
|
||||||
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabSaveQueue;
|
||||||
|
private com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton fabLoadQueue;
|
||||||
|
|
||||||
|
private boolean isMenuOpen = false;
|
||||||
|
private final int ANIMATION_DURATION = 250;
|
||||||
|
private final float FAB_VERTICAL_SPACING_DP = 70f;
|
||||||
|
|
||||||
private PlayerBottomSheetViewModel playerBottomSheetViewModel;
|
private PlayerBottomSheetViewModel playerBottomSheetViewModel;
|
||||||
private PlaybackViewModel playbackViewModel;
|
private PlaybackViewModel playbackViewModel;
|
||||||
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
||||||
|
|
@ -53,6 +67,24 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||||
playerBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(PlayerBottomSheetViewModel.class);
|
playerBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(PlayerBottomSheetViewModel.class);
|
||||||
playbackViewModel = new ViewModelProvider(requireActivity()).get(PlaybackViewModel.class);
|
playbackViewModel = new ViewModelProvider(requireActivity()).get(PlaybackViewModel.class);
|
||||||
|
|
||||||
|
fabMenuToggle = bind.fabMenuToggle;
|
||||||
|
fabClearQueue = bind.fabClearQueue;
|
||||||
|
fabShuffleQueue = bind.fabShuffleQueue;
|
||||||
|
|
||||||
|
fabSaveToPlaylist = bind.fabSaveToPlaylist;
|
||||||
|
fabDownloadAll = bind.fabDownloadAll;
|
||||||
|
fabSaveQueue = bind.fabSaveQueue;
|
||||||
|
fabLoadQueue = bind.fabLoadQueue;
|
||||||
|
|
||||||
|
fabMenuToggle.setOnClickListener(v -> toggleFabMenu());
|
||||||
|
fabClearQueue.setOnClickListener(v -> handleClearQueueClick());
|
||||||
|
fabShuffleQueue.setOnClickListener(v -> handleShuffleQueueClick());
|
||||||
|
|
||||||
|
fabSaveToPlaylist.setOnClickListener(v -> handleSaveToPlaylistClick());
|
||||||
|
fabDownloadAll.setOnClickListener(v -> handleDownloadAllClick());
|
||||||
|
fabSaveQueue.setOnClickListener(v -> handleSaveQueueClick());
|
||||||
|
fabLoadQueue.setOnClickListener(v -> handleLoadQueueClick());
|
||||||
|
|
||||||
initQueueRecyclerView();
|
initQueueRecyclerView();
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
|
|
@ -109,8 +141,8 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||||
mediaBrowserListenableFuture.addListener(() -> {
|
mediaBrowserListenableFuture.addListener(() -> {
|
||||||
try {
|
try {
|
||||||
MediaBrowser mediaBrowser = mediaBrowserListenableFuture.get();
|
MediaBrowser mediaBrowser = mediaBrowserListenableFuture.get();
|
||||||
initShuffleButton(mediaBrowser);
|
// initShuffleButton(mediaBrowser);
|
||||||
initCleanButton(mediaBrowser);
|
// initCleanButton(mediaBrowser);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
@ -188,45 +220,45 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||||
}).attachToRecyclerView(bind.playerQueueRecyclerView);
|
}).attachToRecyclerView(bind.playerQueueRecyclerView);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initShuffleButton(MediaBrowser mediaBrowser) {
|
// private void initShuffleButton(MediaBrowser mediaBrowser) {
|
||||||
bind.playerShuffleQueueFab.setOnClickListener(view -> {
|
// bind.playerShuffleQueueFab.setOnClickListener(view -> {
|
||||||
int startPosition = mediaBrowser.getCurrentMediaItemIndex() + 1;
|
// int startPosition = mediaBrowser.getCurrentMediaItemIndex() + 1;
|
||||||
int endPosition = playerSongQueueAdapter.getItems().size() - 1;
|
// int endPosition = playerSongQueueAdapter.getItems().size() - 1;
|
||||||
|
|
||||||
if (startPosition < endPosition) {
|
// if (startPosition < endPosition) {
|
||||||
ArrayList<Integer> pool = new ArrayList<>();
|
// ArrayList<Integer> pool = new ArrayList<>();
|
||||||
|
|
||||||
for (int i = startPosition; i <= endPosition; i++) {
|
// for (int i = startPosition; i <= endPosition; i++) {
|
||||||
pool.add(i);
|
// pool.add(i);
|
||||||
}
|
// }
|
||||||
|
|
||||||
while (pool.size() >= 2) {
|
// while (pool.size() >= 2) {
|
||||||
int fromPosition = (int) (Math.random() * (pool.size()));
|
// int fromPosition = (int) (Math.random() * (pool.size()));
|
||||||
int positionA = pool.get(fromPosition);
|
// int positionA = pool.get(fromPosition);
|
||||||
pool.remove(fromPosition);
|
// pool.remove(fromPosition);
|
||||||
|
|
||||||
int toPosition = (int) (Math.random() * (pool.size()));
|
// int toPosition = (int) (Math.random() * (pool.size()));
|
||||||
int positionB = pool.get(toPosition);
|
// int positionB = pool.get(toPosition);
|
||||||
pool.remove(toPosition);
|
// pool.remove(toPosition);
|
||||||
|
|
||||||
Collections.swap(playerSongQueueAdapter.getItems(), positionA, positionB);
|
// Collections.swap(playerSongQueueAdapter.getItems(), positionA, positionB);
|
||||||
bind.playerQueueRecyclerView.getAdapter().notifyItemMoved(positionA, positionB);
|
// bind.playerQueueRecyclerView.getAdapter().notifyItemMoved(positionA, positionB);
|
||||||
}
|
// }
|
||||||
|
|
||||||
MediaManager.shuffle(mediaBrowserListenableFuture, playerSongQueueAdapter.getItems(), startPosition, endPosition);
|
// MediaManager.shuffle(mediaBrowserListenableFuture, playerSongQueueAdapter.getItems(), startPosition, endPosition);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
private void initCleanButton(MediaBrowser mediaBrowser) {
|
// private void initCleanButton(MediaBrowser mediaBrowser) {
|
||||||
bind.playerCleanQueueButton.setOnClickListener(view -> {
|
// bind.playerCleanQueueButton.setOnClickListener(view -> {
|
||||||
int startPosition = mediaBrowser.getCurrentMediaItemIndex() + 1;
|
// int startPosition = mediaBrowser.getCurrentMediaItemIndex() + 1;
|
||||||
int endPosition = playerSongQueueAdapter.getItems().size();
|
// int endPosition = playerSongQueueAdapter.getItems().size();
|
||||||
|
|
||||||
MediaManager.removeRange(mediaBrowserListenableFuture, playerSongQueueAdapter.getItems(), startPosition, endPosition);
|
// MediaManager.removeRange(mediaBrowserListenableFuture, playerSongQueueAdapter.getItems(), startPosition, endPosition);
|
||||||
bind.playerQueueRecyclerView.getAdapter().notifyItemRangeRemoved(startPosition, endPosition);
|
// bind.playerQueueRecyclerView.getAdapter().notifyItemRangeRemoved(startPosition, endPosition);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
private void updateNowPlayingItem() {
|
private void updateNowPlayingItem() {
|
||||||
playerSongQueueAdapter.notifyDataSetChanged();
|
playerSongQueueAdapter.notifyDataSetChanged();
|
||||||
|
|
@ -259,4 +291,90 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
|
||||||
playerSongQueueAdapter.setPlaybackState(id, playing != null && playing);
|
playerSongQueueAdapter.setPlaybackState(id, playing != null && playing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the visibility and animates all six secondary FABs.
|
||||||
|
*/
|
||||||
|
private void toggleFabMenu() {
|
||||||
|
if (isMenuOpen) {
|
||||||
|
// CLOSE MENU (Reverse order for visual effect)
|
||||||
|
closeFab(fabSaveToPlaylist, 5);
|
||||||
|
closeFab(fabDownloadAll, 4);
|
||||||
|
closeFab(fabSaveQueue, 3);
|
||||||
|
closeFab(fabLoadQueue, 2);
|
||||||
|
closeFab(fabClearQueue, 1);
|
||||||
|
closeFab(fabShuffleQueue, 0);
|
||||||
|
|
||||||
|
fabMenuToggle.animate().rotation(0f).setDuration(ANIMATION_DURATION).start();
|
||||||
|
} else {
|
||||||
|
// OPEN MENU (lowest index at bottom)
|
||||||
|
openFab(fabShuffleQueue, 0);
|
||||||
|
openFab(fabClearQueue, 1);
|
||||||
|
openFab(fabLoadQueue, 2);
|
||||||
|
openFab(fabSaveQueue, 3);
|
||||||
|
openFab(fabDownloadAll, 4);
|
||||||
|
openFab(fabSaveToPlaylist, 5);
|
||||||
|
|
||||||
|
fabMenuToggle.animate().rotation(45f).setDuration(ANIMATION_DURATION).start();
|
||||||
|
}
|
||||||
|
isMenuOpen = !isMenuOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openFab(View fab, int index) {
|
||||||
|
final float displacement = getResources().getDisplayMetrics().density * (FAB_VERTICAL_SPACING_DP * (index + 1));
|
||||||
|
|
||||||
|
fab.setVisibility(View.VISIBLE);
|
||||||
|
fab.setAlpha(0f);
|
||||||
|
fab.setTranslationY(displacement); // Start at the hidden (closed) position
|
||||||
|
|
||||||
|
fab.animate()
|
||||||
|
.translationY(0f)
|
||||||
|
.alpha(1f)
|
||||||
|
.setDuration(ANIMATION_DURATION)
|
||||||
|
.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeFab(View fab, int index) {
|
||||||
|
final float displacement = getResources().getDisplayMetrics().density * (FAB_VERTICAL_SPACING_DP * (index + 1));
|
||||||
|
|
||||||
|
fab.animate()
|
||||||
|
.translationY(displacement)
|
||||||
|
.alpha(0f)
|
||||||
|
.setDuration(ANIMATION_DURATION)
|
||||||
|
.withEndAction(() -> fab.setVisibility(View.GONE))
|
||||||
|
.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleShuffleQueueClick() {
|
||||||
|
Log.d(TAG, "Shuffle Queue Clicked!");
|
||||||
|
toggleFabMenu();
|
||||||
|
// TODO: Insert existing shuffle logic here
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleClearQueueClick() {
|
||||||
|
Log.d(TAG, "Clear Queue Clicked!");
|
||||||
|
toggleFabMenu();
|
||||||
|
// TODO: Insert existing clear queue logic here
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSaveToPlaylistClick() {
|
||||||
|
Log.d(TAG, "Save to Playlist Clicked! (Placeholder)");
|
||||||
|
toggleFabMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleDownloadAllClick() {
|
||||||
|
Log.d(TAG, "Download All Clicked! (Placeholder)");
|
||||||
|
toggleFabMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSaveQueueClick() {
|
||||||
|
Log.d(TAG, "Save Queue Clicked! (Placeholder)");
|
||||||
|
toggleFabMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleLoadQueueClick() {
|
||||||
|
Log.d(TAG, "Load Queue Clicked! (Placeholder)");
|
||||||
|
toggleFabMenu();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
|
@ -27,14 +29,82 @@
|
||||||
|
|
||||||
</com.cappielloantonio.tempo.helper.recyclerview.NestedScrollableHost>
|
</com.cappielloantonio.tempo.helper.recyclerview.NestedScrollableHost>
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<LinearLayout
|
||||||
android:id="@+id/player_shuffle_queue_fab"
|
android:id="@+id/fab_menu_container"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="end"
|
||||||
android:layout_gravity="bottom|end"
|
android:layout_gravity="bottom|end"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:contentDescription="@string/content_description_shuffle_button"
|
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior">
|
||||||
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
|
|
||||||
app:srcCompat="@drawable/ic_shuffle" />
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
android:id="@+id/fab_save_to_playlist"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="Save to Playlist (TODO)"
|
||||||
|
tools:ignore="HardcodedText"
|
||||||
|
app:icon="@android:drawable/ic_menu_edit" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
android:id="@+id/fab_download_all"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="Download All (TODO)"
|
||||||
|
tools:ignore="HardcodedText"
|
||||||
|
app:icon="@android:drawable/stat_sys_download_done" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
android:id="@+id/fab_save_queue"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="Save Queue (TODO)"
|
||||||
|
tools:ignore="HardcodedText"
|
||||||
|
app:icon="@android:drawable/ic_menu_save" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
android:id="@+id/fab_load_queue"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="Load Queue (TODO)"
|
||||||
|
tools:ignore="HardcodedText"
|
||||||
|
app:icon="@android:drawable/ic_menu_revert" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
android:id="@+id/fab_clear_queue"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="@string/player_queue_clean_all_button"
|
||||||
|
app:icon="@android:drawable/ic_menu_delete" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
android:id="@+id/fab_shuffle_queue"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="@string/content_description_shuffle_button"
|
||||||
|
app:icon="@drawable/ic_shuffle" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/fab_menu_toggle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="Toggle action menu (TODO: Fix Localization)"
|
||||||
|
tools:ignore="HardcodedText"
|
||||||
|
app:srcCompat="@drawable/ic_add" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue