mirror of
https://github.com/CappielloAntonio/tempo.git
synced 2026-01-30 22:32:07 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
499929ad55 | ||
|
|
7b6d2c62a5 | ||
|
|
ff6bf20c30 | ||
|
|
58d540b939 | ||
|
|
4b9eaa8c3d | ||
|
|
03700d9e4c | ||
|
|
374dbb58bb | ||
|
|
a88658ac8f | ||
|
|
0e97eab744 | ||
|
|
309eca0764 | ||
|
|
fd85f36411 | ||
|
|
b4180afa36 | ||
|
|
2712b73dac | ||
|
|
302458e76b | ||
|
|
dd085a2cdb | ||
|
|
7a58ad5494 | ||
|
|
84234849a4 | ||
|
|
6f6f596432 | ||
|
|
4ff2ed38c7 | ||
|
|
321994496a | ||
|
|
3e1c3133ca | ||
|
|
10b9d7ec76 | ||
|
|
1980e53a27 | ||
|
|
54e988b70e | ||
|
|
14d6128df0 | ||
|
|
7488346804 | ||
|
|
733102a8a4 | ||
|
|
28fef53590 | ||
|
|
e35aed9cc4 | ||
|
|
111a17350b | ||
|
|
54be869081 | ||
|
|
b9462d7374 | ||
|
|
234c9a10d2 | ||
|
|
817c3b02e5 | ||
|
|
1f65b4c321 | ||
|
|
ab0e1ead45 |
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -191,7 +191,7 @@
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
||||
@@ -6,6 +6,12 @@
|
||||
<b>Access your music library on all your android devices</b>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/CappielloAntonio/tempo/releases"><img src="https://i.ibb.co/q0mdc4Z/get-it-on-github.png" width="200"></a>
|
||||
<a href="https://f-droid.org/packages/com.cappielloantonio.notquitemy.tempo"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" width="200"></a>
|
||||
<a href="https://apt.izzysoft.de/fdroid/index/apk/com.cappielloantonio.tempo"><img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" width="200"></a>
|
||||
</p>
|
||||
|
||||
**Tempo** is an open-source and lightweight music client for Subsonic, designed and built natively for Android. It provides a seamless and intuitive music streaming experience, allowing you to access and play your Subsonic music library directly from your Android device.
|
||||
|
||||
Tempo does not rely on magic algorithms to decide what you should listen to. Instead, the interface is built around your listening history, randomness, and optionally integrates with services like Last.fm to personalize your music experience.
|
||||
|
||||
@@ -4,7 +4,7 @@ apply plugin: 'kotlin-parcelize'
|
||||
|
||||
android {
|
||||
compileSdk = 34
|
||||
buildToolsVersion = "34.0.0"
|
||||
buildToolsVersion = '34.0.0'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 24
|
||||
@@ -69,8 +69,8 @@ dependencies {
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
|
||||
implementation 'androidx.preference:preference-ktx:1.2.1'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.7.6'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.3.2'
|
||||
implementation 'androidx.room:room-runtime:2.6.1'
|
||||
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||
@@ -84,17 +84,17 @@ dependencies {
|
||||
implementation 'com.github.bumptech.glide:annotations:4.16.0'
|
||||
|
||||
// Media3
|
||||
implementation 'androidx.media3:media3-session:1.2.1'
|
||||
implementation 'androidx.media3:media3-common:1.2.1'
|
||||
implementation 'androidx.media3:media3-exoplayer:1.2.1'
|
||||
implementation 'androidx.media3:media3-ui:1.2.1'
|
||||
tempoImplementation 'androidx.media3:media3-cast:1.2.1'
|
||||
implementation 'androidx.media3:media3-session:1.3.0'
|
||||
implementation 'androidx.media3:media3-common:1.3.0'
|
||||
implementation 'androidx.media3:media3-exoplayer:1.3.0'
|
||||
implementation 'androidx.media3:media3-ui:1.3.0'
|
||||
tempoImplementation 'androidx.media3:media3-cast:1.3.0'
|
||||
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
|
||||
annotationProcessor 'androidx.room:room-compiler:2.6.1'
|
||||
|
||||
// Retrofit
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.10.0'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.12'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.10.0'
|
||||
}
|
||||
5
app/proguard-rules.pro
vendored
5
app/proguard-rules.pro
vendored
@@ -22,4 +22,7 @@
|
||||
|
||||
-keepattributes SourceFile, LineNumberTable
|
||||
-keep public class * extends java.lang.Exception
|
||||
-keep class retrofit2.** { *; }
|
||||
-keep class retrofit2.** { *; }
|
||||
|
||||
-keep class **.reflect.TypeToken { *; }
|
||||
-keep class * extends **.reflect.TypeToken
|
||||
@@ -12,6 +12,9 @@ import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface ChronologyDao {
|
||||
@Query("SELECT * FROM chronology WHERE server == :server GROUP BY id ORDER BY timestamp DESC LIMIT :count")
|
||||
LiveData<List<Chronology>> getLastPlayed(String server, int count);
|
||||
|
||||
@Query("SELECT * FROM chronology WHERE timestamp >= :startDate AND timestamp < :endDate AND server == :server GROUP BY id ORDER BY COUNT(id) DESC LIMIT 9")
|
||||
LiveData<List<Chronology>> getAllFrom(long startDate, long endDate, String server);
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.cappielloantonio.tempo.model
|
||||
|
||||
import androidx.annotation.Keep
|
||||
|
||||
@Keep
|
||||
data class HomeSector(
|
||||
val id: String,
|
||||
val sectorTitle: String,
|
||||
var isVisible: Boolean,
|
||||
val order: Int,
|
||||
)
|
||||
@@ -8,6 +8,7 @@ import com.cappielloantonio.tempo.interfaces.DecadesCallback;
|
||||
import com.cappielloantonio.tempo.interfaces.MediaCallback;
|
||||
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumInfo;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -131,9 +132,10 @@ public class AlbumRepository {
|
||||
.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().getArtist() != null) {
|
||||
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getArtist() != null && response.body().getSubsonicResponse().getArtist().getAlbums() != null) {
|
||||
List<AlbumID3> albums = response.body().getSubsonicResponse().getArtist().getAlbums();
|
||||
albums.sort(Comparator.comparing(AlbumID3::getYear));
|
||||
Collections.reverse(albums);
|
||||
artistsAlbum.setValue(albums);
|
||||
}
|
||||
}
|
||||
@@ -170,6 +172,29 @@ public class AlbumRepository {
|
||||
return album;
|
||||
}
|
||||
|
||||
public MutableLiveData<AlbumInfo> getAlbumInfo(String id) {
|
||||
MutableLiveData<AlbumInfo> albumInfo = new MutableLiveData<>();
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getBrowsingClient()
|
||||
.getAlbumInfo2(id)
|
||||
.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().getAlbumInfo() != null) {
|
||||
albumInfo.setValue(response.body().getSubsonicResponse().getAlbumInfo());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return albumInfo;
|
||||
}
|
||||
|
||||
public void getInstantMix(AlbumID3 album, int count, MediaCallback callback) {
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getBrowsingClient()
|
||||
@@ -250,7 +275,7 @@ public class AlbumRepository {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getAlbumList2() != null && response.body().getSubsonicResponse().getAlbumList2().getAlbums() != null) {
|
||||
if (response.body().getSubsonicResponse().getAlbumList2().getAlbums().size() > 0 && !response.body().getSubsonicResponse().getAlbumList2().getAlbums().isEmpty()) {
|
||||
if (!response.body().getSubsonicResponse().getAlbumList2().getAlbums().isEmpty() && !response.body().getSubsonicResponse().getAlbumList2().getAlbums().isEmpty()) {
|
||||
callback.onLoadYear(response.body().getSubsonicResponse().getAlbumList2().getAlbums().get(0).getYear());
|
||||
} else {
|
||||
callback.onLoadYear(-1);
|
||||
|
||||
@@ -2,9 +2,13 @@ package com.cappielloantonio.tempo.repository;
|
||||
|
||||
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.MediaMetadata;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
@@ -12,9 +16,13 @@ import androidx.media3.session.LibraryResult;
|
||||
|
||||
import com.cappielloantonio.tempo.App;
|
||||
import com.cappielloantonio.tempo.database.AppDatabase;
|
||||
import com.cappielloantonio.tempo.database.dao.ChronologyDao;
|
||||
import com.cappielloantonio.tempo.database.dao.SessionMediaItemDao;
|
||||
import com.cappielloantonio.tempo.glide.CustomGlideRequest;
|
||||
import com.cappielloantonio.tempo.model.Chronology;
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.model.SessionMediaItem;
|
||||
import com.cappielloantonio.tempo.service.DownloaderManager;
|
||||
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Artist;
|
||||
@@ -26,6 +34,7 @@ import com.cappielloantonio.tempo.subsonic.models.InternetRadioStation;
|
||||
import com.cappielloantonio.tempo.subsonic.models.MusicFolder;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Playlist;
|
||||
import com.cappielloantonio.tempo.subsonic.models.PodcastEpisode;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
@@ -44,6 +53,7 @@ import retrofit2.Response;
|
||||
|
||||
public class AutomotiveRepository {
|
||||
private final SessionMediaItemDao sessionMediaItemDao = AppDatabase.getInstance().sessionMediaItemDao();
|
||||
private final ChronologyDao chronologyDao = AppDatabase.getInstance().chronologyDao();
|
||||
|
||||
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getAlbums(String prefix, String type, int size) {
|
||||
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
|
||||
@@ -132,6 +142,66 @@ public class AutomotiveRepository {
|
||||
return listenableFuture;
|
||||
}
|
||||
|
||||
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getRandomSongs(int count) {
|
||||
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getAlbumSongListClient()
|
||||
.getRandomSongs(100, null, null)
|
||||
.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().getRandomSongs() != null && response.body().getSubsonicResponse().getRandomSongs().getSongs() != null) {
|
||||
List<Child> songs = response.body().getSubsonicResponse().getRandomSongs().getSongs();
|
||||
|
||||
setChildrenMetadata(songs);
|
||||
|
||||
List<MediaItem> mediaItems = MappingUtil.mapMediaItems(songs);
|
||||
|
||||
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
|
||||
|
||||
listenableFuture.set(libraryResult);
|
||||
} else {
|
||||
listenableFuture.set(LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||
listenableFuture.setException(t);
|
||||
}
|
||||
});
|
||||
|
||||
return listenableFuture;
|
||||
}
|
||||
|
||||
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getRecentlyPlayedSongs(String server, int count) {
|
||||
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
|
||||
|
||||
chronologyDao.getLastPlayed(server, count).observeForever(new Observer<List<Chronology>>() {
|
||||
@Override
|
||||
public void onChanged(List<Chronology> chronology) {
|
||||
if (chronology != null && !chronology.isEmpty()) {
|
||||
List<Child> songs = new ArrayList<>(chronology);
|
||||
|
||||
setChildrenMetadata(songs);
|
||||
|
||||
List<MediaItem> mediaItems = MappingUtil.mapMediaItems(songs);
|
||||
|
||||
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
|
||||
|
||||
listenableFuture.set(libraryResult);
|
||||
} else {
|
||||
listenableFuture.set(LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE));
|
||||
}
|
||||
|
||||
chronologyDao.getLastPlayed(server, count).removeObserver(this);
|
||||
}
|
||||
});
|
||||
|
||||
return listenableFuture;
|
||||
}
|
||||
|
||||
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getStarredAlbums(String prefix) {
|
||||
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.cappielloantonio.tempo.repository;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.cappielloantonio.tempo.App;
|
||||
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
|
||||
import com.cappielloantonio.tempo.subsonic.models.LyricsList;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class OpenRepository {
|
||||
public MutableLiveData<LyricsList> getLyricsBySongId(String id) {
|
||||
MutableLiveData<LyricsList> lyricsList = new MutableLiveData<>();
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getOpenClient()
|
||||
.getLyricsBySongId(id)
|
||||
.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().getLyricsList() != null) {
|
||||
lyricsList.setValue(response.body().getSubsonicResponse().getLyricsList());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return lyricsList;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,11 @@ import androidx.lifecycle.MutableLiveData;
|
||||
import com.cappielloantonio.tempo.App;
|
||||
import com.cappielloantonio.tempo.interfaces.SystemCallback;
|
||||
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
|
||||
import com.cappielloantonio.tempo.subsonic.models.OpenSubsonicExtension;
|
||||
import com.cappielloantonio.tempo.subsonic.models.ResponseStatus;
|
||||
import com.cappielloantonio.tempo.subsonic.models.SubsonicResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
@@ -43,8 +47,8 @@ public class SystemRepository {
|
||||
});
|
||||
}
|
||||
|
||||
public MutableLiveData<Boolean> ping() {
|
||||
MutableLiveData<Boolean> pingResult = new MutableLiveData<>();
|
||||
public MutableLiveData<SubsonicResponse> ping() {
|
||||
MutableLiveData<SubsonicResponse> pingResult = new MutableLiveData<>();
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getSystemClient()
|
||||
@@ -53,16 +57,39 @@ public class SystemRepository {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
pingResult.postValue(true);
|
||||
pingResult.postValue(response.body().getSubsonicResponse());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||
pingResult.postValue(false);
|
||||
pingResult.postValue(null);
|
||||
}
|
||||
});
|
||||
|
||||
return pingResult;
|
||||
}
|
||||
|
||||
public MutableLiveData<List<OpenSubsonicExtension>> getOpenSubsonicExtensions() {
|
||||
MutableLiveData<List<OpenSubsonicExtension>> extensionsResult = new MutableLiveData<>();
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getSystemClient()
|
||||
.getOpenSubsonicExtensions()
|
||||
.enqueue(new Callback<ApiResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
extensionsResult.postValue(response.body().getSubsonicResponse().getOpenSubsonicExtensions());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||
extensionsResult.postValue(null);
|
||||
}
|
||||
});
|
||||
|
||||
return extensionsResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.cappielloantonio.tempo.subsonic.api.internetradio.InternetRadioClient
|
||||
import com.cappielloantonio.tempo.subsonic.api.mediaannotation.MediaAnnotationClient;
|
||||
import com.cappielloantonio.tempo.subsonic.api.medialibraryscanning.MediaLibraryScanningClient;
|
||||
import com.cappielloantonio.tempo.subsonic.api.mediaretrieval.MediaRetrievalClient;
|
||||
import com.cappielloantonio.tempo.subsonic.api.open.OpenClient;
|
||||
import com.cappielloantonio.tempo.subsonic.api.playlist.PlaylistClient;
|
||||
import com.cappielloantonio.tempo.subsonic.api.podcast.PodcastClient;
|
||||
import com.cappielloantonio.tempo.subsonic.api.searching.SearchingClient;
|
||||
@@ -35,6 +36,7 @@ public class Subsonic {
|
||||
private BookmarksClient bookmarksClient;
|
||||
private InternetRadioClient internetRadioClient;
|
||||
private SharingClient sharingClient;
|
||||
private OpenClient openClient;
|
||||
|
||||
public Subsonic(SubsonicPreferences preferences) {
|
||||
this.preferences = preferences;
|
||||
@@ -128,6 +130,13 @@ public class Subsonic {
|
||||
return sharingClient;
|
||||
}
|
||||
|
||||
public OpenClient getOpenClient() {
|
||||
if (openClient == null) {
|
||||
openClient = new OpenClient(this);
|
||||
}
|
||||
return openClient;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
String url = preferences.getServerUrl() + "/rest/";
|
||||
return url.replace("//rest", "/rest");
|
||||
|
||||
@@ -9,7 +9,7 @@ import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
|
||||
import retrofit2.Call;
|
||||
|
||||
public class MediaRetrievalClient {
|
||||
private static final String TAG = "BrowsingClient";
|
||||
private static final String TAG = "MediaRetrievalClient";
|
||||
|
||||
private final Subsonic subsonic;
|
||||
private final MediaRetrievalService mediaRetrievalService;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.cappielloantonio.tempo.subsonic.api.open;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
|
||||
import com.cappielloantonio.tempo.subsonic.Subsonic;
|
||||
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
|
||||
|
||||
import retrofit2.Call;
|
||||
|
||||
public class OpenClient {
|
||||
private static final String TAG = "OpenClient";
|
||||
|
||||
private final Subsonic subsonic;
|
||||
private final OpenService openService;
|
||||
|
||||
public OpenClient(Subsonic subsonic) {
|
||||
this.subsonic = subsonic;
|
||||
this.openService = new RetrofitClient(subsonic).getRetrofit().create(OpenService.class);
|
||||
}
|
||||
|
||||
public Call<ApiResponse> getLyricsBySongId(String id) {
|
||||
Log.d(TAG, "getLyricsBySongId()");
|
||||
return openService.getLyricsBySongId(subsonic.getParams(), id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.cappielloantonio.tempo.subsonic.api.open;
|
||||
|
||||
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Query;
|
||||
import retrofit2.http.QueryMap;
|
||||
|
||||
public interface OpenService {
|
||||
@GET("getLyricsBySongId")
|
||||
Call<ApiResponse> getLyricsBySongId(@QueryMap Map<String, String> params, @Query("id") String id);
|
||||
}
|
||||
@@ -28,4 +28,9 @@ public class SystemClient {
|
||||
Log.d(TAG, "getLicense()");
|
||||
return systemService.getLicense(subsonic.getParams());
|
||||
}
|
||||
|
||||
public Call<ApiResponse> getOpenSubsonicExtensions() {
|
||||
Log.d(TAG, "getOpenSubsonicExtensions()");
|
||||
return systemService.getOpenSubsonicExtensions(subsonic.getParams());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,7 @@ public interface SystemService {
|
||||
|
||||
@GET("getLicense")
|
||||
Call<ApiResponse> getLicense(@QueryMap Map<String, String> params);
|
||||
|
||||
@GET("getOpenSubsonicExtensions")
|
||||
Call<ApiResponse> getOpenSubsonicExtensions(@QueryMap Map<String, String> params);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.cappielloantonio.tempo.subsonic.models
|
||||
|
||||
import androidx.annotation.Keep
|
||||
|
||||
@Keep
|
||||
class Line {
|
||||
var start: Int? = null
|
||||
lateinit var value: String
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.cappielloantonio.tempo.subsonic.models
|
||||
|
||||
import androidx.annotation.Keep
|
||||
|
||||
@Keep
|
||||
class LyricsList {
|
||||
var structuredLyrics: List<StructuredLyrics>? = null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.cappielloantonio.tempo.subsonic.models
|
||||
|
||||
import androidx.annotation.Keep
|
||||
|
||||
@Keep
|
||||
class OpenSubsonicExtension {
|
||||
var name: String? = null
|
||||
var versions: List<Int>? = null
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.cappielloantonio.tempo.subsonic.models
|
||||
|
||||
import androidx.annotation.Keep
|
||||
|
||||
@Keep
|
||||
class StructuredLyrics {
|
||||
var displayArtist: String? = null
|
||||
var displayTitle: String? = null
|
||||
var lang: String? = null
|
||||
var offset: Int = 0
|
||||
var synced: Boolean = false
|
||||
var line: List<Line>? = null
|
||||
}
|
||||
@@ -51,4 +51,7 @@ class SubsonicResponse {
|
||||
var version: String? = null
|
||||
var type: String? = null
|
||||
var serverVersion: String? = null
|
||||
var openSubsonic: Boolean? = null
|
||||
var openSubsonicExtensions: List<OpenSubsonicExtension>? = null
|
||||
var lyricsList: LyricsList? = null
|
||||
}
|
||||
@@ -70,6 +70,7 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
init();
|
||||
checkConnectionType();
|
||||
getOpenSubsonicExtensions();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -334,11 +335,25 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
private void pingServer() {
|
||||
if (Preferences.getToken() != null) {
|
||||
mainViewModel.ping().observe(this, isPingSuccessfull -> {
|
||||
if (!isPingSuccessfull && Preferences.showServerUnreachableDialog()) {
|
||||
mainViewModel.ping().observe(this, subsonicResponse -> {
|
||||
if (subsonicResponse == null && Preferences.showServerUnreachableDialog()) {
|
||||
ServerUnreachableDialog dialog = new ServerUnreachableDialog();
|
||||
dialog.show(getSupportFragmentManager(), null);
|
||||
}
|
||||
|
||||
if (subsonicResponse != null) {
|
||||
Preferences.setOpenSubsonic(subsonicResponse.getOpenSubsonic() != null && subsonicResponse.getOpenSubsonic());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void getOpenSubsonicExtensions() {
|
||||
if (Preferences.getToken() != null) {
|
||||
mainViewModel.getOpenSubsonicExtensions().observe(this, openSubsonicExtensions -> {
|
||||
if (openSubsonicExtensions != null) {
|
||||
Preferences.setOpenSubsonicExtensions(openSubsonicExtensions);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.cappielloantonio.tempo.ui.adapter;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Filter;
|
||||
import android.widget.Filterable;
|
||||
@@ -24,6 +25,7 @@ import java.util.List;
|
||||
public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAdapter.ViewHolder> implements Filterable {
|
||||
private final ClickCallback click;
|
||||
private String currentFilter;
|
||||
private boolean showArtist;
|
||||
|
||||
private final Filter filtering = new Filter() {
|
||||
@Override
|
||||
@@ -59,11 +61,12 @@ public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAd
|
||||
private List<AlbumID3> albums;
|
||||
private List<AlbumID3> albumsFull;
|
||||
|
||||
public AlbumCatalogueAdapter(ClickCallback click) {
|
||||
public AlbumCatalogueAdapter(ClickCallback click, boolean showArtist) {
|
||||
this.click = click;
|
||||
this.albums = Collections.emptyList();
|
||||
this.albumsFull = Collections.emptyList();
|
||||
this.currentFilter = "";
|
||||
this.showArtist = showArtist;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -79,6 +82,7 @@ public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAd
|
||||
|
||||
holder.item.albumNameLabel.setText(MusicUtil.getReadableString(album.getName()));
|
||||
holder.item.artistNameLabel.setText(MusicUtil.getReadableString(album.getArtist()));
|
||||
holder.item.artistNameLabel.setVisibility(showArtist ? View.VISIBLE : View.GONE);
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(holder.itemView.getContext(), album.getCoverArtId(), CustomGlideRequest.ResourceType.Album)
|
||||
@@ -161,6 +165,10 @@ public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAd
|
||||
case Constants.ALBUM_ORDER_BY_RANDOM:
|
||||
Collections.shuffle(albums);
|
||||
break;
|
||||
case Constants.ALBUM_ORDER_BY_RECENTLY_ADDED:
|
||||
albums.sort(Comparator.comparing(AlbumID3::getCreated));
|
||||
Collections.reverse(albums);
|
||||
break;
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
|
||||
@@ -186,7 +186,15 @@ public class DownloadHorizontalAdapter extends RecyclerView.Adapter<DownloadHori
|
||||
Child song = grouped.get(position);
|
||||
|
||||
holder.item.downloadedItemTitleTextView.setText(MusicUtil.getReadableString(song.getTitle()));
|
||||
holder.item.downloadedItemSubtitleTextView.setText(holder.itemView.getContext().getString(R.string.song_subtitle_formatter, MusicUtil.getReadableString(song.getArtist()), MusicUtil.getReadableDurationString(song.getDuration(), false)));
|
||||
holder.item.downloadedItemSubtitleTextView.setText(
|
||||
holder.itemView.getContext().getString(
|
||||
R.string.song_subtitle_formatter,
|
||||
MusicUtil.getReadableString(song.getArtist()),
|
||||
MusicUtil.getReadableDurationString(song.getDuration(), false),
|
||||
""
|
||||
)
|
||||
);
|
||||
|
||||
holder.item.downloadedItemPreTextView.setText(MusicUtil.getReadableString(song.getAlbum()));
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.cappielloantonio.tempo.ui.adapter;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.tempo.databinding.ItemHorizontalHomeSectorBinding;
|
||||
import com.cappielloantonio.tempo.databinding.ItemHorizontalPlaylistDialogTrackBinding;
|
||||
import com.cappielloantonio.tempo.glide.CustomGlideRequest;
|
||||
import com.cappielloantonio.tempo.model.HomeSector;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class HomeSectorHorizontalAdapter extends RecyclerView.Adapter<HomeSectorHorizontalAdapter.ViewHolder> {
|
||||
private List<HomeSector> sectors;
|
||||
|
||||
public HomeSectorHorizontalAdapter() {
|
||||
this.sectors = Collections.emptyList();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
ItemHorizontalHomeSectorBinding view = ItemHorizontalHomeSectorBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
HomeSector sector = sectors.get(position);
|
||||
|
||||
holder.item.homeSectorTitleCheckBox.setText(sector.getSectorTitle());
|
||||
holder.item.homeSectorTitleCheckBox.setChecked(sector.isVisible());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return sectors.size();
|
||||
}
|
||||
|
||||
public List<HomeSector> getItems() {
|
||||
return this.sectors;
|
||||
}
|
||||
|
||||
public void setItems(List<HomeSector> sectors) {
|
||||
this.sectors = sectors;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public HomeSector getItem(int id) {
|
||||
return sectors.get(id);
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
ItemHorizontalHomeSectorBinding item;
|
||||
|
||||
ViewHolder(ItemHorizontalHomeSectorBinding item) {
|
||||
super(item.getRoot());
|
||||
|
||||
this.item = item;
|
||||
|
||||
this.item.homeSectorTitleCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> onCheck(isChecked));
|
||||
}
|
||||
|
||||
private void onCheck(boolean isChecked) {
|
||||
sectors.get(getBindingAdapterPosition()).setVisible(isChecked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,11 @@ package com.cappielloantonio.tempo.ui.adapter;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.media3.session.MediaBrowser;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
@@ -17,6 +19,7 @@ import com.cappielloantonio.tempo.service.MediaManager;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -46,7 +49,14 @@ public class PlayerSongQueueAdapter extends RecyclerView.Adapter<PlayerSongQueue
|
||||
Child song = songs.get(position);
|
||||
|
||||
holder.item.queueSongTitleTextView.setText(MusicUtil.getReadableString(song.getTitle()));
|
||||
holder.item.queueSongSubtitleTextView.setText(holder.itemView.getContext().getString(R.string.song_subtitle_formatter, MusicUtil.getReadableString(song.getArtist()), MusicUtil.getReadableDurationString(song.getDuration(), false)));
|
||||
holder.item.queueSongSubtitleTextView.setText(
|
||||
holder.itemView.getContext().getString(
|
||||
R.string.song_subtitle_formatter,
|
||||
MusicUtil.getReadableString(song.getArtist()),
|
||||
MusicUtil.getReadableDurationString(song.getDuration(), false),
|
||||
MusicUtil.getReadableAudioQualityString(song)
|
||||
)
|
||||
);
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(holder.itemView.getContext(), song.getCoverArtId(), CustomGlideRequest.ResourceType.Song)
|
||||
@@ -59,12 +69,33 @@ public class PlayerSongQueueAdapter extends RecyclerView.Adapter<PlayerSongQueue
|
||||
if (position < index) {
|
||||
holder.item.queueSongTitleTextView.setAlpha(0.2f);
|
||||
holder.item.queueSongSubtitleTextView.setAlpha(0.2f);
|
||||
holder.item.ratingIndicatorImageView.setAlpha(0.2f);
|
||||
} else {
|
||||
holder.item.queueSongTitleTextView.setAlpha(1.0f);
|
||||
holder.item.queueSongSubtitleTextView.setAlpha(1.0f);
|
||||
holder.item.ratingIndicatorImageView.setAlpha(1.0f);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (Preferences.showItemRating()) {
|
||||
if (song.getStarred() == null && song.getUserRating() == null) {
|
||||
holder.item.ratingIndicatorImageView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
holder.item.preferredIcon.setVisibility(song.getStarred() != null ? View.VISIBLE : View.GONE);
|
||||
holder.item.ratingBarLayout.setVisibility(song.getUserRating() != null ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (song.getUserRating() != null) {
|
||||
holder.item.oneStarIcon.setImageDrawable(AppCompatResources.getDrawable(holder.itemView.getContext(), song.getUserRating() >= 1 ? R.drawable.ic_star : R.drawable.ic_star_outlined));
|
||||
holder.item.twoStarIcon.setImageDrawable(AppCompatResources.getDrawable(holder.itemView.getContext(), song.getUserRating() >= 2 ? R.drawable.ic_star : R.drawable.ic_star_outlined));
|
||||
holder.item.threeStarIcon.setImageDrawable(AppCompatResources.getDrawable(holder.itemView.getContext(), song.getUserRating() >= 3 ? R.drawable.ic_star : R.drawable.ic_star_outlined));
|
||||
holder.item.fourStarIcon.setImageDrawable(AppCompatResources.getDrawable(holder.itemView.getContext(), song.getUserRating() >= 4 ? R.drawable.ic_star : R.drawable.ic_star_outlined));
|
||||
holder.item.fiveStarIcon.setImageDrawable(AppCompatResources.getDrawable(holder.itemView.getContext(), song.getUserRating() >= 5 ? R.drawable.ic_star : R.drawable.ic_star_outlined));
|
||||
}
|
||||
} else {
|
||||
holder.item.ratingIndicatorImageView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Child> getItems() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
@@ -17,6 +18,7 @@ import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -49,13 +51,26 @@ public class SongHorizontalAdapter extends RecyclerView.Adapter<SongHorizontalAd
|
||||
Child song = songs.get(position);
|
||||
|
||||
holder.item.searchResultSongTitleTextView.setText(MusicUtil.getReadableString(song.getTitle()));
|
||||
holder.item.searchResultSongSubtitleTextView.setText(holder.itemView.getContext().getString(R.string.song_subtitle_formatter, MusicUtil.getReadableString(this.showAlbum ? song.getAlbum() : song.getArtist()), MusicUtil.getReadableDurationString(song.getDuration(), false)));
|
||||
|
||||
holder.item.searchResultSongSubtitleTextView.setText(
|
||||
holder.itemView.getContext().getString(
|
||||
R.string.song_subtitle_formatter,
|
||||
MusicUtil.getReadableString(
|
||||
this.showAlbum ?
|
||||
song.getAlbum() :
|
||||
song.getArtist()
|
||||
),
|
||||
MusicUtil.getReadableDurationString(song.getDuration(), false),
|
||||
MusicUtil.getReadableAudioQualityString(song)
|
||||
)
|
||||
);
|
||||
|
||||
holder.item.trackNumberTextView.setText(MusicUtil.getReadableTrackNumber(holder.itemView.getContext(), song.getTrack()));
|
||||
|
||||
if (DownloadUtil.getDownloadTracker(holder.itemView.getContext()).isDownloaded(song.getId())) {
|
||||
holder.item.searchResultDowanloadIndicatorImageView.setVisibility(View.VISIBLE);
|
||||
holder.item.searchResultDownloadIndicatorImageView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.item.searchResultDowanloadIndicatorImageView.setVisibility(View.GONE);
|
||||
holder.item.searchResultDownloadIndicatorImageView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (showCoverArt) CustomGlideRequest.Builder
|
||||
@@ -69,6 +84,25 @@ public class SongHorizontalAdapter extends RecyclerView.Adapter<SongHorizontalAd
|
||||
if (!showCoverArt && (position > 0 && songs.get(position - 1) != null && songs.get(position - 1).getDiscNumber() != null && songs.get(position).getDiscNumber() != null && songs.get(position - 1).getDiscNumber() < songs.get(position).getDiscNumber())) {
|
||||
holder.item.differentDiskDivider.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (Preferences.showItemRating()) {
|
||||
if (song.getStarred() == null && song.getUserRating() == null) {
|
||||
holder.item.ratingIndicatorImageView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
holder.item.preferredIcon.setVisibility(song.getStarred() != null ? View.VISIBLE : View.GONE);
|
||||
holder.item.ratingBarLayout.setVisibility(song.getUserRating() != null ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (song.getUserRating() != null) {
|
||||
holder.item.oneStarIcon.setImageDrawable(AppCompatResources.getDrawable(holder.itemView.getContext(), song.getUserRating() >= 1 ? R.drawable.ic_star : R.drawable.ic_star_outlined));
|
||||
holder.item.twoStarIcon.setImageDrawable(AppCompatResources.getDrawable(holder.itemView.getContext(), song.getUserRating() >= 2 ? R.drawable.ic_star : R.drawable.ic_star_outlined));
|
||||
holder.item.threeStarIcon.setImageDrawable(AppCompatResources.getDrawable(holder.itemView.getContext(), song.getUserRating() >= 3 ? R.drawable.ic_star : R.drawable.ic_star_outlined));
|
||||
holder.item.fourStarIcon.setImageDrawable(AppCompatResources.getDrawable(holder.itemView.getContext(), song.getUserRating() >= 4 ? R.drawable.ic_star : R.drawable.ic_star_outlined));
|
||||
holder.item.fiveStarIcon.setImageDrawable(AppCompatResources.getDrawable(holder.itemView.getContext(), song.getUserRating() >= 5 ? R.drawable.ic_star : R.drawable.ic_star_outlined));
|
||||
}
|
||||
} else {
|
||||
holder.item.ratingIndicatorImageView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.cappielloantonio.tempo.ui.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.databinding.DialogHomeRearrangementBinding;
|
||||
import com.cappielloantonio.tempo.ui.adapter.HomeSectorHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.viewmodel.HomeRearrangementViewModel;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
||||
public class HomeRearrangementDialog extends DialogFragment {
|
||||
private DialogHomeRearrangementBinding bind;
|
||||
private HomeRearrangementViewModel homeRearrangementViewModel;
|
||||
private HomeSectorHorizontalAdapter homeSectorHorizontalAdapter;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
bind = DialogHomeRearrangementBinding.inflate(getLayoutInflater());
|
||||
|
||||
homeRearrangementViewModel = new ViewModelProvider(requireActivity()).get(HomeRearrangementViewModel.class);
|
||||
|
||||
return new MaterialAlertDialogBuilder(requireContext())
|
||||
.setView(bind.getRoot())
|
||||
.setTitle(R.string.home_rearrangement_dialog_title)
|
||||
.setPositiveButton(R.string.home_rearrangement_dialog_positive_button, (dialog, id) -> { })
|
||||
.setNeutralButton(R.string.home_rearrangement_dialog_neutral_button, (dialog, id) -> { })
|
||||
.setNegativeButton(R.string.home_rearrangement_dialog_negative_button, (dialog, id) -> dialog.cancel())
|
||||
.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
setButtonAction();
|
||||
initSectorView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
homeRearrangementViewModel.closeDialog();
|
||||
bind = null;
|
||||
}
|
||||
|
||||
private void setButtonAction() {
|
||||
androidx.appcompat.app.AlertDialog alertDialog = (androidx.appcompat.app.AlertDialog) Objects.requireNonNull(getDialog());
|
||||
|
||||
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
|
||||
homeRearrangementViewModel.saveHomeSectorList(homeSectorHorizontalAdapter.getItems());
|
||||
dismiss();
|
||||
});
|
||||
|
||||
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
|
||||
homeRearrangementViewModel.resetHomeSectorList();
|
||||
dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
private void initSectorView() {
|
||||
bind.homeSectorItemRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||
bind.homeSectorItemRecyclerView.setHasFixedSize(true);
|
||||
|
||||
homeSectorHorizontalAdapter = new HomeSectorHorizontalAdapter();
|
||||
bind.homeSectorItemRecyclerView.setAdapter(homeSectorHorizontalAdapter);
|
||||
homeSectorHorizontalAdapter.setItems(homeRearrangementViewModel.getHomeSectorList());
|
||||
|
||||
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0) {
|
||||
int originalPosition = -1;
|
||||
int fromPosition = -1;
|
||||
int toPosition = -1;
|
||||
|
||||
@Override
|
||||
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
|
||||
if (originalPosition == -1) originalPosition = viewHolder.getBindingAdapterPosition();
|
||||
|
||||
fromPosition = viewHolder.getBindingAdapterPosition();
|
||||
toPosition = target.getBindingAdapterPosition();
|
||||
|
||||
Collections.swap(homeSectorHorizontalAdapter.getItems(), fromPosition, toPosition);
|
||||
Objects.requireNonNull(recyclerView.getAdapter()).notifyItemMoved(fromPosition, toPosition);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
|
||||
homeRearrangementViewModel.orderSectorLiveListAfterSwap(homeSectorHorizontalAdapter.getItems());
|
||||
|
||||
originalPosition = -1;
|
||||
fromPosition = -1;
|
||||
toPosition = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
|
||||
}
|
||||
}
|
||||
).attachToRecyclerView(bind.homeSectorItemRecyclerView);
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public class PlaylistChooserDialog extends DialogFragment implements ClickCallba
|
||||
|
||||
playlistChooserViewModel.getPlaylistList(requireActivity()).observe(requireActivity(), playlists -> {
|
||||
if (playlists != null) {
|
||||
if (playlists.size() > 0) {
|
||||
if (!playlists.isEmpty()) {
|
||||
if (bind != null) bind.noPlaylistsCreatedTextView.setVisibility(View.GONE);
|
||||
if (bind != null) bind.playlistDialogRecyclerView.setVisibility(View.VISIBLE);
|
||||
playlistDialogHorizontalAdapter.setItems(playlists);
|
||||
|
||||
@@ -67,6 +67,7 @@ public class AlbumCatalogueFragment extends Fragment implements ClickCallback {
|
||||
|
||||
initAppBar();
|
||||
initAlbumCatalogueView();
|
||||
initProgressLoader();
|
||||
|
||||
return view;
|
||||
}
|
||||
@@ -111,7 +112,7 @@ public class AlbumCatalogueFragment extends Fragment implements ClickCallback {
|
||||
bind.albumCatalogueRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
|
||||
bind.albumCatalogueRecyclerView.setHasFixedSize(true);
|
||||
|
||||
albumAdapter = new AlbumCatalogueAdapter(this);
|
||||
albumAdapter = new AlbumCatalogueAdapter(this, true);
|
||||
albumAdapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY);
|
||||
bind.albumCatalogueRecyclerView.setAdapter(albumAdapter);
|
||||
albumCatalogueViewModel.getAlbumList().observe(getViewLifecycleOwner(), albums -> albumAdapter.setItems(albums));
|
||||
@@ -124,6 +125,18 @@ public class AlbumCatalogueFragment extends Fragment implements ClickCallback {
|
||||
bind.albumListSortImageView.setOnClickListener(view -> showPopupMenu(view, R.menu.sort_album_popup_menu));
|
||||
}
|
||||
|
||||
private void initProgressLoader() {
|
||||
albumCatalogueViewModel.getLoadingStatus().observe(getViewLifecycleOwner(), isLoading -> {
|
||||
if (isLoading) {
|
||||
bind.albumListSortImageView.setEnabled(false);
|
||||
bind.albumListProgressLoader.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
bind.albumListSortImageView.setEnabled(true);
|
||||
bind.albumListProgressLoader.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.toolbar_menu, menu);
|
||||
@@ -171,6 +184,9 @@ public class AlbumCatalogueFragment extends Fragment implements ClickCallback {
|
||||
} else if (menuItem.getItemId() == R.id.menu_album_sort_random) {
|
||||
albumAdapter.sort(Constants.ALBUM_ORDER_BY_RANDOM);
|
||||
return true;
|
||||
} else if (menuItem.getItemId() == R.id.menu_album_sort_recently_added) {
|
||||
albumAdapter.sort(Constants.ALBUM_ORDER_BY_RECENTLY_ADDED);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
import com.cappielloantonio.tempo.viewmodel.AlbumPageViewModel;
|
||||
import com.google.android.material.chip.Chip;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -73,6 +74,7 @@ public class AlbumPageFragment extends Fragment implements ClickCallback {
|
||||
init();
|
||||
initAppBar();
|
||||
initAlbumInfoTextButton();
|
||||
initAlbumNotes();
|
||||
initMusicButton();
|
||||
initBackCover();
|
||||
initSongsView();
|
||||
@@ -131,10 +133,20 @@ public class AlbumPageFragment extends Fragment implements ClickCallback {
|
||||
bind.albumNameLabel.setText(MusicUtil.getReadableString(albumPageViewModel.getAlbum().getName()));
|
||||
bind.albumArtistLabel.setText(MusicUtil.getReadableString(albumPageViewModel.getAlbum().getArtist()));
|
||||
bind.albumReleaseYearLabel.setText(albumPageViewModel.getAlbum().getYear() != 0 ? String.valueOf(albumPageViewModel.getAlbum().getYear()) : "");
|
||||
bind.albumSongCountDurationTextview.setText(getString(R.string.album_page_tracks_count_and_duration, albumPageViewModel.getAlbum().getSongCount(), albumPageViewModel.getAlbum().getDuration() != null ? albumPageViewModel.getAlbum().getDuration() / 60 : 0));
|
||||
bind.albumGenresTextview.setText(albumPageViewModel.getAlbum().getGenre());
|
||||
|
||||
bind.animToolbar.setNavigationOnClickListener(v -> activity.navController.navigateUp());
|
||||
|
||||
Objects.requireNonNull(bind.animToolbar.getOverflowIcon()).setTint(requireContext().getResources().getColor(R.color.titleTextColor, null));
|
||||
|
||||
bind.albumOtherInfoButton.setOnClickListener(v -> {
|
||||
if (bind.albumDetailView.getVisibility() == View.GONE) {
|
||||
bind.albumDetailView.setVisibility(View.VISIBLE);
|
||||
} else if (bind.albumDetailView.getVisibility() == View.VISIBLE) {
|
||||
bind.albumDetailView.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initAlbumInfoTextButton() {
|
||||
@@ -148,6 +160,18 @@ public class AlbumPageFragment extends Fragment implements ClickCallback {
|
||||
}));
|
||||
}
|
||||
|
||||
private void initAlbumNotes() {
|
||||
albumPageViewModel.getAlbumInfo().observe(getViewLifecycleOwner(), albumInfo -> {
|
||||
if (albumInfo != null) {
|
||||
if (bind != null) bind.albumNotesTextview.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.albumNotesTextview.setText(MusicUtil.getReadableString(albumInfo.getNotes()));
|
||||
} else {
|
||||
if (bind != null) bind.albumNotesTextview.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initMusicButton() {
|
||||
albumPageViewModel.getAlbumSongLiveList().observe(getViewLifecycleOwner(), songs -> {
|
||||
if (bind != null && !songs.isEmpty()) {
|
||||
|
||||
@@ -27,9 +27,11 @@ import com.cappielloantonio.tempo.helper.recyclerview.GridItemDecoration;
|
||||
import com.cappielloantonio.tempo.interfaces.ClickCallback;
|
||||
import com.cappielloantonio.tempo.service.MediaManager;
|
||||
import com.cappielloantonio.tempo.service.MediaService;
|
||||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||
import com.cappielloantonio.tempo.ui.activity.MainActivity;
|
||||
import com.cappielloantonio.tempo.ui.adapter.AlbumArtistPageOrSimilarAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.AlbumCatalogueAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.ArtistCatalogueAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.ArtistSimilarAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
@@ -38,6 +40,10 @@ import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.cappielloantonio.tempo.viewmodel.ArtistPageViewModel;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@UnstableApi
|
||||
public class ArtistPageFragment extends Fragment implements ClickCallback {
|
||||
private FragmentArtistPageBinding bind;
|
||||
@@ -45,9 +51,8 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
|
||||
private ArtistPageViewModel artistPageViewModel;
|
||||
|
||||
private SongHorizontalAdapter songHorizontalAdapter;
|
||||
private AlbumArtistPageOrSimilarAdapter albumArtistPageOrSimilarAdapter;
|
||||
private AlbumCatalogueAdapter albumCatalogueAdapter;
|
||||
private ArtistSimilarAdapter artistSimilarAdapter;
|
||||
private ArtistCatalogueAdapter artistCatalogueAdapter;
|
||||
|
||||
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
||||
|
||||
@@ -64,8 +69,7 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
|
||||
initArtistInfo();
|
||||
initPlayButtons();
|
||||
initTopSongsView();
|
||||
initHorizontalAlbumsView();
|
||||
initVerticalAlbumsView();
|
||||
initAlbumsView();
|
||||
initSimilarArtistsView();
|
||||
|
||||
return view;
|
||||
@@ -99,18 +103,6 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
|
||||
bundle.putParcelable(Constants.ARTIST_OBJECT, artistPageViewModel.getArtist());
|
||||
activity.navController.navigate(R.id.action_artistPageFragment_to_songListPageFragment, bundle);
|
||||
});
|
||||
|
||||
bind.artistPageAlbumsSwitchLayoutTextViewClickable.setOnClickListener(view -> {
|
||||
boolean isHorizontalRecyclerViewVisible = bind.albumsHorizontalRecyclerView.getVisibility() == View.VISIBLE;
|
||||
|
||||
bind.albumsHorizontalRecyclerView.setVisibility(isHorizontalRecyclerViewVisible ? View.GONE : View.VISIBLE);
|
||||
bind.albumsVerticalRecyclerView.setVisibility(isHorizontalRecyclerViewVisible ? View.VISIBLE : View.GONE);
|
||||
|
||||
Preferences.setArtistAlbumLayout(!isHorizontalRecyclerViewVisible);
|
||||
});
|
||||
|
||||
bind.albumsHorizontalRecyclerView.setVisibility(Preferences.isArtistAlbumLayoutHorizontal() ? View.VISIBLE : View.GONE);
|
||||
bind.albumsVerticalRecyclerView.setVisibility(Preferences.isArtistAlbumLayoutHorizontal() ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
private void initAppBar() {
|
||||
@@ -126,8 +118,6 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
|
||||
private void initArtistInfo() {
|
||||
artistPageViewModel.getArtistInfo(artistPageViewModel.getArtist().getId()).observe(getViewLifecycleOwner(), artistInfo -> {
|
||||
if (artistInfo == null) {
|
||||
if (bind != null)
|
||||
bind.artistPageBioPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.artistPageBioSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
String normalizedBio = MusicUtil.forceReadableString(artistInfo.getBiography());
|
||||
@@ -150,8 +140,6 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
if (bind != null)
|
||||
bind.artistPageBioPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.artistPageBioSector.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
@@ -160,7 +148,7 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
|
||||
private void initPlayButtons() {
|
||||
bind.artistPageShuffleButton.setOnClickListener(v -> {
|
||||
artistPageViewModel.getArtistShuffleList().observe(getViewLifecycleOwner(), songs -> {
|
||||
if (songs.size() > 0) {
|
||||
if (!songs.isEmpty()) {
|
||||
MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0);
|
||||
activity.setBottomSheetInPeek(true);
|
||||
} else {
|
||||
@@ -171,7 +159,7 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
|
||||
|
||||
bind.artistPageRadioButton.setOnClickListener(v -> {
|
||||
artistPageViewModel.getArtistInstantMix().observe(getViewLifecycleOwner(), songs -> {
|
||||
if (songs.size() > 0) {
|
||||
if (!songs.isEmpty()) {
|
||||
MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0);
|
||||
activity.setBottomSheetInPeek(true);
|
||||
} else {
|
||||
@@ -188,58 +176,29 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
|
||||
bind.mostStreamedSongRecyclerView.setAdapter(songHorizontalAdapter);
|
||||
artistPageViewModel.getArtistTopSongList().observe(getViewLifecycleOwner(), songs -> {
|
||||
if (songs == null) {
|
||||
if (bind != null)
|
||||
bind.artistPageTopTracksPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.artistPageTopSongsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.artistPageTopTracksPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.artistPageTopSongsSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.artistPageShuffleButton.setEnabled(!songs.isEmpty());
|
||||
songHorizontalAdapter.setItems(songs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initHorizontalAlbumsView() {
|
||||
bind.albumsHorizontalRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
private void initAlbumsView() {
|
||||
bind.albumsRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
|
||||
bind.albumsRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
|
||||
bind.albumsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
albumArtistPageOrSimilarAdapter = new AlbumArtistPageOrSimilarAdapter(this);
|
||||
bind.albumsHorizontalRecyclerView.setAdapter(albumArtistPageOrSimilarAdapter);
|
||||
artistPageViewModel.getAlbumList().observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null)
|
||||
bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.artistPageAlbumsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.artistPageAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
albumArtistPageOrSimilarAdapter.setItems(albums);
|
||||
}
|
||||
});
|
||||
|
||||
CustomLinearSnapHelper albumSnapHelper = new CustomLinearSnapHelper();
|
||||
albumSnapHelper.attachToRecyclerView(bind.albumsHorizontalRecyclerView);
|
||||
}
|
||||
|
||||
private void initVerticalAlbumsView() {
|
||||
bind.albumsVerticalRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
|
||||
bind.albumsVerticalRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
|
||||
bind.albumsVerticalRecyclerView.setHasFixedSize(true);
|
||||
|
||||
albumCatalogueAdapter = new AlbumCatalogueAdapter(this);
|
||||
bind.albumsVerticalRecyclerView.setAdapter(albumCatalogueAdapter);
|
||||
albumCatalogueAdapter = new AlbumCatalogueAdapter(this, false);
|
||||
bind.albumsRecyclerView.setAdapter(albumCatalogueAdapter);
|
||||
|
||||
artistPageViewModel.getAlbumList().observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null)
|
||||
bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.artistPageAlbumsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.artistPageAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
albumCatalogueAdapter.setItems(albums);
|
||||
@@ -248,22 +207,27 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initSimilarArtistsView() {
|
||||
bind.similarArtistsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.similarArtistsRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
|
||||
bind.similarArtistsRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
|
||||
bind.similarArtistsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
artistSimilarAdapter = new ArtistSimilarAdapter(this);
|
||||
bind.similarArtistsRecyclerView.setAdapter(artistSimilarAdapter);
|
||||
artistCatalogueAdapter = new ArtistCatalogueAdapter(this);
|
||||
bind.similarArtistsRecyclerView.setAdapter(artistCatalogueAdapter);
|
||||
|
||||
artistPageViewModel.getArtistInfo(artistPageViewModel.getArtist().getId()).observe(getViewLifecycleOwner(), artist -> {
|
||||
if (artist == null) {
|
||||
if (bind != null)
|
||||
bind.artistPageSimilarArtistPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.similarArtistSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.artistPageSimilarArtistPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
if (bind != null && artist.getSimilarArtists() != null)
|
||||
bind.similarArtistSector.setVisibility(!artist.getSimilarArtists().isEmpty() ? View.VISIBLE : View.GONE);
|
||||
artistSimilarAdapter.setItems(artist.getSimilarArtists());
|
||||
|
||||
List<ArtistID3> artists = new ArrayList<>();
|
||||
|
||||
if (artist.getSimilarArtists() != null) {
|
||||
artists.addAll(artist.getSimilarArtists());
|
||||
}
|
||||
|
||||
artistCatalogueAdapter.setItems(artists);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -111,20 +111,14 @@ public class DownloadFragment extends Fragment implements ClickCallback {
|
||||
if (bind != null) {
|
||||
bind.emptyDownloadLayout.setVisibility(View.VISIBLE);
|
||||
bind.fragmentDownloadNestedScrollView.setVisibility(View.GONE);
|
||||
|
||||
bind.downloadDownloadedPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
bind.downloadDownloadedSector.setVisibility(View.GONE);
|
||||
|
||||
bind.downloadedGroupByImageView.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
if (bind != null) {
|
||||
bind.emptyDownloadLayout.setVisibility(View.GONE);
|
||||
bind.fragmentDownloadNestedScrollView.setVisibility(View.VISIBLE);
|
||||
|
||||
bind.downloadDownloadedPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
bind.downloadDownloadedSector.setVisibility(View.VISIBLE);
|
||||
|
||||
bind.downloadedGroupByImageView.setVisibility(View.VISIBLE);
|
||||
|
||||
finishDownloadView(songs);
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.cappielloantonio.tempo.helper.recyclerview.DotsIndicatorDecoration;
|
||||
import com.cappielloantonio.tempo.helper.recyclerview.GridItemDecoration;
|
||||
import com.cappielloantonio.tempo.interfaces.ClickCallback;
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.model.HomeSector;
|
||||
import com.cappielloantonio.tempo.service.DownloaderManager;
|
||||
import com.cappielloantonio.tempo.service.MediaManager;
|
||||
import com.cappielloantonio.tempo.service.MediaService;
|
||||
@@ -48,6 +49,7 @@ import com.cappielloantonio.tempo.ui.adapter.ShareHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.SimilarTrackAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.YearAdapter;
|
||||
import com.cappielloantonio.tempo.ui.dialog.HomeRearrangementDialog;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
@@ -119,6 +121,9 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
initRecentAddedAlbumView();
|
||||
initGridView();
|
||||
initSharesView();
|
||||
initHomeReorganizer();
|
||||
|
||||
reorder();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -156,7 +161,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
homeViewModel.getRandomShuffleSample().observe(getViewLifecycleOwner(), songs -> {
|
||||
MusicUtil.ratingFilter(songs);
|
||||
|
||||
if (songs.size() > 0) {
|
||||
if (!songs.isEmpty()) {
|
||||
MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0);
|
||||
activity.setBottomSheetInPeek(true);
|
||||
}
|
||||
@@ -303,6 +308,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initDiscoverSongSlideView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_DISCOVERY)) return;
|
||||
|
||||
bind.discoverSongViewPager.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
|
||||
|
||||
discoverSongAdapter = new DiscoverSongAdapter(this);
|
||||
@@ -312,12 +319,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
MusicUtil.ratingFilter(songs);
|
||||
|
||||
if (songs == null) {
|
||||
if (bind != null)
|
||||
bind.homeDiscoveryPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeDiscoverSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.homeDiscoveryPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeDiscoverSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -329,6 +332,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initSimilarSongView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_MADE_FOR_YOU)) return;
|
||||
|
||||
bind.similarTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.similarTracksRecyclerView.setHasFixedSize(true);
|
||||
|
||||
@@ -338,12 +343,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
MusicUtil.ratingFilter(songs);
|
||||
|
||||
if (songs == null) {
|
||||
if (bind != null)
|
||||
bind.homeSimilarTracksPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeSimilarTracksSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.homeSimilarTracksPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeSimilarTracksSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -356,6 +357,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initArtistBestOf() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_BEST_OF)) return;
|
||||
|
||||
bind.bestOfArtistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.bestOfArtistRecyclerView.setHasFixedSize(true);
|
||||
|
||||
@@ -363,12 +366,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
bind.bestOfArtistRecyclerView.setAdapter(bestOfArtistAdapter);
|
||||
homeViewModel.getBestOfArtists(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), artists -> {
|
||||
if (artists == null) {
|
||||
if (bind != null)
|
||||
bind.homeBestOfArtistPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeBestOfArtistSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.homeBestOfArtistPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeBestOfArtistSector.setVisibility(!artists.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -381,6 +380,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initArtistRadio() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_RADIO_STATION)) return;
|
||||
|
||||
bind.radioArtistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.radioArtistRecyclerView.setHasFixedSize(true);
|
||||
|
||||
@@ -388,12 +389,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
bind.radioArtistRecyclerView.setAdapter(radioArtistAdapter);
|
||||
homeViewModel.getStarredArtistsSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), artists -> {
|
||||
if (artists == null) {
|
||||
if (bind != null)
|
||||
bind.homeRadioArtistPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeRadioArtistSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.homeRadioArtistPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeRadioArtistSector.setVisibility(!artists.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
@@ -408,6 +405,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initGridView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_TOP_SONGS)) return;
|
||||
|
||||
bind.gridTracksRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 3));
|
||||
bind.gridTracksRecyclerView.addItemDecoration(new GridItemDecoration(3, 8, false));
|
||||
bind.gridTracksRecyclerView.setHasFixedSize(true);
|
||||
@@ -418,7 +417,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
homeViewModel.getDiscoverSongSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), music -> {
|
||||
if (music != null) {
|
||||
homeViewModel.getGridSongSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), chronologies -> {
|
||||
if (chronologies == null || chronologies.size() == 0) {
|
||||
if (chronologies == null || chronologies.isEmpty()) {
|
||||
if (bind != null) bind.homeGridTracksSector.setVisibility(View.GONE);
|
||||
if (bind != null) bind.afterGridDivider.setVisibility(View.GONE);
|
||||
} else {
|
||||
@@ -432,18 +431,16 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initStarredTracksView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_STARRED_TRACKS)) return;
|
||||
|
||||
bind.starredTracksRecyclerView.setHasFixedSize(true);
|
||||
|
||||
starredSongAdapter = new SongHorizontalAdapter(this, true, false);
|
||||
bind.starredTracksRecyclerView.setAdapter(starredSongAdapter);
|
||||
homeViewModel.getStarredTracks(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> {
|
||||
if (songs == null) {
|
||||
if (bind != null)
|
||||
bind.starredTracksPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.starredTracksSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.starredTracksPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredTracksSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
@@ -467,18 +464,16 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initStarredAlbumsView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_STARRED_ALBUMS)) return;
|
||||
|
||||
bind.starredAlbumsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
starredAlbumAdapter = new AlbumHorizontalAdapter(this, false);
|
||||
bind.starredAlbumsRecyclerView.setAdapter(starredAlbumAdapter);
|
||||
homeViewModel.getStarredAlbums(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null)
|
||||
bind.starredAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.starredAlbumsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.starredAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
@@ -502,18 +497,16 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initStarredArtistsView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_STARRED_ARTISTS)) return;
|
||||
|
||||
bind.starredArtistsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
starredArtistAdapter = new ArtistHorizontalAdapter(this);
|
||||
bind.starredArtistsRecyclerView.setAdapter(starredArtistAdapter);
|
||||
homeViewModel.getStarredArtists(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), artists -> {
|
||||
if (artists == null) {
|
||||
if (bind != null)
|
||||
bind.starredArtistsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.starredArtistsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.starredArtistsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredArtistsSector.setVisibility(!artists.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
@@ -539,18 +532,16 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initNewReleasesView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_NEW_RELEASES)) return;
|
||||
|
||||
bind.newReleasesRecyclerView.setHasFixedSize(true);
|
||||
|
||||
newReleasesAlbumAdapter = new AlbumHorizontalAdapter(this, false);
|
||||
bind.newReleasesRecyclerView.setAdapter(newReleasesAlbumAdapter);
|
||||
homeViewModel.getRecentlyReleasedAlbums(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null)
|
||||
bind.homeNewReleasesPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeNewReleasesSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.homeNewReleasesPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeNewReleasesSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
@@ -574,6 +565,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initYearSongView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_FLASHBACK)) return;
|
||||
|
||||
bind.yearsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.yearsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
@@ -581,12 +574,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
bind.yearsRecyclerView.setAdapter(yearAdapter);
|
||||
homeViewModel.getYearList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), years -> {
|
||||
if (years == null) {
|
||||
if (bind != null)
|
||||
bind.homeFlashbackPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeFlashbackSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.homeFlashbackPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeFlashbackSector.setVisibility(!years.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -599,6 +588,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initMostPlayedAlbumView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_MOST_PLAYED)) return;
|
||||
|
||||
bind.mostPlayedAlbumsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.mostPlayedAlbumsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
@@ -606,15 +597,10 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
bind.mostPlayedAlbumsRecyclerView.setAdapter(mostPlayedAlbumAdapter);
|
||||
homeViewModel.getMostPlayedAlbums(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null)
|
||||
bind.homeMostPlayedAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeMostPlayedAlbumsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.homeMostPlayedAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeMostPlayedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
// if (albums.size() < 5) reorder();
|
||||
|
||||
mostPlayedAlbumAdapter.setItems(albums);
|
||||
}
|
||||
@@ -625,6 +611,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initRecentPlayedAlbumView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_LAST_PLAYED)) return;
|
||||
|
||||
bind.recentlyPlayedAlbumsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.recentlyPlayedAlbumsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
@@ -632,12 +620,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
bind.recentlyPlayedAlbumsRecyclerView.setAdapter(recentlyPlayedAlbumAdapter);
|
||||
homeViewModel.getRecentlyPlayedAlbumList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null)
|
||||
bind.homeRecentlyPlayedAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeRecentlyPlayedAlbumsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.homeRecentlyPlayedAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeRecentlyPlayedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -650,6 +634,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initRecentAddedAlbumView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_RECENTLY_ADDED)) return;
|
||||
|
||||
bind.recentlyAddedAlbumsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.recentlyAddedAlbumsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
@@ -657,12 +643,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
bind.recentlyAddedAlbumsRecyclerView.setAdapter(recentlyAddedAlbumAdapter);
|
||||
homeViewModel.getMostRecentlyAddedAlbums(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null)
|
||||
bind.homeRecentlyAddedAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeRecentlyAddedAlbumsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.homeRecentlyAddedAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeRecentlyAddedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -675,6 +657,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private void initSharesView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_SHARED)) return;
|
||||
|
||||
bind.sharesRecyclerView.setHasFixedSize(true);
|
||||
|
||||
shareHorizontalAdapter = new ShareHorizontalAdapter(this);
|
||||
@@ -682,11 +666,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
if (Preferences.isSharingEnabled()) {
|
||||
homeViewModel.getShares(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), shares -> {
|
||||
if (shares == null) {
|
||||
if (bind != null)
|
||||
bind.sharesPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.sharesSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.sharesPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.sharesSector.setVisibility(!shares.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
@@ -710,6 +691,17 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
);
|
||||
}
|
||||
|
||||
private void initHomeReorganizer() {
|
||||
final Handler handler = new Handler();
|
||||
final Runnable runnable = () -> { if (bind != null) bind.homeSectorRearrangementButton.setVisibility(View.VISIBLE); };
|
||||
handler.postDelayed(runnable, 5000);
|
||||
|
||||
bind.homeSectorRearrangementButton.setOnClickListener(v -> {
|
||||
HomeRearrangementDialog dialog = new HomeRearrangementDialog();
|
||||
dialog.show(requireActivity().getSupportFragmentManager(), null);
|
||||
});
|
||||
}
|
||||
|
||||
private void refreshSharesView() {
|
||||
final Handler handler = new Handler();
|
||||
final Runnable runnable = () -> {
|
||||
@@ -735,6 +727,63 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
});
|
||||
}
|
||||
|
||||
public void reorder() {
|
||||
if (bind != null && homeViewModel.getHomeSectorList() != null) {
|
||||
bind.homeLinearLayoutContainer.removeAllViews();
|
||||
|
||||
for (HomeSector sector : homeViewModel.getHomeSectorList()) {
|
||||
if (!sector.isVisible()) continue;
|
||||
|
||||
switch (sector.getId()) {
|
||||
case Constants.HOME_SECTOR_DISCOVERY:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeDiscoverSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_MADE_FOR_YOU:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeSimilarTracksSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_BEST_OF:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeBestOfArtistSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_RADIO_STATION:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRadioArtistSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_TOP_SONGS:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeGridTracksSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_STARRED_TRACKS:
|
||||
bind.homeLinearLayoutContainer.addView(bind.starredTracksSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_STARRED_ALBUMS:
|
||||
bind.homeLinearLayoutContainer.addView(bind.starredAlbumsSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_STARRED_ARTISTS:
|
||||
bind.homeLinearLayoutContainer.addView(bind.starredArtistsSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_NEW_RELEASES:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeNewReleasesSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_FLASHBACK:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeFlashbackSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_MOST_PLAYED:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeMostPlayedAlbumsSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_LAST_PLAYED:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyPlayedAlbumsSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_RECENTLY_ADDED:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyAddedAlbumsSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_SHARED:
|
||||
bind.homeLinearLayoutContainer.addView(bind.sharesSector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeSectorRearrangementButton);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeMediaBrowser() {
|
||||
mediaBrowserListenableFuture = new MediaBrowser.Builder(requireContext(), new SessionToken(requireContext(), new ComponentName(requireContext(), MediaService.class))).buildAsync();
|
||||
}
|
||||
@@ -753,7 +802,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
homeViewModel.getMediaInstantMix(getViewLifecycleOwner(), bundle.getParcelable(Constants.TRACK_OBJECT)).observe(getViewLifecycleOwner(), songs -> {
|
||||
MusicUtil.ratingFilter(songs);
|
||||
|
||||
if (songs != null && songs.size() > 0) {
|
||||
if (songs != null && !songs.isEmpty()) {
|
||||
MediaManager.enqueue(mediaBrowserListenableFuture, songs, true);
|
||||
}
|
||||
});
|
||||
@@ -794,7 +843,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
homeViewModel.getArtistInstantMix(getViewLifecycleOwner(), bundle.getParcelable(Constants.ARTIST_OBJECT)).observe(getViewLifecycleOwner(), songs -> {
|
||||
MusicUtil.ratingFilter(songs);
|
||||
|
||||
if (songs.size() > 0) {
|
||||
if (!songs.isEmpty()) {
|
||||
MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0);
|
||||
activity.setBottomSheetInPeek(true);
|
||||
}
|
||||
@@ -805,7 +854,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
||||
homeViewModel.getArtistBestOf(getViewLifecycleOwner(), bundle.getParcelable(Constants.ARTIST_OBJECT)).observe(getViewLifecycleOwner(), songs -> {
|
||||
MusicUtil.ratingFilter(songs);
|
||||
|
||||
if (songs.size() > 0) {
|
||||
if (!songs.isEmpty()) {
|
||||
MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0);
|
||||
activity.setBottomSheetInPeek(true);
|
||||
}
|
||||
|
||||
@@ -142,12 +142,8 @@ public class LibraryFragment extends Fragment implements ClickCallback {
|
||||
bind.musicFolderRecyclerView.setAdapter(musicFolderAdapter);
|
||||
libraryViewModel.getMusicFolders(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), musicFolders -> {
|
||||
if (musicFolders == null) {
|
||||
if (bind != null)
|
||||
bind.libraryMusicFolderPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.libraryMusicFolderSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.libraryMusicFolderPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.libraryMusicFolderSector.setVisibility(!musicFolders.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -164,11 +160,8 @@ public class LibraryFragment extends Fragment implements ClickCallback {
|
||||
bind.albumRecyclerView.setAdapter(albumAdapter);
|
||||
libraryViewModel.getAlbumSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null)
|
||||
bind.libraryAlbumPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.libraryAlbumSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.libraryAlbumPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.libraryAlbumSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -188,12 +181,8 @@ public class LibraryFragment extends Fragment implements ClickCallback {
|
||||
bind.artistRecyclerView.setAdapter(artistAdapter);
|
||||
libraryViewModel.getArtistSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), artists -> {
|
||||
if (artists == null) {
|
||||
if (bind != null)
|
||||
bind.libraryArtistPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.libraryArtistSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.libraryArtistPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.libraryArtistSector.setVisibility(!artists.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -214,11 +203,8 @@ public class LibraryFragment extends Fragment implements ClickCallback {
|
||||
|
||||
libraryViewModel.getGenreSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), genres -> {
|
||||
if (genres == null) {
|
||||
if (bind != null)
|
||||
bind.libraryGenrePlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.libraryGenresSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.libraryGenrePlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.libraryGenresSector.setVisibility(!genres.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -238,12 +224,8 @@ public class LibraryFragment extends Fragment implements ClickCallback {
|
||||
bind.playlistRecyclerView.setAdapter(playlistHorizontalAdapter);
|
||||
libraryViewModel.getPlaylistSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), playlists -> {
|
||||
if (playlists == null) {
|
||||
if (bind != null)
|
||||
bind.libraryPlaylistPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.libraryPlaylistSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.libraryPlaylistPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.libraryPlaylistSector.setVisibility(!playlists.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ public class LoginFragment extends Fragment implements ClickCallback {
|
||||
serverAdapter = new ServerAdapter(this);
|
||||
bind.serverListRecyclerView.setAdapter(serverAdapter);
|
||||
loginViewModel.getServerList().observe(getViewLifecycleOwner(), servers -> {
|
||||
if (servers.size() > 0) {
|
||||
if (!servers.isEmpty()) {
|
||||
if (bind != null) bind.noServerAddedTextView.setVisibility(View.GONE);
|
||||
if (bind != null) bind.serverListRecyclerView.setVisibility(View.VISIBLE);
|
||||
serverAdapter.setItems(servers);
|
||||
|
||||
@@ -249,6 +249,11 @@ public class PlayerBottomSheetFragment extends Fragment {
|
||||
bind.playerBodyLayout.playerBodyBottomSheetViewPager.setCurrentItem(1, true);
|
||||
}
|
||||
|
||||
public void setPlayerControllerVerticalPagerDraggableState(Boolean isDraggable) {
|
||||
ViewPager2 playerControllerVerticalPager = (ViewPager2) bind.playerBodyLayout.playerBodyBottomSheetViewPager;
|
||||
playerControllerVerticalPager.setUserInputEnabled(isDraggable);
|
||||
}
|
||||
|
||||
private void defineProgressBarHandler(MediaBrowser mediaBrowser) {
|
||||
progressBarHandler = new Handler();
|
||||
progressBarRunnable = () -> {
|
||||
|
||||
@@ -257,10 +257,20 @@ public class PlayerControllerFragment extends Fragment {
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
|
||||
PlayerBottomSheetFragment playerBottomSheetFragment = (PlayerBottomSheetFragment) requireActivity().getSupportFragmentManager().findFragmentByTag("PlayerBottomSheet");
|
||||
|
||||
if (position == 0) {
|
||||
activity.setBottomSheetDraggableState(true);
|
||||
|
||||
if (playerBottomSheetFragment != null) {
|
||||
playerBottomSheetFragment.setPlayerControllerVerticalPagerDraggableState(true);
|
||||
}
|
||||
} else if (position == 1) {
|
||||
activity.setBottomSheetDraggableState(false);
|
||||
|
||||
if (playerBottomSheetFragment != null) {
|
||||
playerBottomSheetFragment.setPlayerControllerVerticalPagerDraggableState(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,31 +1,60 @@
|
||||
package com.cappielloantonio.tempo.ui.fragment;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.session.MediaBrowser;
|
||||
import androidx.media3.session.SessionToken;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.databinding.InnerFragmentPlayerLyricsBinding;
|
||||
import com.cappielloantonio.tempo.service.MediaService;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Line;
|
||||
import com.cappielloantonio.tempo.subsonic.models.LyricsList;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
import com.cappielloantonio.tempo.util.OpenSubsonicExtensionsUtil;
|
||||
import com.cappielloantonio.tempo.viewmodel.PlayerBottomSheetViewModel;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public class PlayerLyricsFragment extends Fragment {
|
||||
private static final String TAG = "PlayerLyricsFragment";
|
||||
|
||||
private InnerFragmentPlayerLyricsBinding bind;
|
||||
private PlayerBottomSheetViewModel playerBottomSheetViewModel;
|
||||
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
||||
private MediaBrowser mediaBrowser;
|
||||
private Handler syncLyricsHandler;
|
||||
private Runnable syncLyricsRunnable;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
bind = InnerFragmentPlayerLyricsBinding.inflate(inflater, container, false);
|
||||
View view = bind.getRoot();
|
||||
|
||||
playerBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(PlayerBottomSheetViewModel.class);
|
||||
|
||||
initOverlay();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -33,7 +62,32 @@ public class PlayerLyricsFragment extends Fragment {
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
initLyrics();
|
||||
initPanelContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
initializeBrowser();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
bindMediaController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
releaseHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
releaseBrowser();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,27 +96,195 @@ public class PlayerLyricsFragment extends Fragment {
|
||||
bind = null;
|
||||
}
|
||||
|
||||
private void initLyrics() {
|
||||
playerBottomSheetViewModel.getLiveLyrics().observe(getViewLifecycleOwner(), lyrics -> {
|
||||
playerBottomSheetViewModel.getLiveDescription().observe(getViewLifecycleOwner(), description -> {
|
||||
if (bind != null) {
|
||||
if (lyrics != null && !lyrics.trim().equals("")) {
|
||||
bind.nowPlayingSongLyricsTextView.setText(MusicUtil.getReadableLyrics(lyrics));
|
||||
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
|
||||
bind.emptyDescriptionImageView.setVisibility(View.GONE);
|
||||
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
|
||||
} else if (description != null && !description.trim().equals("")) {
|
||||
bind.nowPlayingSongLyricsTextView.setText(MusicUtil.getReadableLyrics(description));
|
||||
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
|
||||
bind.emptyDescriptionImageView.setVisibility(View.GONE);
|
||||
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
|
||||
} else {
|
||||
bind.nowPlayingSongLyricsTextView.setVisibility(View.GONE);
|
||||
bind.emptyDescriptionImageView.setVisibility(View.VISIBLE);
|
||||
bind.titleEmptyDescriptionLabel.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
});
|
||||
private void initOverlay() {
|
||||
bind.syncLyricsTapButton.setOnClickListener(view -> {
|
||||
playerBottomSheetViewModel.changeSyncLyricsState();
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeBrowser() {
|
||||
mediaBrowserListenableFuture = new MediaBrowser.Builder(requireContext(), new SessionToken(requireContext(), new ComponentName(requireContext(), MediaService.class))).buildAsync();
|
||||
}
|
||||
|
||||
private void releaseHandler() {
|
||||
if (syncLyricsHandler != null) {
|
||||
syncLyricsHandler.removeCallbacks(syncLyricsRunnable);
|
||||
syncLyricsHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseBrowser() {
|
||||
MediaBrowser.releaseFuture(mediaBrowserListenableFuture);
|
||||
}
|
||||
|
||||
private void bindMediaController() {
|
||||
mediaBrowserListenableFuture.addListener(() -> {
|
||||
try {
|
||||
mediaBrowser = mediaBrowserListenableFuture.get();
|
||||
defineProgressHandler();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
private void initPanelContent() {
|
||||
if (OpenSubsonicExtensionsUtil.isSongLyricsExtensionAvailable()) {
|
||||
playerBottomSheetViewModel.getLiveLyricsList().observe(getViewLifecycleOwner(), lyricsList -> {
|
||||
setPanelContent(null, lyricsList);
|
||||
});
|
||||
} else {
|
||||
playerBottomSheetViewModel.getLiveLyrics().observe(getViewLifecycleOwner(), lyrics -> {
|
||||
setPanelContent(lyrics, null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setPanelContent(String lyrics, LyricsList lyricsList) {
|
||||
playerBottomSheetViewModel.getLiveDescription().observe(getViewLifecycleOwner(), description -> {
|
||||
if (bind != null) {
|
||||
bind.nowPlayingSongLyricsSrollView.smoothScrollTo(0, 0);
|
||||
|
||||
if (lyrics != null && !lyrics.trim().equals("")) {
|
||||
bind.nowPlayingSongLyricsTextView.setText(MusicUtil.getReadableLyrics(lyrics));
|
||||
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
|
||||
bind.emptyDescriptionImageView.setVisibility(View.GONE);
|
||||
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
|
||||
bind.syncLyricsTapButton.setVisibility(View.GONE);
|
||||
} else if (lyricsList != null && lyricsList.getStructuredLyrics() != null) {
|
||||
setSyncLirics(lyricsList);
|
||||
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
|
||||
bind.emptyDescriptionImageView.setVisibility(View.GONE);
|
||||
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
|
||||
bind.syncLyricsTapButton.setVisibility(View.VISIBLE);
|
||||
} else if (description != null && !description.trim().equals("")) {
|
||||
bind.nowPlayingSongLyricsTextView.setText(MusicUtil.getReadableLyrics(description));
|
||||
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
|
||||
bind.emptyDescriptionImageView.setVisibility(View.GONE);
|
||||
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
|
||||
bind.syncLyricsTapButton.setVisibility(View.GONE);
|
||||
} else {
|
||||
bind.nowPlayingSongLyricsTextView.setVisibility(View.GONE);
|
||||
bind.emptyDescriptionImageView.setVisibility(View.VISIBLE);
|
||||
bind.titleEmptyDescriptionLabel.setVisibility(View.VISIBLE);
|
||||
bind.syncLyricsTapButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private void setSyncLirics(LyricsList lyricsList) {
|
||||
if (lyricsList.getStructuredLyrics() != null && !lyricsList.getStructuredLyrics().isEmpty() && lyricsList.getStructuredLyrics().get(0).getLine() != null) {
|
||||
StringBuilder lyricsBuilder = new StringBuilder();
|
||||
List<Line> lines = lyricsList.getStructuredLyrics().get(0).getLine();
|
||||
|
||||
if (lines != null) {
|
||||
for (Line line : lines) {
|
||||
lyricsBuilder.append(line.getValue().trim()).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
bind.nowPlayingSongLyricsTextView.setText(lyricsBuilder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void defineProgressHandler() {
|
||||
playerBottomSheetViewModel.getLiveLyricsList().observe(getViewLifecycleOwner(), lyricsList -> {
|
||||
if (lyricsList != null) {
|
||||
|
||||
if (lyricsList.getStructuredLyrics() != null && lyricsList.getStructuredLyrics().get(0) != null && !lyricsList.getStructuredLyrics().get(0).getSynced()) {
|
||||
releaseHandler();
|
||||
return;
|
||||
}
|
||||
|
||||
syncLyricsHandler = new Handler();
|
||||
syncLyricsRunnable = () -> {
|
||||
if (syncLyricsHandler != null) {
|
||||
if (bind != null) {
|
||||
displaySyncedLyrics();
|
||||
}
|
||||
|
||||
syncLyricsHandler.postDelayed(syncLyricsRunnable, 250);
|
||||
}
|
||||
};
|
||||
|
||||
syncLyricsHandler.postDelayed(syncLyricsRunnable, 250);
|
||||
} else {
|
||||
releaseHandler();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displaySyncedLyrics() {
|
||||
LyricsList lyricsList = playerBottomSheetViewModel.getLiveLyricsList().getValue();
|
||||
int timestamp = (int) (mediaBrowser.getCurrentPosition());
|
||||
|
||||
if (lyricsList != null && lyricsList.getStructuredLyrics() != null && !lyricsList.getStructuredLyrics().isEmpty() && lyricsList.getStructuredLyrics().get(0).getLine() != null) {
|
||||
StringBuilder lyricsBuilder = new StringBuilder();
|
||||
List<Line> lines = lyricsList.getStructuredLyrics().get(0).getLine();
|
||||
|
||||
if (lines == null || lines.isEmpty()) return;
|
||||
|
||||
for (Line line : lines) {
|
||||
lyricsBuilder.append(line.getValue().trim()).append("\n");
|
||||
}
|
||||
|
||||
Line toHighlight = lines.stream().filter(line -> line != null && line.getStart() != null && line.getStart() < timestamp).reduce((first, second) -> second).orElse(null);
|
||||
|
||||
if (toHighlight != null) {
|
||||
String lyrics = lyricsBuilder.toString();
|
||||
Spannable spannableString = new SpannableString(lyrics);
|
||||
|
||||
int startingPosition = getStartPosition(lines, toHighlight);
|
||||
int endingPosition = startingPosition + toHighlight.getValue().length();
|
||||
|
||||
spannableString.setSpan(new ForegroundColorSpan(requireContext().getResources().getColor(R.color.shadowsLyricsTextColor, null)), 0, lyrics.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannableString.setSpan(new ForegroundColorSpan(requireContext().getResources().getColor(R.color.lyricsTextColor, null)), startingPosition, endingPosition, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
bind.nowPlayingSongLyricsTextView.setText(spannableString);
|
||||
|
||||
if (playerBottomSheetViewModel.getSyncLyricsState()) {
|
||||
bind.nowPlayingSongLyricsSrollView.smoothScrollTo(0, getScroll(lines, toHighlight));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getStartPosition(List<Line> lines, Line toHighlight) {
|
||||
int start = 0;
|
||||
|
||||
for (Line line : lines) {
|
||||
if (line != toHighlight) {
|
||||
start = start + line.getValue().length() + 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
private int getLineCount(List<Line> lines, Line toHighlight) {
|
||||
int start = 0;
|
||||
|
||||
for (Line line : lines) {
|
||||
if (line != toHighlight) {
|
||||
bind.tempLyricsLineTextView.setText(line.getValue());
|
||||
start = start + bind.tempLyricsLineTextView.getLineCount();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
private int getScroll(List<Line> lines, Line toHighlight) {
|
||||
int lineHeight = bind.nowPlayingSongLyricsTextView.getLineHeight();
|
||||
int lineCount = getLineCount(lines, toHighlight);
|
||||
int scrollViewHeight = bind.nowPlayingSongLyricsSrollView.getHeight();
|
||||
|
||||
return lineHeight * lineCount < scrollViewHeight / 2 ? 0 : lineHeight * lineCount - scrollViewHeight / 2 + lineHeight;
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,7 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
|
||||
|
||||
// Pic top-left
|
||||
CustomGlideRequest.Builder
|
||||
.from(requireContext(), songs.size() > 0 ? songs.get(0).getCoverArtId() : playlistPageViewModel.getPlaylist().getCoverArtId(), CustomGlideRequest.ResourceType.Song)
|
||||
.from(requireContext(), !songs.isEmpty() ? songs.get(0).getCoverArtId() : playlistPageViewModel.getPlaylist().getCoverArtId(), CustomGlideRequest.ResourceType.Song)
|
||||
.build()
|
||||
.transform(new GranularRoundedCorners(CustomGlideRequest.CORNER_RADIUS, 0, 0, 0))
|
||||
.into(bind.playlistCoverImageViewTopLeft);
|
||||
|
||||
@@ -117,7 +117,7 @@ public class AlbumBottomSheetDialog extends BottomSheetDialogFragment implements
|
||||
public void onLoadMedia(List<?> media) {
|
||||
MusicUtil.ratingFilter((ArrayList<Child>) media);
|
||||
|
||||
if (media.size() > 0) {
|
||||
if (!media.isEmpty()) {
|
||||
MediaManager.startQueue(mediaBrowserListenableFuture, (ArrayList<Child>) media, 0);
|
||||
((MainActivity) requireActivity()).setBottomSheetInPeek(true);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public class ArtistBottomSheetDialog extends BottomSheetDialogFragment implement
|
||||
artistRepository.getInstantMix(artist, 20).observe(getViewLifecycleOwner(), songs -> {
|
||||
MusicUtil.ratingFilter(songs);
|
||||
|
||||
if (songs.size() > 0) {
|
||||
if (!songs.isEmpty()) {
|
||||
MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0);
|
||||
((MainActivity) requireActivity()).setBottomSheetInPeek(true);
|
||||
}
|
||||
@@ -106,7 +106,7 @@ public class ArtistBottomSheetDialog extends BottomSheetDialogFragment implement
|
||||
artistRepository.getRandomSong(artist, 50).observe(getViewLifecycleOwner(), songs -> {
|
||||
MusicUtil.ratingFilter(songs);
|
||||
|
||||
if (songs.size() > 0) {
|
||||
if (!songs.isEmpty()) {
|
||||
MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0);
|
||||
((MainActivity) requireActivity()).setBottomSheetInPeek(true);
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ public class SongBottomSheetDialog extends BottomSheetDialogFragment implements
|
||||
return;
|
||||
}
|
||||
|
||||
if (songs.size() > 0) {
|
||||
if (!songs.isEmpty()) {
|
||||
MediaManager.enqueue(mediaBrowserListenableFuture, songs, true);
|
||||
dismissBottomSheet();
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ object Constants {
|
||||
const val ALBUM_ORDER_BY_ARTIST = "ALBUM_ORDER_BY_ARTIST"
|
||||
const val ALBUM_ORDER_BY_YEAR = "ALBUM_ORDER_BY_YEAR"
|
||||
const val ALBUM_ORDER_BY_RANDOM = "ALBUM_ORDER_BY_RANDOM"
|
||||
const val ALBUM_ORDER_BY_RECENTLY_ADDED = "ALBUM_ORDER_BY_RECENTLY_ADDED"
|
||||
|
||||
const val ARTIST_DOWNLOADED = "ARTIST_DOWNLOADED"
|
||||
const val ARTIST_STARRED = "ARTIST_STARRED"
|
||||
@@ -90,4 +91,19 @@ object Constants {
|
||||
|
||||
const val PLAYABLE_MEDIA_LIMIT = 100
|
||||
const val PRE_PLAYABLE_MEDIA = 15
|
||||
|
||||
const val HOME_SECTOR_DISCOVERY = "HOME_SECTOR_DISCOVERY"
|
||||
const val HOME_SECTOR_MADE_FOR_YOU = "HOME_SECTOR_MADE_FOR_YOU"
|
||||
const val HOME_SECTOR_BEST_OF = "HOME_SECTOR_BEST_OF"
|
||||
const val HOME_SECTOR_RADIO_STATION = "HOME_SECTOR_RADIO_STATION"
|
||||
const val HOME_SECTOR_TOP_SONGS = "HOME_SECTOR_TOP_SONGS"
|
||||
const val HOME_SECTOR_STARRED_TRACKS = "HOME_SECTOR_STARRED_TRACKS"
|
||||
const val HOME_SECTOR_STARRED_ALBUMS = "HOME_SECTOR_STARRED_ALBUMS"
|
||||
const val HOME_SECTOR_STARRED_ARTISTS = "HOME_SECTOR_STARRED_ARTISTS"
|
||||
const val HOME_SECTOR_NEW_RELEASES = "HOME_SECTOR_NEW_RELEASES"
|
||||
const val HOME_SECTOR_FLASHBACK = "HOME_SECTOR_FLASHBACK"
|
||||
const val HOME_SECTOR_MOST_PLAYED = "HOME_SECTOR_MOST_PLAYED"
|
||||
const val HOME_SECTOR_LAST_PLAYED = "HOME_SECTOR_LAST_PLAYED"
|
||||
const val HOME_SECTOR_RECENTLY_ADDED = "HOME_SECTOR_RECENTLY_ADDED"
|
||||
const val HOME_SECTOR_SHARED = "HOME_SECTOR_SHARED"
|
||||
}
|
||||
@@ -156,6 +156,17 @@ public class MusicUtil {
|
||||
return getReadableDurationString(lenght, millis);
|
||||
}
|
||||
|
||||
public static String getReadableAudioQualityString(Child child) {
|
||||
if (!Preferences.showAudioQuality()) return "";
|
||||
|
||||
return "•" +
|
||||
" " +
|
||||
child.getBitrate() +
|
||||
"kbps" +
|
||||
" " +
|
||||
child.getSuffix();
|
||||
}
|
||||
|
||||
public static String getReadablePodcastDurationString(long duration) {
|
||||
long minutes = duration / 60;
|
||||
|
||||
@@ -211,7 +222,7 @@ public class MusicUtil {
|
||||
public static List<String> getReadableStrings(List<String> strings) {
|
||||
List<String> readableStrings = new ArrayList<>();
|
||||
|
||||
if (strings.size() > 0) {
|
||||
if (!strings.isEmpty()) {
|
||||
for (String string : strings) {
|
||||
if (string != null) {
|
||||
readableStrings.add(Html.fromHtml(string, Html.FROM_HTML_MODE_COMPACT).toString());
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.cappielloantonio.tempo.util;
|
||||
|
||||
import com.cappielloantonio.tempo.subsonic.models.OpenSubsonicExtension;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OpenSubsonicExtensionsUtil {
|
||||
private static List<OpenSubsonicExtension> getOpenSubsonicExtensions() {
|
||||
List<OpenSubsonicExtension> extensions = null;
|
||||
|
||||
if (Preferences.isOpenSubsonic() && Preferences.getOpenSubsonicExtensions() != null) {
|
||||
extensions = new Gson().fromJson(
|
||||
Preferences.getOpenSubsonicExtensions(),
|
||||
new TypeToken<List<OpenSubsonicExtension>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
private static OpenSubsonicExtension getOpenSubsonicExtension(String extensionName) {
|
||||
if (getOpenSubsonicExtensions() == null) return null;
|
||||
|
||||
return getOpenSubsonicExtensions().stream().filter(openSubsonicExtension -> openSubsonicExtension.getName().equals(extensionName)).findAny().orElse(null);
|
||||
}
|
||||
|
||||
public static boolean isTranscodeOffsetExtensionAvailable() {
|
||||
return getOpenSubsonicExtension("transcodeOffset") != null;
|
||||
}
|
||||
|
||||
public static boolean isFormPostExtensionAvailable() {
|
||||
return getOpenSubsonicExtension("formPost") != null;
|
||||
}
|
||||
|
||||
public static boolean isSongLyricsExtensionAvailable() {
|
||||
return getOpenSubsonicExtension("songLyrics") != null;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
package com.cappielloantonio.tempo.util
|
||||
|
||||
import com.cappielloantonio.tempo.App
|
||||
import com.cappielloantonio.tempo.model.HomeSector
|
||||
import com.cappielloantonio.tempo.subsonic.models.OpenSubsonicExtension
|
||||
import com.google.gson.Gson
|
||||
|
||||
|
||||
|
||||
|
||||
object Preferences {
|
||||
const val THEME = "theme"
|
||||
@@ -12,6 +18,8 @@ object Preferences {
|
||||
private const val LOW_SECURITY = "low_security"
|
||||
private const val BATTERY_OPTIMIZATION = "battery_optimization"
|
||||
private const val SERVER_ID = "server_id"
|
||||
private const val OPEN_SUBSONIC = "open_subsonic"
|
||||
private const val OPEN_SUBSONIC_EXTENSIONS = "open_subsonic_extensions"
|
||||
private const val PLAYBACK_SPEED = "playback_speed"
|
||||
private const val SKIP_SILENCE = "skip_silence"
|
||||
private const val IMAGE_CACHE_SIZE = "image_cache_size"
|
||||
@@ -45,8 +53,10 @@ object Preferences {
|
||||
private const val BUFFERING_STRATEGY = "buffering_strategy"
|
||||
private const val SKIP_MIN_STAR_RATING = "skip_min_star_rating"
|
||||
private const val MIN_STAR_RATING = "min_star_rating"
|
||||
private const val ARTIST_ALBUM_LAYOUT = "artist_album_layout"
|
||||
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 RATING_PER_ITEM = "rating_per_item"
|
||||
|
||||
|
||||
@JvmStatic
|
||||
@@ -119,6 +129,26 @@ object Preferences {
|
||||
App.getInstance().preferences.edit().putString(SERVER_ID, serverId).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isOpenSubsonic(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(OPEN_SUBSONIC, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setOpenSubsonic(isOpenSubsonic: Boolean) {
|
||||
App.getInstance().preferences.edit().putBoolean(OPEN_SUBSONIC, isOpenSubsonic).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getOpenSubsonicExtensions(): String? {
|
||||
return App.getInstance().preferences.getString(OPEN_SUBSONIC_EXTENSIONS, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setOpenSubsonicExtensions(extension: List<OpenSubsonicExtension>) {
|
||||
App.getInstance().preferences.edit().putString(OPEN_SUBSONIC_EXTENSIONS, Gson().toJson(extension)).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun askForOptimization(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(BATTERY_OPTIMIZATION, true)
|
||||
@@ -348,19 +378,28 @@ object Preferences {
|
||||
return App.getInstance().preferences.getInt(MIN_STAR_RATING, 0)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isArtistAlbumLayoutHorizontal(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(ARTIST_ALBUM_LAYOUT, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setArtistAlbumLayout(isArtistAlbumLayoutHorizontal: Boolean) {
|
||||
App.getInstance().preferences.edit().putBoolean(ARTIST_ALBUM_LAYOUT, isArtistAlbumLayoutHorizontal)
|
||||
.apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isDisplayAlwaysOn(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(ALWAYS_ON_DISPLAY, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showAudioQuality(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(AUDIO_QUALITY_PER_ITEM, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getHomeSectorList(): String? {
|
||||
return App.getInstance().preferences.getString(HOME_SECTOR_LIST, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setHomeSectorList(extension: List<HomeSector>?) {
|
||||
App.getInstance().preferences.edit().putString(HOME_SECTOR_LIST, Gson().toJson(extension)).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showItemRating(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(RATING_PER_ITEM, false)
|
||||
}
|
||||
}
|
||||
@@ -102,7 +102,7 @@ public class ReplayGainUtil {
|
||||
|
||||
private static Float parseReplayGainTag(Metadata.Entry entry) {
|
||||
try {
|
||||
return Float.parseFloat(entry.toString().replaceAll("[^\\d.]", ""));
|
||||
return Float.parseFloat(entry.toString().replaceAll("[^\\d.-]", ""));
|
||||
} catch (NumberFormatException exception) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import retrofit2.Callback;
|
||||
|
||||
public class AlbumCatalogueViewModel extends AndroidViewModel {
|
||||
private final MutableLiveData<List<AlbumID3>> albumList = new MutableLiveData<>(new ArrayList<>());
|
||||
private final MutableLiveData<Boolean> loading = new MutableLiveData<>(true);
|
||||
|
||||
private int page = 0;
|
||||
private Status status = Status.STOPPED;
|
||||
@@ -32,6 +33,10 @@ public class AlbumCatalogueViewModel extends AndroidViewModel {
|
||||
return albumList;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getLoadingStatus() {
|
||||
return loading;
|
||||
}
|
||||
|
||||
public void loadAlbums() {
|
||||
page = 0;
|
||||
status = Status.RUNNING;
|
||||
@@ -52,6 +57,7 @@ public class AlbumCatalogueViewModel extends AndroidViewModel {
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
if (status == Status.STOPPED) {
|
||||
loading.setValue(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,8 +68,10 @@ public class AlbumCatalogueViewModel extends AndroidViewModel {
|
||||
|
||||
if (media.size() == size) {
|
||||
loadAlbums(size);
|
||||
loading.setValue(true);
|
||||
} else {
|
||||
status = Status.STOPPED;
|
||||
loading.setValue(false);
|
||||
}
|
||||
}
|
||||
}, size, size * page++);
|
||||
|
||||
@@ -9,6 +9,7 @@ import androidx.lifecycle.LiveData;
|
||||
import com.cappielloantonio.tempo.repository.AlbumRepository;
|
||||
import com.cappielloantonio.tempo.repository.ArtistRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumInfo;
|
||||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
|
||||
@@ -42,4 +43,8 @@ public class AlbumPageViewModel extends AndroidViewModel {
|
||||
public LiveData<ArtistID3> getArtist() {
|
||||
return artistRepository.getArtistInfo(album.getArtistId());
|
||||
}
|
||||
|
||||
public LiveData<AlbumInfo> getAlbumInfo() {
|
||||
return albumRepository.getAlbumInfo(album.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.cappielloantonio.tempo.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.model.HomeSector;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HomeRearrangementViewModel extends AndroidViewModel {
|
||||
private List<HomeSector> sectors = new ArrayList<>();
|
||||
|
||||
public HomeRearrangementViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
||||
public List<HomeSector> getHomeSectorList() {
|
||||
if (sectors != null && !sectors.isEmpty()) return sectors;
|
||||
|
||||
if (Preferences.getHomeSectorList() != null && !Preferences.getHomeSectorList().equals("null")) {
|
||||
sectors = new Gson().fromJson(
|
||||
Preferences.getHomeSectorList(),
|
||||
new TypeToken<List<HomeSector>>() {
|
||||
}.getType()
|
||||
);
|
||||
} else {
|
||||
sectors = fillStandardHomeSectorList();
|
||||
}
|
||||
|
||||
return sectors;
|
||||
}
|
||||
|
||||
public void orderSectorLiveListAfterSwap(List<HomeSector> sectors) {
|
||||
this.sectors = sectors;
|
||||
}
|
||||
|
||||
public void saveHomeSectorList(List<HomeSector> sectors) {
|
||||
Preferences.setHomeSectorList(sectors);
|
||||
}
|
||||
|
||||
public void resetHomeSectorList() {
|
||||
Preferences.setHomeSectorList(null);
|
||||
}
|
||||
|
||||
public void closeDialog() {
|
||||
sectors = null;
|
||||
}
|
||||
|
||||
private List<HomeSector> fillStandardHomeSectorList() {
|
||||
List<HomeSector> sectors = new ArrayList<>();
|
||||
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_DISCOVERY, getApplication().getString(R.string.home_title_discovery), true, 1));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_MADE_FOR_YOU, getApplication().getString(R.string.home_title_made_for_you), true, 2));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_BEST_OF, getApplication().getString(R.string.home_title_best_of), true, 3));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_RADIO_STATION, getApplication().getString(R.string.home_title_radio_station), true, 4));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_TOP_SONGS, getApplication().getString(R.string.home_title_top_songs), true, 5));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_STARRED_TRACKS, getApplication().getString(R.string.home_title_starred_tracks), true, 6));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_STARRED_ALBUMS, getApplication().getString(R.string.home_title_starred_albums), true, 7));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_STARRED_ARTISTS, getApplication().getString(R.string.home_title_starred_artists), true, 8));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_NEW_RELEASES, getApplication().getString(R.string.home_title_new_releases), true, 9));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_FLASHBACK, getApplication().getString(R.string.home_title_flashback), true, 10));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_MOST_PLAYED, getApplication().getString(R.string.home_title_most_played), true, 11));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_LAST_PLAYED, getApplication().getString(R.string.home_title_last_played), true, 12));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_RECENTLY_ADDED, getApplication().getString(R.string.home_title_recently_added), true, 13));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_SHARED, getApplication().getString(R.string.home_title_shares), true, 14));
|
||||
|
||||
return sectors;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import androidx.lifecycle.MutableLiveData;
|
||||
import com.cappielloantonio.tempo.interfaces.StarCallback;
|
||||
import com.cappielloantonio.tempo.model.Chronology;
|
||||
import com.cappielloantonio.tempo.model.Favorite;
|
||||
import com.cappielloantonio.tempo.model.HomeSector;
|
||||
import com.cappielloantonio.tempo.repository.AlbumRepository;
|
||||
import com.cappielloantonio.tempo.repository.ArtistRepository;
|
||||
import com.cappielloantonio.tempo.repository.ChronologyRepository;
|
||||
@@ -22,6 +23,8 @@ 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.Preferences;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
@@ -59,10 +62,13 @@ public class HomeViewModel extends AndroidViewModel {
|
||||
private final MutableLiveData<List<Child>> artistBestOf = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Share>> shares = new MutableLiveData<>(null);
|
||||
|
||||
private List<HomeSector> sectors;
|
||||
|
||||
public HomeViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
||||
setHomeSectorList();
|
||||
|
||||
songRepository = new SongRepository();
|
||||
albumRepository = new AlbumRepository();
|
||||
artistRepository = new ArtistRepository();
|
||||
@@ -266,6 +272,26 @@ public class HomeViewModel extends AndroidViewModel {
|
||||
sharingRepository.getShares().observe(owner, this.shares::postValue);
|
||||
}
|
||||
|
||||
private void setHomeSectorList() {
|
||||
if (Preferences.getHomeSectorList() != null && !Preferences.getHomeSectorList().equals("null")) {
|
||||
sectors = new Gson().fromJson(
|
||||
Preferences.getHomeSectorList(),
|
||||
new TypeToken<List<HomeSector>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public List<HomeSector> getHomeSectorList() {
|
||||
return sectors;
|
||||
}
|
||||
|
||||
public boolean checkHomeSectorVisibility(String sectorId) {
|
||||
return sectors != null && sectors.stream().filter(sector -> sector.getId().equals(sectorId))
|
||||
.findAny()
|
||||
.orElse(null) == null;
|
||||
}
|
||||
|
||||
public void setOfflineFavorite() {
|
||||
ArrayList<Favorite> favorites = getFavorites();
|
||||
ArrayList<Favorite> favoritesToSave = getFavoritesToSave(favorites);
|
||||
|
||||
@@ -8,6 +8,10 @@ import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.cappielloantonio.tempo.repository.QueueRepository;
|
||||
import com.cappielloantonio.tempo.repository.SystemRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.OpenSubsonicExtension;
|
||||
import com.cappielloantonio.tempo.subsonic.models.SubsonicResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MainViewModel extends AndroidViewModel {
|
||||
private static final String TAG = "SearchViewModel";
|
||||
@@ -25,7 +29,11 @@ public class MainViewModel extends AndroidViewModel {
|
||||
return queueRepository.count() != 0;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> ping() {
|
||||
public LiveData<SubsonicResponse> ping() {
|
||||
return systemRepository.ping();
|
||||
}
|
||||
|
||||
public LiveData<List<OpenSubsonicExtension>> getOpenSubsonicExtensions() {
|
||||
return systemRepository.getOpenSubsonicExtensions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,15 +16,18 @@ import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.model.Queue;
|
||||
import com.cappielloantonio.tempo.repository.ArtistRepository;
|
||||
import com.cappielloantonio.tempo.repository.FavoriteRepository;
|
||||
import com.cappielloantonio.tempo.repository.OpenRepository;
|
||||
import com.cappielloantonio.tempo.repository.QueueRepository;
|
||||
import com.cappielloantonio.tempo.repository.SongRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.subsonic.models.LyricsList;
|
||||
import com.cappielloantonio.tempo.subsonic.models.PlayQueue;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.NetworkUtil;
|
||||
import com.cappielloantonio.tempo.util.OpenSubsonicExtensionsUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -40,13 +43,14 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
||||
private final ArtistRepository artistRepository;
|
||||
private final QueueRepository queueRepository;
|
||||
private final FavoriteRepository favoriteRepository;
|
||||
|
||||
private final OpenRepository openRepository;
|
||||
private final MutableLiveData<String> lyricsLiveData = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<LyricsList> lyricsListLiveData = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<String> descriptionLiveData = new MutableLiveData<>(null);
|
||||
|
||||
private final MutableLiveData<Child> liveMedia = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<ArtistID3> liveArtist = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Child>> instantMix = new MutableLiveData<>(null);
|
||||
private boolean lyricsSyncState = true;
|
||||
|
||||
|
||||
public PlayerBottomSheetViewModel(@NonNull Application application) {
|
||||
@@ -56,6 +60,7 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
||||
artistRepository = new ArtistRepository();
|
||||
queueRepository = new QueueRepository();
|
||||
favoriteRepository = new FavoriteRepository();
|
||||
openRepository = new OpenRepository();
|
||||
}
|
||||
|
||||
public LiveData<List<Queue>> getQueueSong() {
|
||||
@@ -125,8 +130,18 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
||||
return lyricsLiveData;
|
||||
}
|
||||
|
||||
public LiveData<LyricsList> getLiveLyricsList() {
|
||||
return lyricsListLiveData;
|
||||
}
|
||||
|
||||
public void refreshMediaInfo(LifecycleOwner owner, Child media) {
|
||||
songRepository.getSongLyrics(media).observe(owner, lyricsLiveData::postValue);
|
||||
if (OpenSubsonicExtensionsUtil.isSongLyricsExtensionAvailable()) {
|
||||
openRepository.getLyricsBySongId(media.getId()).observe(owner, lyricsListLiveData::postValue);
|
||||
lyricsLiveData.postValue(null);
|
||||
} else {
|
||||
songRepository.getSongLyrics(media).observe(owner, lyricsLiveData::postValue);
|
||||
lyricsListLiveData.postValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
public LiveData<Child> getLiveMedia() {
|
||||
@@ -196,4 +211,12 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void changeSyncLyricsState() {
|
||||
lyricsSyncState = !lyricsSyncState;
|
||||
}
|
||||
|
||||
public boolean getSyncLyricsState() {
|
||||
return lyricsSyncState;
|
||||
}
|
||||
}
|
||||
|
||||
9
app/src/main/res/drawable/ic_arrow_down.xml
Normal file
9
app/src/main/res/drawable/ic_arrow_down.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="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@color/titleTextColor"
|
||||
android:pathData="M480,600L280,400L680,400L480,600Z"/>
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@color/titleTextColor"
|
||||
android:pathData="M19,9H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM5,15h14c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z" />
|
||||
</vector>
|
||||
android:pathData="M228.29,600Q213,600 202.5,589.71Q192,579.42 192,564.21Q192,549 202.34,538.5Q212.69,528 227.98,528L731.71,528Q747,528 757.5,538.29Q768,548.58 768,563.79Q768,579 757.66,589.5Q747.31,600 732.02,600L228.29,600ZM228.29,432Q213,432 202.5,421.71Q192,411.42 192,396.21Q192,381 202.34,370.5Q212.69,360 227.98,360L731.71,360Q747,360 757.5,370.29Q768,380.58 768,395.79Q768,411 757.66,421.5Q747.31,432 732.02,432L228.29,432Z" />
|
||||
</vector>
|
||||
@@ -4,6 +4,6 @@
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/colorOnPrimaryContainer"
|
||||
android:fillColor="@color/titleTextColor"
|
||||
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z" />
|
||||
</vector>
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/colorOnPrimaryContainer"
|
||||
android:fillColor="@color/titleTextColor"
|
||||
android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3 4.42,3 2,5.42 2,8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5 22,5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z" />
|
||||
</vector>
|
||||
|
||||
9
app/src/main/res/drawable/ic_lyrics_sync_lock.xml
Normal file
9
app/src/main/res/drawable/ic_lyrics_sync_lock.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="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@color/titleTextColor"
|
||||
android:pathData="M160,800L160,720L269,720Q218,676 189,614Q160,552 160,480Q160,368 228,282.5Q296,197 400,170L400,254Q330,279 285,340.5Q240,402 240,480Q240,534 261.5,579.5Q283,625 320,658L320,560L400,560L400,800L160,800ZM720,480Q720,429 699.5,384.5Q679,340 640,302L640,400L560,400L560,160L800,160L800,240L691,240Q750,293 774.5,353.5Q799,414 800,480L720,480ZM640,880Q623,880 611.5,868.5Q600,857 600,840L600,720Q600,703 611.5,691.5Q623,680 640,680L640,680L640,640Q640,607 663.5,583.5Q687,560 720,560Q753,560 776.5,583.5Q800,607 800,640L800,680L800,680Q817,680 828.5,691.5Q840,703 840,720L840,840Q840,857 828.5,868.5Q817,880 800,880L640,880ZM680,680L760,680L760,640Q760,623 748.5,611.5Q737,600 720,600Q703,600 691.5,611.5Q680,623 680,640L680,680Z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_star.xml
Normal file
9
app/src/main/res/drawable/ic_star.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="960"
|
||||
android:viewportWidth="960"
|
||||
android:width="24dp">
|
||||
<path
|
||||
android:fillColor="@color/titleTextColor"
|
||||
android:pathData="M233,840L298,559L80,370L368,345L480,80L592,345L880,370L662,559L727,840L480,691L233,840Z" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_star_outlined.xml
Normal file
9
app/src/main/res/drawable/ic_star_outlined.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="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@color/titleTextColor"
|
||||
android:pathData="M354,673L480,597L606,674L573,530L684,434L538,421L480,285L422,420L276,433L387,530L354,673ZM233,840L298,559L80,370L368,345L480,80L592,345L880,370L662,559L727,840L480,691L233,840ZM480,490L480,490L480,490L480,490L480,490L480,490L480,490L480,490L480,490L480,490L480,490Z" />
|
||||
</vector>
|
||||
23
app/src/main/res/layout/dialog_home_rearrangement.xml
Normal file
23
app/src/main/res/layout/dialog_home_rearrangement.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
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/home_rearrangement_dialog_subtitle" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/home_sector_item_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:paddingHorizontal="18dp" />
|
||||
</LinearLayout>
|
||||
@@ -1,98 +1,117 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/home_radio_station_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true">
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/server_name_text_view"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/server_signup_dialog_hint_name"
|
||||
android:inputType="textNoSuggestions"
|
||||
android:textCursorDrawable="@null" />
|
||||
android:orientation="vertical">
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/server_name_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/server_signup_dialog_hint_name"
|
||||
android:inputType="textNoSuggestions"
|
||||
android:textCursorDrawable="@null" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/username_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/server_signup_dialog_hint_username"
|
||||
android:inputType="textShortMessage"
|
||||
android:textCursorDrawable="@null" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:endIconMode="password_toggle"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/username_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/server_signup_dialog_hint_username"
|
||||
android:inputType="textShortMessage"
|
||||
android:textCursorDrawable="@null" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/password_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/server_signup_dialog_hint_password"
|
||||
android:inputType="textPassword"
|
||||
android:textCursorDrawable="@null" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:endIconMode="password_toggle"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/password_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/server_signup_dialog_hint_password"
|
||||
android:inputType="textPassword"
|
||||
android:textCursorDrawable="@null" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/server_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/server_signup_dialog_hint_url"
|
||||
android:inputType="textNoSuggestions"
|
||||
android:textCursorDrawable="@null" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/low_security_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="@string/server_signup_dialog_action_low_security" />
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/server_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/server_signup_dialog_hint_url"
|
||||
android:inputType="textNoSuggestions"
|
||||
android:textCursorDrawable="@null" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/low_security_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="@string/server_signup_dialog_action_low_security" />
|
||||
</LinearLayout>
|
||||
@@ -58,6 +58,20 @@
|
||||
app:icon="@drawable/ic_sort_list"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/album_list_progress_loader"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
||||
@@ -48,18 +48,33 @@
|
||||
style="@style/LabelExtraLarge"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="18dp"
|
||||
android:layout_marginEnd="18dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:paddingTop="8dp"
|
||||
android:singleLine="false"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@+id/album_cover_image_view"
|
||||
app:layout_constraintStart_toStartOf="@+id/album_cover_image_view"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_cover_image_view" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/album_other_info_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/album_name_label"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_name_label"
|
||||
app:layout_constraintTop_toTopOf="@+id/album_name_label"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:background="@drawable/ic_arrow_down" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/album_artist_label"
|
||||
style="@style/LabelMedium"
|
||||
@@ -88,6 +103,62 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_artist_label" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/album_detail_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_release_year_label"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/album_genres_textview"
|
||||
style="@style/LabelSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="18dp"
|
||||
android:layout_marginEnd="18dp"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/album_song_count_duration_textview"
|
||||
style="@style/LabelSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="2dp"
|
||||
android:layout_marginStart="18dp"
|
||||
android:layout_marginEnd="18dp"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_genres_textview" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/album_notes_textview"
|
||||
style="@style/LabelSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="18dp"
|
||||
android:layout_marginEnd="18dp"
|
||||
android:text="@string/label_placeholder"
|
||||
android:justificationMode="inter_word"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_song_count_duration_textview" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/upper_button_divider"
|
||||
style="@style/Divider"
|
||||
@@ -96,7 +167,7 @@
|
||||
android:layout_marginEnd="18dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_release_year_label" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_detail_view" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/album_page_button_layout"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
@@ -110,7 +111,9 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="22dp">
|
||||
android:paddingBottom="22dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -146,18 +149,15 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/artist_page_bio_placeholder"
|
||||
layout="@layout/item_placehoder_biography"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
android:id="@+id/artist_page_top_songs_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="22dp">
|
||||
android:paddingBottom="22dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -193,55 +193,24 @@
|
||||
android:paddingTop="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/artist_page_top_tracks_placeholder"
|
||||
layout="@layout/item_placeholder_horizontal"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/artist_page_albums_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<LinearLayout
|
||||
<TextView
|
||||
style="@style/TitleLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
style="@style/TitleLarge"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/artist_page_title_album_section" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/artist_page_albums_switch_layout_text_view_clickable"
|
||||
style="@style/TitleMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/artist_page_switch_layout_button" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/albums_horizontal_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="visible"/>
|
||||
android:text="@string/artist_page_title_album_section" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/albums_vertical_recycler_view"
|
||||
android:id="@+id/albums_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="8dp"
|
||||
@@ -250,20 +219,16 @@
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"/>
|
||||
android:paddingBottom="8dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/artist_page_album_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/similar_artist_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
style="@style/TitleLarge"
|
||||
@@ -283,16 +248,10 @@
|
||||
android:clipToPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/artist_page_similar_artist_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
@@ -68,7 +69,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="@dimen/global_padding_bottom">
|
||||
android:paddingBottom="@dimen/global_padding_bottom"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/downloaded_text_view_refreshable"
|
||||
@@ -124,14 +127,6 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/shuffle_downloaded_text_view_clickable" />
|
||||
|
||||
<include
|
||||
android:id="@+id/download_downloaded_placeholder"
|
||||
layout="@layout/item_placeholder_horizontal"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/downloaded_text_view_refreshable" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/fragment_home_nested_scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -29,8 +29,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingVertical="12dp"
|
||||
android:paddingHorizontal="20dp">
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingVertical="12dp">
|
||||
|
||||
<!-- Title, secondary and supporting text -->
|
||||
<TextView
|
||||
@@ -111,17 +111,19 @@
|
||||
android:id="@+id/home_discover_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/discovery_text_view_refreshable"
|
||||
@@ -153,17 +155,14 @@
|
||||
android:paddingBottom="16dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/home_discovery_placeholder"
|
||||
layout="@layout/item_placehoder_discovery"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Similar tracks -->
|
||||
<LinearLayout
|
||||
android:id="@+id/home_similar_tracks_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/similar_tracks_pre_text_view"
|
||||
@@ -171,7 +170,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_subtitle_made_for_you"
|
||||
android:textAllCaps="true" />
|
||||
@@ -198,17 +197,14 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/home_similar_tracks_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Best of -->
|
||||
<LinearLayout
|
||||
android:id="@+id/home_best_of_artist_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/most_streamed_song_pre_text_view"
|
||||
@@ -216,7 +212,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_subtitle_best_of"
|
||||
android:textAllCaps="true" />
|
||||
@@ -243,17 +239,14 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/home_best_of_artist_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Radio Artist -->
|
||||
<LinearLayout
|
||||
android:id="@+id/home_radio_artist_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/radio_artist_text_view_refreshable"
|
||||
@@ -261,7 +254,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_title_radio_station" />
|
||||
|
||||
@@ -278,18 +271,15 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/home_radio_artist_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
<View
|
||||
android:id="@+id/after_radio_artist_divider"
|
||||
style="@style/Divider"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp" />
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!-- Grid tracks -->
|
||||
<LinearLayout
|
||||
@@ -297,7 +287,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grid_tracks_pre_text_view"
|
||||
@@ -305,7 +296,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_title_last_week"
|
||||
android:textAllCaps="true" />
|
||||
@@ -336,16 +327,20 @@
|
||||
android:id="@+id/after_grid_divider"
|
||||
style="@style/Divider"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp" />
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!-- Favorites -->
|
||||
<LinearLayout
|
||||
android:id="@+id/starred_tracks_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
@@ -353,8 +348,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/starred_tracks_text_view_refreshable"
|
||||
@@ -387,16 +383,13 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/starred_tracks_placeholder"
|
||||
layout="@layout/item_placeholder_horizontal"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/starred_albums_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
@@ -404,8 +397,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/starred_albums_text_view_refreshable"
|
||||
@@ -414,7 +408,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_starred_albums" />
|
||||
|
||||
@@ -424,7 +417,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_starred_albums_see_all_button" />
|
||||
</LinearLayout>
|
||||
@@ -440,16 +432,13 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/starred_albums_placeholder"
|
||||
layout="@layout/item_placeholder_horizontal"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/starred_artists_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
@@ -457,8 +446,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/starred_artists_text_view_refreshable"
|
||||
@@ -467,7 +457,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_starred_artists" />
|
||||
|
||||
@@ -477,7 +466,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_starred_artists_see_all_button" />
|
||||
</LinearLayout>
|
||||
@@ -493,25 +481,23 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/starred_artists_placeholder"
|
||||
layout="@layout/item_placeholder_horizontal"
|
||||
android:visibility="gone" />
|
||||
|
||||
<View
|
||||
android:id="@+id/after_favorites_divider"
|
||||
style="@style/Divider"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp" />
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/home_new_releases_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- New releases -->
|
||||
<TextView
|
||||
@@ -519,7 +505,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_title_new_releases" />
|
||||
|
||||
@@ -534,17 +520,14 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/home_new_releases_placeholder"
|
||||
layout="@layout/item_placeholder_horizontal"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Fashback -->
|
||||
<LinearLayout
|
||||
android:id="@+id/home_flashback_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Label and button -->
|
||||
<TextView
|
||||
@@ -552,7 +535,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_title_flashback" />
|
||||
|
||||
@@ -569,17 +552,14 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/home_flashback_placeholder"
|
||||
layout="@layout/item_placeholder_year"
|
||||
android:visibility="gone" />
|
||||
|
||||
<View
|
||||
style="@style/Divider"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp" />
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!-- Most played albums -->
|
||||
<LinearLayout
|
||||
@@ -587,7 +567,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
@@ -595,8 +576,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/most_played_albums_text_view_refreshable"
|
||||
@@ -605,7 +587,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_most_played" />
|
||||
|
||||
@@ -615,7 +596,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_most_played_see_all_button" />
|
||||
</LinearLayout>
|
||||
@@ -633,17 +613,14 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/home_most_played_albums_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Recently played albums -->
|
||||
<LinearLayout
|
||||
android:id="@+id/home_recently_played_albums_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
@@ -651,8 +628,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recently_played_albums_text_view_refreshable"
|
||||
@@ -661,7 +639,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_last_played" />
|
||||
|
||||
@@ -672,7 +649,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_last_played_see_all_button" />
|
||||
|
||||
@@ -691,17 +667,14 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/home_recently_played_albums_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Recently added albums -->
|
||||
<LinearLayout
|
||||
android:id="@+id/home_recently_added_albums_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
@@ -709,8 +682,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recently_added_albums_text_view_refreshable"
|
||||
@@ -719,7 +693,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_recently_added" />
|
||||
|
||||
@@ -730,7 +703,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/home_title_recently_added_see_all_button" />
|
||||
|
||||
@@ -749,26 +721,22 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/home_recently_added_albums_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Shares -->
|
||||
<LinearLayout
|
||||
android:id="@+id/shares_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/shares_text_view_refreshable"
|
||||
style="@style/TitleLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_title_shares" />
|
||||
|
||||
@@ -783,10 +751,15 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/shares_placeholder"
|
||||
layout="@layout/item_placeholder_horizontal"
|
||||
android:visibility="gone" />
|
||||
<Button
|
||||
android:id="@+id/home_sector_rearrangement_button"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/home_option_reorganize"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
@@ -24,7 +25,9 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/podcast_channels_pre_text_view"
|
||||
@@ -84,7 +87,9 @@
|
||||
android:id="@+id/home_newest_podcasts_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
style="@style/TitleLarge"
|
||||
@@ -106,12 +111,6 @@
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:paddingTop="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/podcast_episodes_placeholder"
|
||||
layout="@layout/item_placeholder_horizontal"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
@@ -29,7 +30,9 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
style="@style/TitleLarge"
|
||||
@@ -49,23 +52,19 @@
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:clipToPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="4dp" />
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/library_music_folder_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Album -->
|
||||
<LinearLayout
|
||||
android:id="@+id/library_album_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Album -->
|
||||
<!-- Label and button -->
|
||||
@@ -74,8 +73,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/album_catalogue_sample_text_view_refreshable"
|
||||
@@ -84,7 +84,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/library_title_album" />
|
||||
|
||||
@@ -94,7 +93,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/library_title_album_see_all_button" />
|
||||
|
||||
@@ -113,17 +111,13 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/library_album_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/library_artist_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Artist -->
|
||||
<!-- Label and button -->
|
||||
@@ -132,8 +126,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/artist_catalogue_sample_text_view_refreshable"
|
||||
@@ -142,7 +137,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/library_title_artist" />
|
||||
|
||||
@@ -153,7 +147,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/library_title_artist_see_all_button" />
|
||||
|
||||
@@ -172,17 +165,13 @@
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/library_artist_placeholder"
|
||||
layout="@layout/item_placeholder_album"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/library_genres_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Genre -->
|
||||
<!-- Label and button -->
|
||||
@@ -191,8 +180,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/genre_catalogue_sample_text_view_refreshable"
|
||||
@@ -201,7 +191,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/library_title_genre" />
|
||||
|
||||
@@ -212,7 +201,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/library_title_genre_see_all_button" />
|
||||
</LinearLayout>
|
||||
@@ -229,17 +217,13 @@
|
||||
android:paddingEnd="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/library_genre_placeholder"
|
||||
layout="@layout/item_placeholder_genre"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/library_playlist_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Playlist -->
|
||||
<!-- Label and button -->
|
||||
@@ -248,8 +232,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/playlist_catalogue_sample_text_view_refreshable"
|
||||
@@ -258,7 +243,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/library_title_playlist" />
|
||||
|
||||
@@ -268,7 +252,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="@string/library_title_playlist_see_all_button" />
|
||||
|
||||
@@ -285,11 +268,6 @@
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/library_playlist_placeholder"
|
||||
layout="@layout/item_placeholder_horizontal"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -32,6 +32,7 @@
|
||||
app:layout_constraintTop_toBottomOf="@+id/empty_description_image_view" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/now_playing_song_lyrics_sroll_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
@@ -49,4 +50,32 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/sync_lyrics_tap_button"
|
||||
style="@style/Widget.Material3.Button.TonalButton.Icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_margin="16dp"
|
||||
android:insetLeft="0dp"
|
||||
android:insetTop="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:insetBottom="0dp"
|
||||
app:cornerRadius="64dp"
|
||||
android:alpha="0.7"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_lyrics_sync_lock"
|
||||
app:layout_constraintEnd_toEndOf="@+id/now_playing_song_lyrics_sroll_view"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/now_playing_song_lyrics_sroll_view" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/temp_lyrics_line_text_view"
|
||||
style="@style/BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:visibility="invisible"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
26
app/src/main/res/layout/item_horizontal_home_sector.xml
Normal file
26
app/src/main/res/layout/item_horizontal_home_sector.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clipChildren="false"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/home_sector_title_check_box"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_sector_rearranger_image_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_drag_handle"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/home_sector_title_check_box"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/home_sector_title_check_box" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,5 +1,6 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
@@ -58,7 +59,7 @@
|
||||
android:singleLine="true"
|
||||
android:text="@string/label_placeholder"
|
||||
app:layout_constraintBottom_toTopOf="@+id/search_result_song_subtitle_text_view"
|
||||
app:layout_constraintEnd_toStartOf="@+id/search_result_dowanload_indicator_image_view"
|
||||
app:layout_constraintEnd_toStartOf="@+id/rating_indicator_image_view"
|
||||
app:layout_constraintStart_toEndOf="@+id/cover_image_separator"
|
||||
app:layout_constraintTop_toTopOf="@+id/song_cover_image_view"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
@@ -73,20 +74,85 @@
|
||||
android:singleLine="true"
|
||||
android:text="@string/label_placeholder"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/song_cover_image_view"
|
||||
app:layout_constraintEnd_toStartOf="@+id/search_result_dowanload_indicator_image_view"
|
||||
app:layout_constraintEnd_toStartOf="@+id/rating_indicator_image_view"
|
||||
app:layout_constraintStart_toEndOf="@+id/cover_image_separator"
|
||||
app:layout_constraintTop_toBottomOf="@+id/search_result_song_title_text_view" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/rating_indicator_image_view"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/song_cover_image_view"
|
||||
app:layout_constraintEnd_toStartOf="@+id/search_result_download_indicator_image_view"
|
||||
app:layout_constraintStart_toEndOf="@+id/search_result_song_title_text_view"
|
||||
app:layout_constraintTop_toTopOf="@+id/song_cover_image_view">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/preferred_icon"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:background="@drawable/ic_favorite"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rating_bar_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/preferred_icon">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/one_star_icon"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
tools:src="@drawable/ic_star" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/two_star_icon"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
tools:src="@drawable/ic_star" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/three_star_icon"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
tools:src="@drawable/ic_star" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/four_star_icon"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
tools:src="@drawable/ic_star" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/five_star_icon"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
tools:src="@drawable/ic_star" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/search_result_dowanload_indicator_image_view"
|
||||
android:id="@+id/search_result_download_indicator_image_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/song_cover_image_view"
|
||||
app:layout_constraintEnd_toStartOf="@+id/search_result_song_more_button"
|
||||
app:layout_constraintStart_toEndOf="@+id/search_result_song_title_text_view"
|
||||
app:layout_constraintTop_toTopOf="@+id/song_cover_image_view">
|
||||
app:layout_constraintStart_toEndOf="@+id/rating_indicator_image_view"
|
||||
app:layout_constraintTop_toTopOf="@+id/song_cover_image_view"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="18dp"
|
||||
@@ -102,7 +168,7 @@
|
||||
android:padding="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/song_cover_image_view"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/search_result_dowanload_indicator_image_view"
|
||||
app:layout_constraintStart_toEndOf="@+id/search_result_download_indicator_image_view"
|
||||
app:layout_constraintTop_toTopOf="@+id/song_cover_image_view">
|
||||
|
||||
<ImageView
|
||||
|
||||
@@ -31,10 +31,16 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:paddingBottom="16dp"
|
||||
android:singleLine="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_name_label" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/artist_name_label"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,43 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/placeholder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="9"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="156dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
@@ -1,43 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/placeholder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="9"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="190dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/placeholder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="8"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="22dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="2"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="172dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="112dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="172dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="112dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="172dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="112dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,110 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/placeholder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,294 +0,0 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/placeholder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="8"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="22dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="2"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_cover_placeholder_1"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="2dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_title_placeholder_1"
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover_placeholder_1"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover_placeholder_1"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_title_placeholder_1" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingBottom="3dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_cover_placeholder_2"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="2dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_title_placeholder_2"
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover_placeholder_2"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover_placeholder_2"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_title_placeholder_2" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingBottom="3dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_cover_placeholder_3"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="2dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_title_placeholder_3"
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover_placeholder_3"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover_placeholder_3"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_title_placeholder_3" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingBottom="3dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_cover_placeholder_4"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="2dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_title_placeholder_4"
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover_placeholder_4"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover_placeholder_4"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_title_placeholder_4" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingBottom="3dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_cover_placeholder_5"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="2dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_title_placeholder_5"
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover_placeholder_5"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover_placeholder_5"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_title_placeholder_5" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/placeholder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="8"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="22dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="2"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="172dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="112dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="172dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="112dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="172dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="124dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="112dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/placeholder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="72dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="72dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="72dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorSurface" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,11 +1,12 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingBottom="3dp">
|
||||
|
||||
@@ -30,9 +31,11 @@
|
||||
android:paddingEnd="12dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/label_placeholder"
|
||||
app:layout_constraintEnd_toStartOf="@+id/queue_song_holder_image"
|
||||
app:layout_constraintEnd_toStartOf="@+id/rating_indicator_image_view"
|
||||
app:layout_constraintStart_toEndOf="@+id/queue_song_cover_image_view"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="@id/queue_song_cover_image_view"
|
||||
app:layout_constraintBottom_toTopOf="@id/queue_song_subtitle_text_view"
|
||||
app:layout_constraintVertical_chainStyle="packed"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/queue_song_subtitle_text_view"
|
||||
@@ -45,19 +48,84 @@
|
||||
android:singleLine="true"
|
||||
android:text="@string/label_placeholder"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/queue_song_holder_image"
|
||||
app:layout_constraintEnd_toEndOf="@+id/queue_song_title_text_view"
|
||||
app:layout_constraintStart_toEndOf="@+id/queue_song_cover_image_view"
|
||||
app:layout_constraintTop_toBottomOf="@+id/queue_song_title_text_view" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/queue_song_title_text_view"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/queue_song_cover_image_view"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/rating_indicator_image_view"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="8dp"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/queue_song_cover_image_view"
|
||||
app:layout_constraintEnd_toStartOf="@+id/queue_song_holder_image"
|
||||
app:layout_constraintStart_toEndOf="@+id/queue_song_title_text_view"
|
||||
app:layout_constraintTop_toTopOf="@+id/queue_song_cover_image_view">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/preferred_icon"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:background="@drawable/ic_favorite"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rating_bar_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/preferred_icon">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/one_star_icon"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
tools:src="@drawable/ic_star" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/two_star_icon"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
tools:src="@drawable/ic_star" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/three_star_icon"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
tools:src="@drawable/ic_star" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/four_star_icon"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
tools:src="@drawable/ic_star" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/five_star_icon"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
tools:src="@drawable/ic_star" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/queue_song_holder_image"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:src="@drawable/ic_drag_handle"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/queue_song_cover_image_view"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintStart_toEndOf="@+id/rating_indicator_image_view"
|
||||
app:layout_constraintTop_toTopOf="@+id/queue_song_cover_image_view" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -12,4 +12,7 @@
|
||||
<item
|
||||
android:id="@+id/menu_album_sort_random"
|
||||
android:title="@string/menu_sort_random" />
|
||||
<item
|
||||
android:id="@+id/menu_album_sort_recently_added"
|
||||
android:title="@string/menu_sort_recently_added" />
|
||||
</menu>
|
||||
@@ -313,7 +313,7 @@
|
||||
<string name="song_list_page_starred">Lieblingslieder</string>
|
||||
<string name="song_list_page_top">%1$s\'s Top Tracks</string>
|
||||
<string name="song_list_page_year">Jahr %1$d</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s %3$s</string>
|
||||
<string name="starred_sync_dialog_negative_button">Abbrechen</string>
|
||||
<string name="starred_sync_dialog_neutral_button">Weiter</string>
|
||||
<string name="starred_sync_dialog_positive_button">Weiter und Herunterladen</string>
|
||||
|
||||
@@ -328,7 +328,7 @@
|
||||
<string name="song_list_page_starred">Titres favoris</string>
|
||||
<string name="song_list_page_top">Les meilleurs titres de %1$s</string>
|
||||
<string name="song_list_page_year">Année %1$d</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s %3$s</string>
|
||||
<string name="starred_sync_dialog_negative_button">Annuler</string>
|
||||
<string name="starred_sync_dialog_neutral_button">Continuer</string>
|
||||
<string name="starred_sync_dialog_positive_button">Continuer et télécharger</string>
|
||||
|
||||
@@ -331,7 +331,7 @@
|
||||
<string name="song_list_page_starred">즐겨찾기한 트랙</string>
|
||||
<string name="song_list_page_top">%1$s\의 top tracks</string>
|
||||
<string name="song_list_page_year">년도 %1$d</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s %3$s</string>
|
||||
<string name="starred_sync_dialog_negative_button">취소</string>
|
||||
<string name="starred_sync_dialog_neutral_button">계속</string>
|
||||
<string name="starred_sync_dialog_positive_button">계속해서 다운로드</string>
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
<color name="subtitleTextColor">#9B9B9B</color>
|
||||
<color name="dividerColor">#404040</color>
|
||||
|
||||
<color name="lyricsTextColor">#DADADA</color>
|
||||
<color name="shadowsLyricsTextColor">#606060</color>
|
||||
|
||||
<color name="searchPlaceholderColor">#CFCFCF</color>
|
||||
<color name="searchColor">#DADADA</color>
|
||||
</resources>
|
||||
|
||||
242
app/src/main/res/values-pt/arrays.xml
Normal file
242
app/src/main/res/values-pt/arrays.xml
Normal file
@@ -0,0 +1,242 @@
|
||||
<resources>
|
||||
<string-array name="theme_list_titles">
|
||||
<item>Claro</item>
|
||||
<item>Escuro</item>
|
||||
<item>Padrão do sistema</item>
|
||||
</string-array>
|
||||
<string-array name="theme_list_values">
|
||||
<item>light</item>
|
||||
<item>dark</item>
|
||||
<item>default</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_cache_size_titles">
|
||||
<item>Alta</item>
|
||||
<item>Média</item>
|
||||
<item>Baixa</item>
|
||||
</string-array>
|
||||
<string-array name="pref_cache_size_values">
|
||||
<item>500</item>
|
||||
<item>250</item>
|
||||
<item>125</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_image_size_titles">
|
||||
<item>Alta</item>
|
||||
<item>Média</item>
|
||||
<item>Baixa</item>
|
||||
</string-array>
|
||||
<string-array name="pref_image_size_values">
|
||||
<item>-1</item>
|
||||
<item>500</item>
|
||||
<item>300</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="max_bitrate_wifi_list_titles">
|
||||
<item>Original</item>
|
||||
<item>32 kbps</item>
|
||||
<item>48 kbps</item>
|
||||
<item>64 kbps</item>
|
||||
<item>80 kbps</item>
|
||||
<item>96 kbps</item>
|
||||
<item>112 kbps</item>
|
||||
<item>128 kbps</item>
|
||||
<item>160 kbps</item>
|
||||
<item>192 kbps</item>
|
||||
<item>256 kbps</item>
|
||||
<item>320 kbps</item>
|
||||
</string-array>
|
||||
<string-array name="max_bitrate_wifi_list_values">
|
||||
<item>0</item>
|
||||
<item>32</item>
|
||||
<item>48</item>
|
||||
<item>64</item>
|
||||
<item>80</item>
|
||||
<item>96</item>
|
||||
<item>112</item>
|
||||
<item>128</item>
|
||||
<item>160</item>
|
||||
<item>192</item>
|
||||
<item>256</item>
|
||||
<item>320</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="max_bitrate_mobile_list_titles">
|
||||
<item>Original</item>
|
||||
<item>32 kbps</item>
|
||||
<item>48 kbps</item>
|
||||
<item>64 kbps</item>
|
||||
<item>80 kbps</item>
|
||||
<item>96 kbps</item>
|
||||
<item>112 kbps</item>
|
||||
<item>128 kbps</item>
|
||||
<item>160 kbps</item>
|
||||
<item>192 kbps</item>
|
||||
<item>256 kbps</item>
|
||||
<item>320 kbps</item>
|
||||
</string-array>
|
||||
<string-array name="max_bitrate_mobile_list_values">
|
||||
<item>0</item>
|
||||
<item>32</item>
|
||||
<item>48</item>
|
||||
<item>64</item>
|
||||
<item>80</item>
|
||||
<item>96</item>
|
||||
<item>112</item>
|
||||
<item>128</item>
|
||||
<item>160</item>
|
||||
<item>192</item>
|
||||
<item>256</item>
|
||||
<item>320</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="max_bitrate_download_list_titles">
|
||||
<item>Original</item>
|
||||
<item>32 kbps</item>
|
||||
<item>48 kbps</item>
|
||||
<item>64 kbps</item>
|
||||
<item>80 kbps</item>
|
||||
<item>96 kbps</item>
|
||||
<item>112 kbps</item>
|
||||
<item>128 kbps</item>
|
||||
<item>160 kbps</item>
|
||||
<item>192 kbps</item>
|
||||
<item>256 kbps</item>
|
||||
<item>320 kbps</item>
|
||||
</string-array>
|
||||
<string-array name="max_bitrate_download_list_values">
|
||||
<item>0</item>
|
||||
<item>32</item>
|
||||
<item>48</item>
|
||||
<item>64</item>
|
||||
<item>80</item>
|
||||
<item>96</item>
|
||||
<item>112</item>
|
||||
<item>128</item>
|
||||
<item>160</item>
|
||||
<item>192</item>
|
||||
<item>256</item>
|
||||
<item>320</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="audio_transcode_format_wifi_list_titles">
|
||||
<item>Reprodução direta</item>
|
||||
<item>Opus</item>
|
||||
<item>AAC</item>
|
||||
<item>Mp3</item>
|
||||
<item>Flac</item>
|
||||
</string-array>
|
||||
<string-array name="audio_transcode_format_wifi_list_values">
|
||||
<item>raw</item>
|
||||
<item>opus</item>
|
||||
<item>aac</item>
|
||||
<item>mp3</item>
|
||||
<item>flac</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="audio_transcode_format_mobile_list_titles">
|
||||
<item>Reprodução direta</item>
|
||||
<item>Opus</item>
|
||||
<item>AAC</item>
|
||||
<item>Mp3</item>
|
||||
<item>Flac</item>
|
||||
</string-array>
|
||||
<string-array name="audio_transcode_format_mobile_list_values">
|
||||
<item>raw</item>
|
||||
<item>opus</item>
|
||||
<item>aac</item>
|
||||
<item>mp3</item>
|
||||
<item>flac</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="audio_transcode_format_download_list_titles">
|
||||
<item>Download direto</item>
|
||||
<item>Opus</item>
|
||||
<item>AAC</item>
|
||||
<item>Mp3</item>
|
||||
<item>Flac</item>
|
||||
</string-array>
|
||||
<string-array name="audio_transcode_format_download_list_values">
|
||||
<item>raw</item>
|
||||
<item>opus</item>
|
||||
<item>aac</item>
|
||||
<item>mp3</item>
|
||||
<item>flac</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="queue_syncing_countdown_titles">
|
||||
<item>Dez segundos</item>
|
||||
<item>Cinco segundos</item>
|
||||
<item>Dois segundos</item>
|
||||
</string-array>
|
||||
<string-array name="queue_syncing_countdown_values">
|
||||
<item>10</item>
|
||||
<item>5</item>
|
||||
<item>2</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="rounded_corner_size_titles">
|
||||
<item>Alta</item>
|
||||
<item>Média</item>
|
||||
<item>Baixa</item>
|
||||
</string-array>
|
||||
<string-array name="rounded_corner_size_values">
|
||||
<item>18</item>
|
||||
<item>12</item>
|
||||
<item>6</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="replay_gain_titles">
|
||||
<item>Desabilitado</item>
|
||||
<item>Faixa</item>
|
||||
<item>Álbum</item>
|
||||
<item>Automático</item>
|
||||
</string-array>
|
||||
<string-array name="replay_gain_values">
|
||||
<item>disabled</item>
|
||||
<item>track</item>
|
||||
<item>album</item>
|
||||
<item>auto</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="transcoded_download_option_list_titles">
|
||||
<item>Não transcodifique</item>
|
||||
<item>Configurações do servidor</item>
|
||||
<item>Formato de transcodificação para Wi-Fi</item>
|
||||
<item>Formato de transcodificação para Rede Móvel</item>
|
||||
</string-array>
|
||||
<string-array name="transcoded_download_option_list_values">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="buffering_strategy_titles">
|
||||
<item>Mínimo</item>
|
||||
<item>Moderado</item>
|
||||
<item>Agressivo</item>
|
||||
<item>Extremo</item>
|
||||
</string-array>
|
||||
<string-array name="buffering_strategy_values">
|
||||
<item>.1</item>
|
||||
<item>1</item>
|
||||
<item>4</item>
|
||||
<item>8</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="skip_min_star_rating_titles">
|
||||
<item>No mínimo 0 estrelas</item>
|
||||
<item>No mínimo 1 estrela</item>
|
||||
<item>No mínimo 2 estrelas</item>
|
||||
<item>No mínimo 3 estrelas</item>
|
||||
<item>No mínimo 4 estrelas</item>
|
||||
</string-array>
|
||||
<string-array name="skip_min_star_rating_values">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
365
app/src/main/res/values-pt/strings.xml
Normal file
365
app/src/main/res/values-pt/strings.xml
Normal file
@@ -0,0 +1,365 @@
|
||||
<resources>
|
||||
<string name="activity_battery_optimizations_conclusion">Em caso de problemas, visite https://dontkillmyapp.com. Você encontrará instruções detalhadas sobre como desativar quaisquer recursos de economia de energia que possam afetar o desempenho do aplicativo.</string>
|
||||
<string name="activity_battery_optimizations_summary">Por favor, desative as otimizações de bateria para a reprodução de mídia enquanto a tela estiver desligada.</string>
|
||||
<string name="activity_battery_optimizations_title">Otimizações de bateria</string>
|
||||
<string name="activity_info_offline_mode">Modo offline</string>
|
||||
<string name="album_bottom_sheet_add_to_queue">Adicionar à fila</string>
|
||||
<string name="album_bottom_sheet_download_all">Baixar todos</string>
|
||||
<string name="album_bottom_sheet_go_to_artist">Ir para o(a) artista</string>
|
||||
<string name="album_bottom_sheet_instant_mix">Mixagem instantânea</string>
|
||||
<string name="album_bottom_sheet_play_next">Tocar em seguida</string>
|
||||
<string name="album_bottom_sheet_remove_all">Remover todos</string>
|
||||
<string name="album_bottom_sheet_share">Compartilhar</string>
|
||||
<string name="album_bottom_sheet_shuffle">Aleatório</string>
|
||||
<string name="album_catalogue_title">Álbuns</string>
|
||||
<string name="album_catalogue_title_expanded">Navegar pelos Álbuns</string>
|
||||
<string name="album_error_retrieving_artist">Erro ao recuperar artista</string>
|
||||
<string name="album_list_page_downloaded">Álbuns baixados</string>
|
||||
<string name="album_list_page_most_played">Álbuns mais reproduzidos</string>
|
||||
<string name="album_list_page_new_releases">Novos lançamentos</string>
|
||||
<string name="album_list_page_recently_added">Álbuns recém-adicionados</string>
|
||||
<string name="album_list_page_recently_played">Álbuns recém-reproduzidos</string>
|
||||
<string name="album_list_page_starred">Álbuns favoritos</string>
|
||||
<string name="album_list_page_title">Álbuns</string>
|
||||
<string name="album_page_extra_info_button">Sugestões semelhantes</string>
|
||||
<string name="album_page_play_button">Reproduzir</string>
|
||||
<string name="album_page_shuffle_button">Aleatório</string>
|
||||
<string name="app_name">Tempo</string>
|
||||
<string name="artist_adapter_radio_station_starting">Procurando…</string>
|
||||
<string name="artist_bottom_sheet_instant_mix">Mixagem instantânea</string>
|
||||
<string name="artist_bottom_sheet_shuffle">Aleatório</string>
|
||||
<string name="artist_catalogue_title">Artistas</string>
|
||||
<string name="artist_catalogue_title_expanded">Navegar pelos Artistas</string>
|
||||
<string name="artist_error_retrieving_radio">Erro ao recuperar rádio do artista</string>
|
||||
<string name="artist_error_retrieving_tracks">Erro ao recuperar faixas do artista</string>
|
||||
<string name="artist_list_page_downloaded">Artistas baixados</string>
|
||||
<string name="artist_list_page_starred">Artistas favoritos</string>
|
||||
<string name="artist_list_page_title">Artistas</string>
|
||||
<string name="artist_page_radio_button">Rádio</string>
|
||||
<string name="artist_page_shuffle_button">Aleatório</string>
|
||||
<string name="artist_page_switch_layout_button">Alternar layout</string>
|
||||
<string name="artist_page_title_album_more_like_this_button">Sugestões semelhantes</string>
|
||||
<string name="artist_page_title_album_section">Álbuns</string>
|
||||
<string name="artist_page_title_biography_more_button">Mais</string>
|
||||
<string name="artist_page_title_biography_section">Biografia</string>
|
||||
<string name="artist_page_title_most_streamed_song_section">Músicas Mais Tocadas</string>
|
||||
<string name="artist_page_title_most_streamed_song_see_all_button">Ver todos</string>
|
||||
<string name="battery_optimization_negative_button">Ignorar</string>
|
||||
<string name="battery_optimization_neutral_button">Não perguntar novamente</string>
|
||||
<string name="battery_optimization_positive_button">Desativar</string>
|
||||
<string name="connection_alert_dialog_negative_button">Cancelar</string>
|
||||
<string name="connection_alert_dialog_neutral_button">Ativar economia de dados</string>
|
||||
<string name="connection_alert_dialog_positive_button">OK</string>
|
||||
<string name="connection_alert_dialog_summary">O acesso ao servidor Subsonic em conexões que não sejam Wi-Fi foi restrito. Para impedir que este aviso apareça novamente, desative a verificação de conexão nas configurações do aplicativo.</string>
|
||||
<string name="connection_alert_dialog_title">Wi-Fi não conectado</string>
|
||||
<string name="delete_download_storage_dialog_negative_button">Cancelar</string>
|
||||
<string name="delete_download_storage_dialog_positive_button">Continuar</string>
|
||||
<string name="delete_download_storage_dialog_summary">Esteja ciente de que esta ação resultará na exclusão permanente de todos os itens baixados de todos os servidores.</string>
|
||||
<string name="delete_download_storage_dialog_title">Excluir itens salvos</string>
|
||||
<string name="description_empty_title">Nenhuma descrição disponível</string>
|
||||
<string name="download_directory_dialog_negative_button">Cancelar</string>
|
||||
<string name="download_directory_dialog_positive_button">Download</string>
|
||||
<string name="download_directory_dialog_summary">Todas as músicas desta pasta serão baixadas. As músicas presentes nas subpastas não serão baixadas.</string>
|
||||
<string name="download_directory_dialog_title">Baixar as músicas</string>
|
||||
<string name="download_info_empty_subtitle">Ao baixar uma música, você a encontrará aqui</string>
|
||||
<string name="download_info_empty_title">Ainda não há downloads!</string>
|
||||
<string name="download_item_multiple_subtitle_formatter">%1$s • %2$s itens</string>
|
||||
<string name="download_item_single_subtitle_formatter">%1$s itens</string>
|
||||
<string name="download_shuffle_all_subtitle">Aleatório</string>
|
||||
<string name="download_storage_dialog_sub_summary">Para que as alterações tenham efeito, reinicie o aplicativo.</string>
|
||||
<string name="download_storage_dialog_summary">Alterar o destino dos arquivos baixados de um armazenamento para outro resultará na exclusão imediata de todos os arquivos baixados anteriormente no outro armazenamento.</string>
|
||||
<string name="download_storage_dialog_title">Selecione a opção de armazenamento</string>
|
||||
<string name="download_storage_external_dialog_positive_button">Externo</string>
|
||||
<string name="download_storage_internal_dialog_negative_button">Interno</string>
|
||||
<string name="download_title_section">Downloads</string>
|
||||
<string name="downloaded_bottom_sheet_add_to_queue">Adicionar à fila</string>
|
||||
<string name="downloaded_bottom_sheet_play_next">Tocar em seguida</string>
|
||||
<string name="downloaded_bottom_sheet_remove">Remover</string>
|
||||
<string name="downloaded_bottom_sheet_remove_all">Remover todos</string>
|
||||
<string name="downloaded_bottom_sheet_shuffle">Aleatório</string>
|
||||
<string name="empty_string"></string>
|
||||
<string name="error_required">Obrigatório</string>
|
||||
<string name="error_server_prefix">É necessário que o método seja http ou https</string>
|
||||
<string name="exo_download_notification_channel_name">Downloads</string>
|
||||
<string name="filter_info_selection">Selecione dois ou mais filtros</string>
|
||||
<string name="filter_title">Filtro</string>
|
||||
<string name="filter_title_expanded">Filtrar por Gêneros</string>
|
||||
<string name="genre_catalogue_title">Catálogo de Gêneros</string>
|
||||
<string name="genre_catalogue_title_expanded">Navegar pelos Gêneros</string>
|
||||
<string name="home_subtitle_best_of">Músicas populares dos seus artistas favoritos</string>
|
||||
<string name="home_subtitle_made_for_you">Comece a mixagem de uma música que você favoritou</string>
|
||||
<string name="home_subtitle_new_internet_radio_station">Adicionar um novo rádio</string>
|
||||
<string name="home_subtitle_new_podcast_channel">Adicionar um novo canal de podcast</string>
|
||||
<string name="home_sync_starred_cancel">Cancelar</string>
|
||||
<string name="home_sync_starred_download">Download</string>
|
||||
<string name="home_sync_starred_subtitle">O download dessas faixas pode envolver um uso significativo de dados</string>
|
||||
<string name="home_sync_starred_title">Parece que existem algumas faixas favoritas para sincronizar</string>
|
||||
<string name="home_title_best_of">Melhor de</string>
|
||||
<string name="home_title_discovery">Descobrir</string>
|
||||
<string name="home_title_discovery_shuffle_all_button">Aleatório</string>
|
||||
<string name="home_title_flashback">Flashback</string>
|
||||
<string name="home_title_internet_radio_station">Estações de rádio via internet</string>
|
||||
<string name="home_title_last_played">Reproduções recentes</string>
|
||||
<string name="home_title_last_played_see_all_button">Ver todos</string>
|
||||
<string name="home_title_last_week">Semana passada</string>
|
||||
<string name="home_title_made_for_you">Feito para você</string>
|
||||
<string name="home_title_most_played">Mais reproduzidas</string>
|
||||
<string name="home_title_most_played_see_all_button">Ver todos</string>
|
||||
<string name="home_title_new_releases">Novos lançamentos</string>
|
||||
<string name="home_title_newest_podcasts">Podcasts mais recentes</string>
|
||||
<string name="home_title_podcast_channels">Canais</string>
|
||||
<string name="home_title_podcast_channels_see_all_button">Ver todos</string>
|
||||
<string name="home_title_radio_station">Estações de rádio</string>
|
||||
<string name="home_title_recently_added">Adicionado recentemente</string>
|
||||
<string name="home_title_recently_added_see_all_button">Ver todos</string>
|
||||
<string name="home_title_shares">Compartilhamentos</string>
|
||||
<string name="home_title_starred_albums">★ Álbuns favoritos</string>
|
||||
<string name="home_title_starred_albums_see_all_button">Ver todos</string>
|
||||
<string name="home_title_starred_artists">★ Artistas favoritos</string>
|
||||
<string name="home_title_starred_artists_see_all_button">Ver todos</string>
|
||||
<string name="home_title_starred_tracks">★ Músicas favoritas</string>
|
||||
<string name="home_title_starred_tracks_see_all_button">Ver todos</string>
|
||||
<string name="home_title_top_songs">Suas músicas mais ouvidas</string>
|
||||
<string name="library_title_album">Álbuns</string>
|
||||
<string name="library_title_album_see_all_button">Ver todos</string>
|
||||
<string name="library_title_artist">Artistas</string>
|
||||
<string name="library_title_artist_see_all_button">Ver todos</string>
|
||||
<string name="library_title_genre">Genêros</string>
|
||||
<string name="library_title_genre_see_all_button">Ver todos</string>
|
||||
<string name="library_title_music_folder">Pastas de música</string>
|
||||
<string name="library_title_playlist">Playlists</string>
|
||||
<string name="library_title_playlist_see_all_button">Ver todos</string>
|
||||
<string name="login_empty">Nenhum servidor adicionado</string>
|
||||
<string name="login_title">Servidores Subsonic</string>
|
||||
<string name="login_title_expanded">Servidores Subsonic</string>
|
||||
<string name="media_route_menu_title">Transmitir</string>
|
||||
<string name="menu_add_button">Adicionar</string>
|
||||
<string name="menu_download_all_button">Baixar todos</string>
|
||||
<string name="menu_download_label">Download</string>
|
||||
<string name="menu_filter_all">Todos</string>
|
||||
<string name="menu_filter_download">Baixados</string>
|
||||
<string name="menu_group_by_album">Álbum</string>
|
||||
<string name="menu_group_by_artist">Artista</string>
|
||||
<string name="menu_group_by_genre">Gênero</string>
|
||||
<string name="menu_group_by_track">Faixa</string>
|
||||
<string name="menu_group_by_year">Ano</string>
|
||||
<string name="menu_home_label">Início</string>
|
||||
<string name="menu_library_label">Biblioteca</string>
|
||||
<string name="menu_search_button">Pesquisar</string>
|
||||
<string name="menu_settings_button">Configurações</string>
|
||||
<string name="menu_sort_artist">Artista</string>
|
||||
<string name="menu_sort_name">Nome</string>
|
||||
<string name="menu_sort_random">Aleatório</string>
|
||||
<string name="menu_sort_year">Ano</string>
|
||||
<string name="player_playback_speed">%1$.2fx</string>
|
||||
<string name="player_queue_clean_all_button">Limpar fila de reprodução</string>
|
||||
<string name="player_server_priority">Prioridade do Servidor</string>
|
||||
<string name="playlist_catalogue_title">Catálogo de Playlists</string>
|
||||
<string name="playlist_catalogue_title_expanded">Navegar pelas Playlists</string>
|
||||
<string name="playlist_chooser_dialog_empty">Nenhuma playlist criada</string>
|
||||
<string name="playlist_chooser_dialog_negative_button">Cancelar</string>
|
||||
<string name="playlist_chooser_dialog_neutral_button">Criar</string>
|
||||
<string name="playlist_chooser_dialog_title">Adicionar a uma playlist</string>
|
||||
<string name="playlist_counted_tracks">%1$d faixas • %2$s</string>
|
||||
<string name="playlist_duration">Duração • %1$s</string>
|
||||
<string name="playlist_editor_dialog_hint_name">Nome da playlist</string>
|
||||
<string name="playlist_editor_dialog_negative_button">Cancelar</string>
|
||||
<string name="playlist_editor_dialog_neutral_button">Excluir</string>
|
||||
<string name="playlist_editor_dialog_positive_button">Salvar</string>
|
||||
<string name="playlist_editor_dialog_title">Editar playlist</string>
|
||||
<string name="playlist_page_play_button">Reproduzir</string>
|
||||
<string name="playlist_page_shuffle_button">Aleatório</string>
|
||||
<string name="playlist_song_count">Playlist • %1$d músicas</string>
|
||||
<string name="podcast_bottom_sheet_add_to_queue">Adicionar à fila</string>
|
||||
<string name="podcast_bottom_sheet_delete">Excluir</string>
|
||||
<string name="podcast_bottom_sheet_download">Download</string>
|
||||
<string name="podcast_bottom_sheet_go_to_channel">Ir para o canal</string>
|
||||
<string name="podcast_bottom_sheet_play_next">Tocar em seguida</string>
|
||||
<string name="podcast_bottom_sheet_remove">Remover</string>
|
||||
<string name="podcast_channel_catalogue_title">Canais</string>
|
||||
<string name="podcast_channel_catalogue_title_expanded">Navegar pelos Canais</string>
|
||||
<string name="podcast_channel_editor_dialog_hint_rss_url">URL do Feed RSS</string>
|
||||
<string name="podcast_channel_editor_dialog_title">Canal de Podcast</string>
|
||||
<string name="podcast_channel_page_title_description_section">Descrição</string>
|
||||
<string name="podcast_channel_page_title_episode_section">Episódios</string>
|
||||
<string name="podcast_channel_page_title_no_episode_available">Nenhum episódio disponível</string>
|
||||
<string name="podcast_episode_download_request_snackbar">Sua solicitação foi enviada ao servidor</string>
|
||||
<string name="podcast_info_empty_button">Clique para ocultar a seção\nOs efeitos serão visíveis ao reiniciar</string>
|
||||
<string name="podcast_info_empty_subtitle">Ao adicionar um canal, você o encontrará aqui</string>
|
||||
<string name="podcast_info_empty_title">Nenhum podcast encontrado!</string>
|
||||
<string name="podcast_release_date_duration_formatter">%1$s • %2$s</string>
|
||||
<string name="radio_editor_dialog_hint_homepage_url">URL da Página Inicial da Rádio</string>
|
||||
<string name="radio_editor_dialog_hint_name">Nome da Rádio</string>
|
||||
<string name="radio_editor_dialog_hint_stream_url">URL de Stream da Rádio</string>
|
||||
<string name="radio_editor_dialog_negative_button">Cancelar</string>
|
||||
<string name="radio_editor_dialog_neutral_button">Excluir</string>
|
||||
<string name="radio_editor_dialog_positive_button">Salvar</string>
|
||||
<string name="radio_editor_dialog_title">Estação de rádio via internet</string>
|
||||
<string name="radio_station_info_empty_button">Clique para ocultar a seção\nOs efeitos serão visíveis ao reiniciar</string>
|
||||
<string name="radio_station_info_empty_subtitle">Ao adicionar uma estação de rádio, você a encontrará aqui</string>
|
||||
<string name="radio_station_info_empty_title">Nenhuma estação encontrada!</string>
|
||||
<string name="rating_dialog_negative_button">Cancelar</string>
|
||||
<string name="rating_dialog_positive_button">Salvar</string>
|
||||
<string name="rating_dialog_title">Avaliar</string>
|
||||
<string name="search_hint">Pesquisar por título, artistas ou álbuns</string>
|
||||
<string name="search_info_minimum_characters">Insira pelo menos três caracteres</string>
|
||||
<string name="search_title_album">Álbuns</string>
|
||||
<string name="search_title_artist">Artistas</string>
|
||||
<string name="search_title_song">Músicas</string>
|
||||
<string name="server_signup_dialog_action_low_security">Baixa segurança</string>
|
||||
<string name="server_signup_dialog_hint_name">Nome do Servidor</string>
|
||||
<string name="server_signup_dialog_hint_password">Senha</string>
|
||||
<string name="server_signup_dialog_hint_url">URL do servidor</string>
|
||||
<string name="server_signup_dialog_hint_username">Usuário</string>
|
||||
<string name="server_signup_dialog_negative_button">Cancelar</string>
|
||||
<string name="server_signup_dialog_neutral_button">Excluir</string>
|
||||
<string name="server_signup_dialog_positive_button">Salvar</string>
|
||||
<string name="server_signup_dialog_title">Adicionar servidor</string>
|
||||
<string name="server_unreachable_dialog_negative_button">Cancelar</string>
|
||||
<string name="server_unreachable_dialog_neutral_button">Ir para o login</string>
|
||||
<string name="server_unreachable_dialog_positive_button">Continuar mesmo assim</string>
|
||||
<string name="server_unreachable_dialog_summary">O servidor solicitado não está disponível. Se você optar por continuar, essa caixa de diálogo não será exibida pela próxima hora.</string>
|
||||
<string name="server_unreachable_dialog_title">Servidor inacessível</string>
|
||||
<string name="settings_about_summary">O Tempo é um cliente de música leve e de código aberto para Subsonic, projetado e desenvolvido nativamente para Android.</string>
|
||||
<string name="settings_about_title">Sobre</string>
|
||||
<string name="settings_always_on_display">Tela sempre ativa</string>
|
||||
<string name="settings_audio_transcode_download_format">Formato de transcodificação</string>
|
||||
<string name="settings_audio_transcode_download_priority_summary">Se ativado, Tempo não forçará o download da faixa com as configurações de transcodificação abaixo.</string>
|
||||
<string name="settings_audio_transcode_download_priority_title">Priorizar as configurações do servidor usadas para streaming nos downloads</string>
|
||||
<string name="settings_audio_transcode_download_summary">Se ativado, Tempo irá baixar faixas transcodificadas.</string>
|
||||
<string name="settings_audio_transcode_download_title">Baixar faixas transcodificadas</string>
|
||||
<string name="settings_audio_transcode_estimate_content_length_summary">Se ativado, o servidor será solicitado a informar a duração estimada da faixa.</string>
|
||||
<string name="settings_audio_transcode_estimate_content_length_title">Calcular tamanho do conteúdo</string>
|
||||
<string name="settings_audio_transcode_format_download">Formato de transcodificação para downloads</string>
|
||||
<string name="settings_audio_transcode_format_mobile">Formato de transcodificação na rede móvel</string>
|
||||
<string name="settings_audio_transcode_format_wifi">Formato de transcodificação no Wi-Fi</string>
|
||||
<string name="settings_audio_transcode_priority_summary">Se ativado, Tempo não forçará a transmissão da faixa com as configurações de transcodificação abaixo.</string>
|
||||
<string name="settings_audio_transcode_priority_title">Priorizar configurações de transcodificação do servidor</string>
|
||||
<string name="settings_audio_transcode_priority_toast">Prioridade na transcodificação da faixa fornecida pelo servidor</string>
|
||||
<string name="settings_buffering_strategy">Estratégia de buffer</string>
|
||||
<string name="settings_buffering_strategy_summary">Para que a alteração tenha efeito você deve reiniciar o aplicativo manualmente.</string>
|
||||
<string name="settings_covers_cache">Tamanho do cache das capas</string>
|
||||
<string name="settings_data_saving_mode_summary">Para reduzir o consumo de dados, evite baixar capas de álbum.</string>
|
||||
<string name="settings_data_saving_mode_title">Limitar uso de dados móveis</string>
|
||||
<string name="settings_delete_download_storage_summary">O processo resultará na exclusão irreversível de todos os itens salvos.</string>
|
||||
<string name="settings_delete_download_storage_title">Excluir itens salvos</string>
|
||||
<string name="settings_download_storage_title">Armazenamento dos downloads</string>
|
||||
<string name="settings_equalizer_summary">Ajustar configurações de áudio</string>
|
||||
<string name="settings_equalizer_title">Equalizador</string>
|
||||
<string name="settings_github_link">https://github.com/CappielloAntonio/tempo</string>
|
||||
<string name="settings_github_summary">Acompanhe o desenvolvimento</string>
|
||||
<string name="settings_github_title">Github</string>
|
||||
<string name="settings_image_size">Definir resolução da imagem</string>
|
||||
<string name="settings_language">Idioma</string>
|
||||
<string name="settings_logout_title">Encerrar sessão</string>
|
||||
<string name="settings_max_bitrate_download">Taxa de bits para os downloads</string>
|
||||
<string name="settings_max_bitrate_mobile">Taxa de bits para a rede móvel</string>
|
||||
<string name="settings_max_bitrate_wifi">Bitrate no Wi-Fi</string>
|
||||
<string name="settings_media_cache">Tamanho do cache dos arquivos de mídia</string>
|
||||
<string name="settings_music_directory">Mostrar diretórios de música</string>
|
||||
<string name="settings_music_directory_summary">Se ativado, mostrará a seção do diretório de música. Observe que, para que a navegação na pasta funcione corretamente, o servidor deve oferecer suporte a esse recurso.</string>
|
||||
<string name="settings_podcast">Mostrar podcast</string>
|
||||
<string name="settings_podcast_summary">Se ativado, mostrará a seção de podcasts. Reinicie o aplicativo para que as mudanças tenham efeito.</string>
|
||||
<string name="settings_queue_syncing_countdown">Temporizador de sincronização</string>
|
||||
<string name="settings_queue_syncing_summary">Se ativado, o usuário poderá salvar sua fila de reprodução e carregar o estado ao abrir o aplicativo.</string>
|
||||
<string name="settings_queue_syncing_title">Sincronizar a fila de reprodução para este usuário</string>
|
||||
<string name="settings_radio">Mostrar rádios</string>
|
||||
<string name="settings_radio_summary">Se ativado, mostrará a seção de rádios. Reinicie o aplicativo para que as mudanças tenham efeito.</string>
|
||||
<string name="settings_replay_gain">Habilitar o modo Replay Gain</string>
|
||||
<string name="settings_rounded_corner">Cantos arredondados</string>
|
||||
<string name="settings_rounded_corner_size">Tamanho dos cantos</string>
|
||||
<string name="settings_rounded_corner_size_summary">Define a magnitude do ângulo de curvatura.</string>
|
||||
<string name="settings_rounded_corner_summary">Se ativado, define um ângulo de curvatura para todas as capas renderizadas. As alterações terão efeito ao reiniciar.</string>
|
||||
<string name="settings_scan_title">Escanear biblioteca</string>
|
||||
<string name="settings_scrobble_title">Habilitar scrobbling</string>
|
||||
<string name="settings_share_title">Ativar compartilhamento de música</string>
|
||||
<string name="settings_sub_summary_scrobble">É importante observar que o scrobbling também depende de o servidor estar habilitado para receber esses dados.</string>
|
||||
<string name="settings_summary_skip_min_star_rating">Ao ouvir a rádio de um artista, uma mixagem instantânea ou ao reproduzir aleatóriamente, as faixas abaixo de uma determinada classificação de usuário serão ignoradas.</string>
|
||||
<string name="settings_summary_replay_gain">Replay Gain é um recurso que permite ajustar o nível de volume das faixas para uma experiência de áudio consistente. Esta configuração só é eficaz se a faixa contiver os metadados necessários.</string>
|
||||
<string name="settings_summary_scrobble">Scrobbling é um recurso que permite ao seu dispositivo enviar informações sobre as músicas que você ouve no servidor de música. Essa informação ajuda a criar recomendações personalizadas com base em suas preferências de música.</string>
|
||||
<string name="settings_summary_share">Permite ao usuário compartilhar música através de um link. A funcionalidade deve ser suportada e habilitada pelo servidor e se limita a faixas, álbuns e listas de reprodução individuais.</string>
|
||||
<string name="settings_summary_syncing">Retorna o estado da fila de reprodução para esse usuário. Isso inclui as faixas na fila de reprodução, a faixa sendo reproduzida e a posição nesta faixa. O servidor deve suportar este recurso.</string>
|
||||
<string name="settings_summary_transcoding">Prioridade dada ao modo de transcodificação. Se definido para \"Reprodução direta\" a taxa de bits do arquivo não será alterada.</string>
|
||||
<string name="settings_summary_transcoding_download">Baixar mídia transcodificada. Se ativado, o endpoint de download não será usado, e sim, as seguintes configurações. \n\n Se \"Formato de transcodificação para downloads\" estiver definido como \"Download direto\" a taxa de bits do arquivo não será alterada.</string>
|
||||
<string name="settings_summary_transcoding_estimate_content_length">Quando o arquivo é transcodificado em tempo real, o cliente geralmente não mostra a duração da faixa. É possível solicitar aos servidores que suportam a funcionalidade, que informem a duração da faixa que está sendo reproduzida, porém, os tempos de resposta podem ser mais longos.</string>
|
||||
<string name="settings_sync_starred_tracks_for_offline_use_summary">Se ativado, as faixas favoritadas serão baixadas para uso offline.</string>
|
||||
<string name="settings_sync_starred_tracks_for_offline_use_title">Sincronizar faixas favoritas para uso offline</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="settings_title_data">Dados</string>
|
||||
<string name="settings_title_general">Geral</string>
|
||||
<string name="settings_title_rating">Classificação</string>
|
||||
<string name="settings_title_replay_gain">Replay Gain</string>
|
||||
<string name="settings_title_scrobble">Scrobble</string>
|
||||
<string name="settings_title_skip_min_star_rating">Ignorar faixas baseadas na classificação</string>
|
||||
<string name="settings_title_skip_min_star_rating_dialog">Músicas com uma classificação de:</string>
|
||||
<string name="settings_title_share">Compartilhar</string>
|
||||
<string name="settings_title_syncing">Sincronizando</string>
|
||||
<string name="settings_title_transcoding">Transcodificação</string>
|
||||
<string name="settings_title_transcoding_download">Transcodificação dos Downloads</string>
|
||||
<string name="settings_title_ui">UI</string>
|
||||
<string name="settings_transcoded_download">Transcodificação dos Downloads</string>
|
||||
<string name="settings_version_title">Versão</string>
|
||||
<string name="settings_wifi_only_summary">Solicitar confirmação do usuário antes de fazer streaming através da rede móvel.</string>
|
||||
<string name="settings_wifi_only_title">Alerta de transmissão somente via Wi-Fi</string>
|
||||
<string name="share_bottom_sheet_copy_link">Copiar link</string>
|
||||
<string name="share_bottom_sheet_delete">Excluir compartilhamento</string>
|
||||
<string name="share_bottom_sheet_update">Atualizar compartilhamento</string>
|
||||
<string name="share_subtitle_item">Data de expiração: %1$s</string>
|
||||
<string name="share_unsupported_error">O compartilhamento não é suportado ou não está habilitado</string>
|
||||
<string name="share_update_dialog_hint_description">Descrição</string>
|
||||
<string name="share_update_dialog_hint_expiration_date">Data de expiração</string>
|
||||
<string name="share_update_dialog_negative_button">Cancelar</string>
|
||||
<string name="share_update_dialog_positive_button">Salvar</string>
|
||||
<string name="share_update_dialog_title">Compartilhar</string>
|
||||
<string name="song_bottom_sheet_add_to_playlist">Adicionar a uma playlist</string>
|
||||
<string name="song_bottom_sheet_add_to_queue">Adicionar à fila</string>
|
||||
<string name="song_bottom_sheet_download">Download</string>
|
||||
<string name="song_bottom_sheet_error_retrieving_album">Erro ao recuperar álbum</string>
|
||||
<string name="song_bottom_sheet_error_retrieving_artist">Erro ao recuperar artista</string>
|
||||
<string name="song_bottom_sheet_go_to_album">Ir para álbum</string>
|
||||
<string name="song_bottom_sheet_go_to_artist">Ir para artista</string>
|
||||
<string name="song_bottom_sheet_instant_mix">Mixagem instantânea</string>
|
||||
<string name="song_bottom_sheet_play_next">Tocar em seguida</string>
|
||||
<string name="song_bottom_sheet_rate">Avaliar</string>
|
||||
<string name="song_bottom_sheet_remove">Remover</string>
|
||||
<string name="song_bottom_sheet_share">Compartilhar</string>
|
||||
<string name="song_list_page_downloaded">Baixados</string>
|
||||
<string name="song_list_page_most_played">Músicas mais reproduzidas</string>
|
||||
<string name="song_list_page_recently_added">Músicas recém-adicionadas</string>
|
||||
<string name="song_list_page_recently_played">Músicas recém-reproduzidas</string>
|
||||
<string name="song_list_page_starred">Músicas favoritas</string>
|
||||
<string name="song_list_page_top">Músicas preferidas de %1$s</string>
|
||||
<string name="song_list_page_year">Ano %1$d</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s %3$s</string>
|
||||
<string name="starred_sync_dialog_negative_button">Cancelar</string>
|
||||
<string name="starred_sync_dialog_neutral_button">Continuar</string>
|
||||
<string name="starred_sync_dialog_positive_button">Continuar e baixar</string>
|
||||
<string name="starred_sync_dialog_summary">O download de faixas favoritadas pode exigir uma grande quantidade de dados.</string>
|
||||
<string name="starred_sync_dialog_title">Sincronizar músicas favoritas</string>
|
||||
<string name="track_info_album">Álbum</string>
|
||||
<string name="track_info_artist">Artista</string>
|
||||
<string name="track_info_bitrate">Taxa de bits</string>
|
||||
<string name="track_info_content_type">Tipo de Conteúdo</string>
|
||||
<string name="track_info_dialog_positive_button">OK</string>
|
||||
<string name="track_info_dialog_title">Informações da música</string>
|
||||
<string name="track_info_disc_number">Número do disco</string>
|
||||
<string name="track_info_duration">Duração</string>
|
||||
<string name="track_info_genre">Gênero</string>
|
||||
<string name="track_info_path">Caminho</string>
|
||||
<string name="track_info_size">Tamanho</string>
|
||||
<string name="track_info_suffix">Suffix</string>
|
||||
<string name="track_info_summary_downloaded_file">O arquivo foi baixado usando a API do Subsonic. O codec e a taxa de bits do arquivo permanecem inalterados do arquivo de origem.</string>
|
||||
<string name="track_info_summary_full_transcode">O aplicativo solicitará ao servidor que transcodifique o arquivo e modifique sua taxa de bits. O codec solicitado pelo usuário é %1$s, com uma taxa de bits de %2$s. Todas as possíveis alterações no codec e na taxa de bits do arquivo no formato escolhido serão tratadas pelo servidor, que pode ou não dar suporte à operação.</string>
|
||||
<string name="track_info_summary_original_file">O aplicativo só irá ler o arquivo original conforme fornecido pelo servidor. O aplicativo solicitará explicitamente ao servidor o arquivo não transcodificado com a taxa de bits da fonte original.</string>
|
||||
<string name="track_info_summary_server_prioritized">A qualidade do arquivo a ser reproduzido é de responsabilidade do servidor. O aplicativo não vai impor a escolha do codec e da taxa de bits para qualquer possível transcodificação.</string>
|
||||
<string name="track_info_summary_transcoding_bitrate">O aplicativo solicitará ao servidor que modifique a taxa de bits do arquivo. A taxa de bits solicitada pelo usuário é de %1$s, enquanto o codec do arquivo de origem permanecerá o mesmo. Todas as possíveis alterações na taxa de bits do arquivo no formato escolhido serão tratadas pelo servidor, que pode ou não dar suporte à operação.</string>
|
||||
<string name="track_info_summary_transcoding_codec">O aplicativo solicitará ao servidor para transcodificar o arquivo. O codec solicitado pelo usuário é %1$s, enquanto o bitrate do arquivo de origem permanecerá o mesmo. Todas as possíveis alterações no codec do arquivo no formato escolhido serão tratadas pelo servidor, que pode ou não dar suporte à operação.</string>
|
||||
<string name="track_info_title">Título</string>
|
||||
<string name="track_info_track_number">Número da faixa</string>
|
||||
<string name="track_info_transcoded_content_type">Tipo de conteúdo transcodificado</string>
|
||||
<string name="track_info_transcoded_suffix">Sufixo transcodificado</string>
|
||||
<string name="track_info_year">Ano</string>
|
||||
<string name="undraw_page">unDraw</string>
|
||||
<string name="undraw_thanks">Um agradecimento especial ao unDraw, sem cujas ilustrações não poderíamos ter deixado esta aplicação tão bonita.</string>
|
||||
<string name="undraw_url">https://undraw.co/</string>
|
||||
</resources>
|
||||
@@ -327,7 +327,7 @@
|
||||
<string name="song_list_page_starred">已收藏的曲目</string>
|
||||
<string name="song_list_page_top">%1$s 的热门曲目</string>
|
||||
<string name="song_list_page_year">年份 %1$d</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s %3$s</string>
|
||||
<string name="starred_sync_dialog_negative_button">取消</string>
|
||||
<string name="starred_sync_dialog_neutral_button">继续</string>
|
||||
<string name="starred_sync_dialog_positive_button">继续并下载</string>
|
||||
|
||||
@@ -61,6 +61,9 @@
|
||||
<color name="dividerColor">#e0e0e0</color>
|
||||
<color name="white">#FFFFFF</color>
|
||||
|
||||
<color name="lyricsTextColor">#252525</color>
|
||||
<color name="shadowsLyricsTextColor">#B4B4B4</color>
|
||||
|
||||
<color name="searchPlaceholderColor">#303030</color>
|
||||
<color name="searchColor">#252525</color>
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<string name="album_page_extra_info_button">More like this</string>
|
||||
<string name="album_page_play_button">Play</string>
|
||||
<string name="album_page_shuffle_button">Shuffle</string>
|
||||
<string name="album_page_tracks_count_and_duration">%1$d songs • %2$d minutes</string>
|
||||
<string name="app_name">Tempo</string>
|
||||
<string name="artist_adapter_radio_station_starting">Searching…</string>
|
||||
<string name="artist_bottom_sheet_instant_mix">Instant mix</string>
|
||||
@@ -86,6 +87,11 @@
|
||||
<string name="filter_title_expanded">Filter Genres</string>
|
||||
<string name="genre_catalogue_title">Genre Catalogue</string>
|
||||
<string name="genre_catalogue_title_expanded">Browse Genres</string>
|
||||
<string name="home_rearrangement_dialog_negative_button">Cancel</string>
|
||||
<string name="home_rearrangement_dialog_neutral_button">Reset</string>
|
||||
<string name="home_rearrangement_dialog_positive_button">Save</string>
|
||||
<string name="home_rearrangement_dialog_title">Rearrange home</string>
|
||||
<string name="home_rearrangement_dialog_subtitle">Please note that in order for the changes made to take effect, it is necessary to restart the application.</string>
|
||||
<string name="home_subtitle_best_of">Top songs of your favorite artists</string>
|
||||
<string name="home_subtitle_made_for_you">Start mix from a song you liked</string>
|
||||
<string name="home_subtitle_new_internet_radio_station">Add a new radio</string>
|
||||
@@ -120,6 +126,7 @@
|
||||
<string name="home_title_starred_tracks">★ Starred tracks</string>
|
||||
<string name="home_title_starred_tracks_see_all_button">See all</string>
|
||||
<string name="home_title_top_songs">Your top songs</string>
|
||||
<string name="home_option_reorganize">Reorganize</string>
|
||||
<string name="label_dot_separator" translatable="false">•</string>
|
||||
<string name="label_placeholder" translatable="false">--</string>
|
||||
<string name="library_title_album">Albums</string>
|
||||
@@ -152,6 +159,7 @@
|
||||
<string name="menu_sort_artist">Artist</string>
|
||||
<string name="menu_sort_name">Name</string>
|
||||
<string name="menu_sort_random">Random</string>
|
||||
<string name="menu_sort_recently_added">Recently added</string>
|
||||
<string name="menu_sort_year">Year</string>
|
||||
<string name="player_playback_speed">%1$.2fx</string>
|
||||
<string name="player_queue_clean_all_button">Clean play queue</string>
|
||||
@@ -262,6 +270,10 @@
|
||||
<string name="settings_music_directory_summary">If enabled, show the music directory section. Please note that for folder navigation to work properly, the server must support this feature.</string>
|
||||
<string name="settings_podcast">Show podcast</string>
|
||||
<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_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>
|
||||
<string name="settings_queue_syncing_summary">If enabled, the user will have the ability to save their play queue and will have the ability to load state when opening the application.</string>
|
||||
<string name="settings_queue_syncing_title">Sync play queue for this user</string>
|
||||
@@ -333,7 +345,7 @@
|
||||
<string name="song_list_page_starred">Starred tracks</string>
|
||||
<string name="song_list_page_top">%1$s\'s top tracks</string>
|
||||
<string name="song_list_page_year">Year %1$d</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s</string>
|
||||
<string name="song_subtitle_formatter">%1$s • %2$s %3$s</string>
|
||||
<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>
|
||||
|
||||
@@ -51,6 +51,18 @@
|
||||
app:title="@string/settings_rounded_corner_size"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<SwitchPreference
|
||||
android:title="@string/settings_audio_quality"
|
||||
android:defaultValue="false"
|
||||
android:summary="@string/settings_audio_quality_summary"
|
||||
android:key="audio_quality_per_item" />
|
||||
|
||||
<SwitchPreference
|
||||
android:title="@string/settings_item_rating"
|
||||
android:defaultValue="false"
|
||||
android:summary="@string/settings_item_rating_summary"
|
||||
android:key="rating_per_item" />
|
||||
|
||||
<SwitchPreference
|
||||
android:title="@string/settings_podcast"
|
||||
android:defaultValue="true"
|
||||
|
||||
@@ -5,4 +5,5 @@
|
||||
<locale android:name="fr-FR"/> <!-- French -->
|
||||
<locale android:name="zh-CN"/> <!-- Simplified Chinese-->
|
||||
<locale android:name="ko-KR"/> <!-- Korean-->
|
||||
<locale android:name="pt-BR"/> <!-- Brazilian Portuguese -->
|
||||
</locale-config>
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.media3.common.*
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.DefaultLoadControl
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||
import androidx.media3.exoplayer.source.TrackGroupArray
|
||||
@@ -18,6 +19,7 @@ import com.cappielloantonio.tempo.R
|
||||
import com.cappielloantonio.tempo.ui.activity.MainActivity
|
||||
import com.cappielloantonio.tempo.util.Constants
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil
|
||||
import com.cappielloantonio.tempo.util.Preferences
|
||||
import com.cappielloantonio.tempo.util.ReplayGainUtil
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.util.concurrent.Futures
|
||||
@@ -143,6 +145,7 @@ class MediaService : MediaLibraryService() {
|
||||
.setAudioAttributes(AudioAttributes.DEFAULT, true)
|
||||
.setHandleAudioBecomingNoisy(true)
|
||||
.setWakeMode(C.WAKE_MODE_NETWORK)
|
||||
.setLoadControl(initializeLoadControl())
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -175,6 +178,7 @@ class MediaService : MediaLibraryService() {
|
||||
|
||||
override fun onTracksChanged(tracks: Tracks) {
|
||||
ReplayGainUtil.setReplayGain(player, tracks)
|
||||
MediaManager.scrobble(player.currentMediaItem, false)
|
||||
}
|
||||
|
||||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||
@@ -248,6 +252,17 @@ class MediaService : MediaLibraryService() {
|
||||
/* Do nothing. */
|
||||
}
|
||||
|
||||
private fun initializeLoadControl(): DefaultLoadControl {
|
||||
return DefaultLoadControl.Builder()
|
||||
.setBufferDurationsMs(
|
||||
(DefaultLoadControl.DEFAULT_MIN_BUFFER_MS * Preferences.getBufferingStrategy()).toInt(),
|
||||
(DefaultLoadControl.DEFAULT_MAX_BUFFER_MS * Preferences.getBufferingStrategy()).toInt(),
|
||||
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
|
||||
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun getRenderersFactory() = DownloadUtil.buildRenderersFactory(this, false)
|
||||
|
||||
private fun getMediaSourceFactory() =
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package com.cappielloantonio.tempo.service
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
||||
import androidx.media3.common.MediaMetadata
|
||||
import androidx.media3.session.LibraryResult
|
||||
import com.cappielloantonio.tempo.repository.AutomotiveRepository
|
||||
import com.cappielloantonio.tempo.util.Preferences.getServerId
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
@@ -31,10 +33,12 @@ object MediaBrowserTree {
|
||||
private const val MOST_PLAYED_ID = "[mostPlayedID]"
|
||||
private const val LAST_PLAYED_ID = "[lastPlayedID]"
|
||||
private const val RECENTLY_ADDED_ID = "[recentlyAddedID]"
|
||||
private const val RECENT_SONGS_ID = "[recentSongsID]"
|
||||
private const val MADE_FOR_YOU_ID = "[madeForYouID]"
|
||||
private const val STARRED_TRACKS_ID = "[starredTracksID]"
|
||||
private const val STARRED_ALBUMS_ID = "[starredAlbumsID]"
|
||||
private const val STARRED_ARTISTS_ID = "[starredArtistsID]"
|
||||
private const val RANDOM_ID = "[randomID]"
|
||||
|
||||
// Second level LIBRARY_ID
|
||||
private const val FOLDER_ID = "[folderID]"
|
||||
@@ -193,6 +197,17 @@ object MediaBrowserTree {
|
||||
)
|
||||
)
|
||||
|
||||
treeNodes[RECENT_SONGS_ID] =
|
||||
MediaItemNode(
|
||||
buildMediaItem(
|
||||
title = "Recent songs",
|
||||
mediaId = RECENT_SONGS_ID,
|
||||
isPlayable = false,
|
||||
isBrowsable = true,
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED
|
||||
)
|
||||
)
|
||||
|
||||
treeNodes[MADE_FOR_YOU_ID] =
|
||||
MediaItemNode(
|
||||
buildMediaItem(
|
||||
@@ -237,13 +252,26 @@ object MediaBrowserTree {
|
||||
)
|
||||
)
|
||||
|
||||
treeNodes[RANDOM_ID] =
|
||||
MediaItemNode(
|
||||
buildMediaItem(
|
||||
title = "Random",
|
||||
mediaId = RANDOM_ID,
|
||||
isPlayable = false,
|
||||
isBrowsable = true,
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED
|
||||
)
|
||||
)
|
||||
|
||||
treeNodes[HOME_ID]!!.addChild(MOST_PLAYED_ID)
|
||||
treeNodes[HOME_ID]!!.addChild(LAST_PLAYED_ID)
|
||||
treeNodes[HOME_ID]!!.addChild(RECENTLY_ADDED_ID)
|
||||
treeNodes[HOME_ID]!!.addChild(RECENT_SONGS_ID)
|
||||
treeNodes[HOME_ID]!!.addChild(MADE_FOR_YOU_ID)
|
||||
treeNodes[HOME_ID]!!.addChild(STARRED_TRACKS_ID)
|
||||
treeNodes[HOME_ID]!!.addChild(STARRED_ALBUMS_ID)
|
||||
treeNodes[HOME_ID]!!.addChild(STARRED_ARTISTS_ID)
|
||||
treeNodes[HOME_ID]!!.addChild(RANDOM_ID)
|
||||
|
||||
// Second level LIBRARY_ID
|
||||
|
||||
@@ -316,10 +344,12 @@ object MediaBrowserTree {
|
||||
MOST_PLAYED_ID -> automotiveRepository.getAlbums(id, "frequent", 100)
|
||||
LAST_PLAYED_ID -> automotiveRepository.getAlbums(id, "recent", 100)
|
||||
RECENTLY_ADDED_ID -> automotiveRepository.getAlbums(id, "newest", 100)
|
||||
RECENT_SONGS_ID -> automotiveRepository.getRecentlyPlayedSongs(getServerId(),100)
|
||||
MADE_FOR_YOU_ID -> automotiveRepository.getStarredArtists(id)
|
||||
STARRED_TRACKS_ID -> automotiveRepository.starredSongs
|
||||
STARRED_ALBUMS_ID -> automotiveRepository.getStarredAlbums(id)
|
||||
STARRED_ARTISTS_ID -> automotiveRepository.getStarredArtists(id)
|
||||
RANDOM_ID -> automotiveRepository.getRandomSongs(100)
|
||||
FOLDER_ID -> automotiveRepository.getMusicFolders(id)
|
||||
PLAYLIST_ID -> automotiveRepository.getPlaylists(id)
|
||||
PODCAST_ID -> automotiveRepository.getNewestPodcastEpisodes(100)
|
||||
|
||||
@@ -120,6 +120,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||
|
||||
override fun onTracksChanged(tracks: Tracks) {
|
||||
ReplayGainUtil.setReplayGain(player, tracks)
|
||||
MediaManager.scrobble(player.currentMediaItem, false)
|
||||
}
|
||||
|
||||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||
|
||||
@@ -4,7 +4,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.1.4'
|
||||
classpath 'com.android.tools.build:gradle:8.3.1'
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0'
|
||||
}
|
||||
}
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Wed Aug 16 22:52:26 CEST 2023
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
Reference in New Issue
Block a user