mirror of
https://github.com/antebudimir/tempus.git
synced 2025-12-31 17:43:32 +00:00
Implemented the saving and loading functionality of the queue from the server
This commit is contained in:
parent
cbb6239b90
commit
f5a3ba49cc
13 changed files with 223 additions and 16 deletions
|
|
@ -1,18 +1,30 @@
|
||||||
package com.cappielloantonio.play.repository;
|
package com.cappielloantonio.play.repository;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
|
|
||||||
|
import com.cappielloantonio.play.App;
|
||||||
import com.cappielloantonio.play.database.AppDatabase;
|
import com.cappielloantonio.play.database.AppDatabase;
|
||||||
import com.cappielloantonio.play.database.dao.QueueDao;
|
import com.cappielloantonio.play.database.dao.QueueDao;
|
||||||
import com.cappielloantonio.play.model.Queue;
|
import com.cappielloantonio.play.model.Queue;
|
||||||
|
import com.cappielloantonio.play.subsonic.base.ApiResponse;
|
||||||
import com.cappielloantonio.play.subsonic.models.Child;
|
import com.cappielloantonio.play.subsonic.models.Child;
|
||||||
|
import com.cappielloantonio.play.subsonic.models.PlayQueue;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
public class QueueRepository {
|
public class QueueRepository {
|
||||||
private static final String TAG = "QueueRepository";
|
private static final String TAG = "QueueRepository";
|
||||||
|
|
||||||
|
|
@ -42,6 +54,46 @@ public class QueueRepository {
|
||||||
return media;
|
return media;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MutableLiveData<PlayQueue> getPlayQueue() {
|
||||||
|
MutableLiveData<PlayQueue> playQueue = new MutableLiveData<>();
|
||||||
|
|
||||||
|
App.getSubsonicClientInstance(false)
|
||||||
|
.getBookmarksClient()
|
||||||
|
.getPlayQueue()
|
||||||
|
.enqueue(new Callback<ApiResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getPlayQueue() != null) {
|
||||||
|
playQueue.setValue(response.body().getSubsonicResponse().getPlayQueue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||||
|
playQueue.setValue(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return playQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void savePlayQueue(List<String> ids, String current, long position) {
|
||||||
|
App.getSubsonicClientInstance(false)
|
||||||
|
.getBookmarksClient()
|
||||||
|
.savePlayQueue(ids, current, position)
|
||||||
|
.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 insert(Child media, boolean reset, int afterIndex) {
|
public void insert(Child media, boolean reset, int afterIndex) {
|
||||||
try {
|
try {
|
||||||
List<Queue> mediaList = new ArrayList<>();
|
List<Queue> mediaList = new ArrayList<>();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.cappielloantonio.play.subsonic;
|
package com.cappielloantonio.play.subsonic;
|
||||||
|
|
||||||
import com.cappielloantonio.play.subsonic.api.albumsonglist.AlbumSongListClient;
|
import com.cappielloantonio.play.subsonic.api.albumsonglist.AlbumSongListClient;
|
||||||
|
import com.cappielloantonio.play.subsonic.api.bookmarks.BookmarksClient;
|
||||||
import com.cappielloantonio.play.subsonic.api.browsing.BrowsingClient;
|
import com.cappielloantonio.play.subsonic.api.browsing.BrowsingClient;
|
||||||
import com.cappielloantonio.play.subsonic.api.mediaannotation.MediaAnnotationClient;
|
import com.cappielloantonio.play.subsonic.api.mediaannotation.MediaAnnotationClient;
|
||||||
import com.cappielloantonio.play.subsonic.api.medialibraryscanning.MediaLibraryScanningClient;
|
import com.cappielloantonio.play.subsonic.api.medialibraryscanning.MediaLibraryScanningClient;
|
||||||
|
|
@ -29,6 +30,7 @@ public class Subsonic {
|
||||||
private MediaAnnotationClient mediaAnnotationClient;
|
private MediaAnnotationClient mediaAnnotationClient;
|
||||||
private PodcastClient podcastClient;
|
private PodcastClient podcastClient;
|
||||||
private MediaLibraryScanningClient mediaLibraryScanningClient;
|
private MediaLibraryScanningClient mediaLibraryScanningClient;
|
||||||
|
private BookmarksClient bookmarksClient;
|
||||||
|
|
||||||
public Subsonic(SubsonicPreferences preferences) {
|
public Subsonic(SubsonicPreferences preferences) {
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
|
|
@ -101,6 +103,13 @@ public class Subsonic {
|
||||||
return mediaLibraryScanningClient;
|
return mediaLibraryScanningClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BookmarksClient getBookmarksClient() {
|
||||||
|
if (bookmarksClient == null) {
|
||||||
|
bookmarksClient = new BookmarksClient(this);
|
||||||
|
}
|
||||||
|
return bookmarksClient;
|
||||||
|
}
|
||||||
|
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
String url = preferences.getServerUrl() + "/rest/";
|
String url = preferences.getServerUrl() + "/rest/";
|
||||||
return url.replace("//rest", "/rest");
|
return url.replace("//rest", "/rest");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.cappielloantonio.play.subsonic.api.bookmarks;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.cappielloantonio.play.subsonic.RetrofitClient;
|
||||||
|
import com.cappielloantonio.play.subsonic.Subsonic;
|
||||||
|
import com.cappielloantonio.play.subsonic.base.ApiResponse;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
|
||||||
|
public class BookmarksClient {
|
||||||
|
private static final String TAG = "BookmarksClient";
|
||||||
|
|
||||||
|
private final Subsonic subsonic;
|
||||||
|
private final BookmarksService bookmarksService;
|
||||||
|
|
||||||
|
public BookmarksClient(Subsonic subsonic) {
|
||||||
|
this.subsonic = subsonic;
|
||||||
|
this.bookmarksService = new RetrofitClient(subsonic).getRetrofit().create(BookmarksService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Call<ApiResponse> getPlayQueue() {
|
||||||
|
Log.d(TAG, "getPlayQueue()");
|
||||||
|
return bookmarksService.getPlayQueue(subsonic.getParams());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Call<ApiResponse> savePlayQueue(List<String> ids, String current, long position) {
|
||||||
|
Log.d(TAG, "savePlayQueue()");
|
||||||
|
return bookmarksService.savePlayQueue(subsonic.getParams(), ids, current, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.cappielloantonio.play.subsonic.api.bookmarks;
|
||||||
|
|
||||||
|
import com.cappielloantonio.play.subsonic.base.ApiResponse;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.http.GET;
|
||||||
|
import retrofit2.http.Query;
|
||||||
|
import retrofit2.http.QueryMap;
|
||||||
|
|
||||||
|
public interface BookmarksService {
|
||||||
|
@GET("getPlayQueue")
|
||||||
|
Call<ApiResponse> getPlayQueue(@QueryMap Map<String, String> params);
|
||||||
|
|
||||||
|
@GET("savePlayQueue")
|
||||||
|
Call<ApiResponse> savePlayQueue(@QueryMap Map<String, String> params, @Query("id") List<String> ids, @Query("current") String current, @Query("position") long position);
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
package com.cappielloantonio.play.subsonic.models
|
package com.cappielloantonio.play.subsonic.models
|
||||||
|
|
||||||
import java.time.LocalDateTime
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class PlayQueue {
|
class PlayQueue {
|
||||||
|
@SerializedName("entry")
|
||||||
var entries: List<Child>? = null
|
var entries: List<Child>? = null
|
||||||
var current: Int? = null
|
var current: String? = null
|
||||||
var position: Long? = null
|
var position: Long? = null
|
||||||
var username: String? = null
|
var username: String? = null
|
||||||
var changed: LocalDateTime? = null
|
var changed: Date? = null
|
||||||
var changedBy: String? = null
|
var changedBy: String? = null
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.OptIn;
|
import androidx.annotation.OptIn;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.lifecycle.Observer;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.media3.common.MediaMetadata;
|
import androidx.media3.common.MediaMetadata;
|
||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
|
|
@ -26,7 +27,9 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
|
||||||
import com.cappielloantonio.play.R;
|
import com.cappielloantonio.play.R;
|
||||||
import com.cappielloantonio.play.databinding.FragmentPlayerBottomSheetBinding;
|
import com.cappielloantonio.play.databinding.FragmentPlayerBottomSheetBinding;
|
||||||
import com.cappielloantonio.play.glide.CustomGlideRequest;
|
import com.cappielloantonio.play.glide.CustomGlideRequest;
|
||||||
|
import com.cappielloantonio.play.service.MediaManager;
|
||||||
import com.cappielloantonio.play.service.MediaService;
|
import com.cappielloantonio.play.service.MediaService;
|
||||||
|
import com.cappielloantonio.play.subsonic.models.PlayQueue;
|
||||||
import com.cappielloantonio.play.ui.fragment.pager.PlayerControllerVerticalPager;
|
import com.cappielloantonio.play.ui.fragment.pager.PlayerControllerVerticalPager;
|
||||||
import com.cappielloantonio.play.util.Constants;
|
import com.cappielloantonio.play.util.Constants;
|
||||||
import com.cappielloantonio.play.util.MusicUtil;
|
import com.cappielloantonio.play.util.MusicUtil;
|
||||||
|
|
@ -35,6 +38,8 @@ import com.google.android.material.elevation.SurfaceColors;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
@OptIn(markerClass = UnstableApi.class)
|
@OptIn(markerClass = UnstableApi.class)
|
||||||
public class PlayerBottomSheetFragment extends Fragment {
|
public class PlayerBottomSheetFragment extends Fragment {
|
||||||
private FragmentPlayerBottomSheetBinding bind;
|
private FragmentPlayerBottomSheetBinding bind;
|
||||||
|
|
@ -55,6 +60,7 @@ public class PlayerBottomSheetFragment extends Fragment {
|
||||||
|
|
||||||
customizeBottomSheetBackground();
|
customizeBottomSheetBackground();
|
||||||
initViewPager();
|
initViewPager();
|
||||||
|
setHeaderBookmarksButton();
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
@ -247,4 +253,35 @@ public class PlayerBottomSheetFragment extends Fragment {
|
||||||
progressBarHandler.removeCallbacks(progressBarRunnable);
|
progressBarHandler.removeCallbacks(progressBarRunnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setHeaderBookmarksButton() {
|
||||||
|
playerBottomSheetViewModel.getPlayQueue().observeForever(new Observer<PlayQueue>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(PlayQueue playQueue) {
|
||||||
|
if (playQueue != null && !playQueue.getEntries().isEmpty()) {
|
||||||
|
int index = IntStream.range(0, playQueue.getEntries().size()).filter(ix -> playQueue.getEntries().get(ix).getId().equals(playQueue.getCurrent())).findFirst().orElse(-1);
|
||||||
|
|
||||||
|
if (index != -1) {
|
||||||
|
bind.playerHeaderLayout.playerHeaderBookmarkMediaButton.setVisibility(View.VISIBLE);
|
||||||
|
bind.playerHeaderLayout.playerHeaderBookmarkMediaButton.setOnClickListener(v -> {
|
||||||
|
MediaManager.startQueue(mediaBrowserListenableFuture, playQueue.getEntries(), index);
|
||||||
|
bind.playerHeaderLayout.playerHeaderBookmarkMediaButton.setVisibility(View.GONE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bind.playerHeaderLayout.playerHeaderBookmarkMediaButton.setVisibility(View.GONE);
|
||||||
|
bind.playerHeaderLayout.playerHeaderBookmarkMediaButton.setOnClickListener(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
playerBottomSheetViewModel.getPlayQueue().removeObserver(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bind.playerHeaderLayout.playerHeaderBookmarkMediaButton.setOnLongClickListener(v -> {
|
||||||
|
bind.playerHeaderLayout.playerHeaderBookmarkMediaButton.setVisibility(View.GONE);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
new Handler().postDelayed(() -> bind.playerHeaderLayout.playerHeaderBookmarkMediaButton.setVisibility(View.GONE), 5000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import com.cappielloantonio.play.util.Constants;
|
||||||
import com.cappielloantonio.play.util.DownloadUtil;
|
import com.cappielloantonio.play.util.DownloadUtil;
|
||||||
import com.cappielloantonio.play.util.MappingUtil;
|
import com.cappielloantonio.play.util.MappingUtil;
|
||||||
import com.cappielloantonio.play.viewmodel.PlayerBottomSheetViewModel;
|
import com.cappielloantonio.play.viewmodel.PlayerBottomSheetViewModel;
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
|
||||||
|
|
@ -114,11 +115,8 @@ public class PlayerCoverFragment extends Fragment {
|
||||||
});
|
});
|
||||||
|
|
||||||
bind.innerButtonBottomRight.setOnClickListener(view -> {
|
bind.innerButtonBottomRight.setOnClickListener(view -> {
|
||||||
if (getActivity() != null) {
|
if (playerBottomSheetViewModel.savePlayQueue()) {
|
||||||
PlayerBottomSheetFragment playerBottomSheetFragment = (PlayerBottomSheetFragment) requireActivity().getSupportFragmentManager().findFragmentByTag("PlayerBottomSheet");
|
Snackbar.make(requireView(), "Salvato", Snackbar.LENGTH_LONG).show();
|
||||||
if (playerBottomSheetFragment != null) {
|
|
||||||
playerBottomSheetFragment.goToLyricsPage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -136,8 +134,8 @@ public class PlayerCoverFragment extends Fragment {
|
||||||
private void bindMediaController() {
|
private void bindMediaController() {
|
||||||
mediaBrowserListenableFuture.addListener(() -> {
|
mediaBrowserListenableFuture.addListener(() -> {
|
||||||
try {
|
try {
|
||||||
MediaBrowser mediaBrowseri = mediaBrowserListenableFuture.get();
|
MediaBrowser mediaBrowser = mediaBrowserListenableFuture.get();
|
||||||
setMediaBrowserListener(mediaBrowseri);
|
setMediaBrowserListener(mediaBrowser);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,23 @@ import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
|
||||||
|
import com.cappielloantonio.play.model.Download;
|
||||||
import com.cappielloantonio.play.model.Queue;
|
import com.cappielloantonio.play.model.Queue;
|
||||||
import com.cappielloantonio.play.repository.ArtistRepository;
|
import com.cappielloantonio.play.repository.ArtistRepository;
|
||||||
import com.cappielloantonio.play.repository.QueueRepository;
|
import com.cappielloantonio.play.repository.QueueRepository;
|
||||||
import com.cappielloantonio.play.repository.SongRepository;
|
import com.cappielloantonio.play.repository.SongRepository;
|
||||||
import com.cappielloantonio.play.subsonic.models.ArtistID3;
|
import com.cappielloantonio.play.subsonic.models.ArtistID3;
|
||||||
import com.cappielloantonio.play.subsonic.models.Child;
|
import com.cappielloantonio.play.subsonic.models.Child;
|
||||||
|
import com.cappielloantonio.play.subsonic.models.PlayQueue;
|
||||||
import com.cappielloantonio.play.util.Constants;
|
import com.cappielloantonio.play.util.Constants;
|
||||||
|
import com.cappielloantonio.play.util.DownloadUtil;
|
||||||
|
import com.cappielloantonio.play.util.MappingUtil;
|
||||||
|
import com.cappielloantonio.play.util.Preferences;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@OptIn(markerClass = UnstableApi.class)
|
@OptIn(markerClass = UnstableApi.class)
|
||||||
public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
||||||
|
|
@ -59,13 +65,12 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
||||||
songRepository.star(media.getId());
|
songRepository.star(media.getId());
|
||||||
media.setStarred(new Date());
|
media.setStarred(new Date());
|
||||||
|
|
||||||
// TODO
|
if (Preferences.isStarredSyncEnabled()) {
|
||||||
/* if (Preferences.isStarredSyncEnabled()) {
|
|
||||||
DownloadUtil.getDownloadTracker(context).download(
|
DownloadUtil.getDownloadTracker(context).download(
|
||||||
MappingUtil.mapMediaItem(media, false),
|
MappingUtil.mapDownload(media),
|
||||||
MappingUtil.mapDownload(media, null, null)
|
new Download(media)
|
||||||
);
|
);
|
||||||
} */
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -119,4 +124,25 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
||||||
|
|
||||||
return instantMix;
|
return instantMix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<PlayQueue> getPlayQueue() {
|
||||||
|
return queueRepository.getPlayQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean savePlayQueue() {
|
||||||
|
Child media = getLiveMedia().getValue();
|
||||||
|
List<Child> queue = queueRepository.getMedia();
|
||||||
|
List<String> ids = queue.stream().map(Child::getId).collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (media != null) {
|
||||||
|
queueRepository.savePlayQueue(ids, media.getId(), 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void emptyPlayQueue() {
|
||||||
|
queueRepository.savePlayQueue(null, null, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
app/src/main/res/drawable/ic_bookmark.xml
Normal file
9
app/src/main/res/drawable/ic_bookmark.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/titleTextColor"
|
||||||
|
android:pathData="M5,21V5Q5,4.175 5.588,3.587Q6.175,3 7,3H17Q17.825,3 18.413,3.587Q19,4.175 19,5V21L12,18Z" />
|
||||||
|
</vector>
|
||||||
9
app/src/main/res/drawable/ic_bookmark_sync.xml
Normal file
9
app/src/main/res/drawable/ic_bookmark_sync.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/titleTextColor"
|
||||||
|
android:pathData="M4,20V18H6.725Q5.45,16.9 4.725,15.35Q4,13.8 4,12Q4,9.2 5.7,7.062Q7.4,4.925 10,4.25V6.35Q8.25,6.975 7.125,8.512Q6,10.05 6,12Q6,13.35 6.537,14.488Q7.075,15.625 8,16.45V14H10V20ZM15,20Q13.75,20 12.875,19.125Q12,18.25 12,17Q12,15.8 12.825,14.938Q13.65,14.075 14.85,14.025Q15.275,13.125 16.113,12.562Q16.95,12 18,12Q19.325,12 20.288,12.863Q21.25,13.725 21.45,15Q22.5,15 23.25,15.725Q24,16.45 24,17.475Q24,18.525 23.275,19.262Q22.55,20 21.5,20ZM17.9,11Q17.725,9.975 17.225,9.1Q16.725,8.225 16,7.55V10H14V4H20V6H17.275Q18.35,6.95 19.038,8.225Q19.725,9.5 19.925,11Z" />
|
||||||
|
</vector>
|
||||||
|
|
@ -60,6 +60,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="28dp"
|
||||||
android:visibility="gone">
|
android:visibility="gone">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
app:cornerRadius="30dp"
|
app:cornerRadius="30dp"
|
||||||
app:icon="@drawable/ic_lyrics"
|
app:icon="@drawable/ic_bookmark"
|
||||||
app:layout_constraintStart_toEndOf="@+id/vertical_guideline"
|
app:layout_constraintStart_toEndOf="@+id/vertical_guideline"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/horizontal_guideline" />
|
app:layout_constraintTop_toBottomOf="@+id/horizontal_guideline" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,18 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/player_header_bookmark_media_button"
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:background="@drawable/ic_bookmark_sync"
|
||||||
|
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/player_header_seek_bar"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/player_header_button"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/player_header_rewind_media_button"
|
android:id="@+id/player_header_rewind_media_button"
|
||||||
android:layout_width="28dp"
|
android:layout_width="28dp"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue