mirror of
https://github.com/CappielloAntonio/tempo.git
synced 2025-12-24 00:18:02 -05:00
project upload
This commit is contained in:
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
6
.idea/compiler.xml
generated
Normal file
6
.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="1.8" />
|
||||
</component>
|
||||
</project>
|
||||
23
.idea/gradle.xml
generated
Normal file
23
.idea/gradle.xml
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="PLATFORM" />
|
||||
<option name="disableWrapperSourceDistributionNotification" value="true" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="1.8" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
<option name="useQualifiedModuleNames" value="true" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
30
.idea/jarRepositories.xml
generated
Normal file
30
.idea/jarRepositories.xml
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BintrayJCenter" />
|
||||
<option name="name" value="BintrayJCenter" />
|
||||
<option name="url" value="https://jcenter.bintray.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/misc.xml
generated
Normal file
9
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
1
app/.gitignore
vendored
Normal file
1
app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
63
app/build.gradle
Normal file
63
app/build.gradle
Normal file
@@ -0,0 +1,63 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "29.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.cappielloantonio.play"
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.1"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility 1.8
|
||||
targetCompatibility 1.8
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation 'androidx.core:core-ktx:1.3.2'
|
||||
implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.4.10'
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
||||
implementation 'pub.devrel:easypermissions:3.0.0'
|
||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||
implementation 'com.android.volley:volley:1.1.1'
|
||||
implementation "com.paulrybitskyi.persistentsearchview:persistentsearchview:1.1.3"
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
||||
implementation "androidx.room:room-runtime:2.2.5"
|
||||
implementation 'com.github.jellyfin.jellyfin-apiclient-java:android:0.7.7'
|
||||
implementation "androidx.cardview:cardview:1.0.0"
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
|
||||
annotationProcessor "androidx.room:room-compiler:2.2.5"
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
debugImplementation 'com.amitshekhar.android:debug-db:1.0.6'
|
||||
}
|
||||
21
app/proguard-rules.pro
vendored
Normal file
21
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.cappielloantonio.play;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
assertEquals("com.cappielloantonio.libr", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
30
app/src/main/AndroidManifest.xml
Normal file
30
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.cappielloantonio.play">
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:usesCleartextTraffic="true">
|
||||
<activity
|
||||
android:name=".ui.activities.MainActivity"
|
||||
android:windowSoftInputMode="adjustPan|adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
65
app/src/main/java/com/cappielloantonio/play/App.java
Normal file
65
app/src/main/java/com/cappielloantonio/play/App.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package com.cappielloantonio.play;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.android.volley.RequestQueue;
|
||||
import com.android.volley.toolbox.Volley;
|
||||
import com.cappielloantonio.play.helper.ThemeHelper;
|
||||
import com.cappielloantonio.play.util.PreferenceUtil;
|
||||
|
||||
import org.jellyfin.apiclient.AppInfo;
|
||||
import org.jellyfin.apiclient.Jellyfin;
|
||||
import org.jellyfin.apiclient.JellyfinAndroidKt;
|
||||
import org.jellyfin.apiclient.JellyfinOptions;
|
||||
import org.jellyfin.apiclient.interaction.AndroidDevice;
|
||||
import org.jellyfin.apiclient.interaction.ApiClient;
|
||||
import org.jellyfin.apiclient.interaction.ApiEventListener;
|
||||
import org.jellyfin.apiclient.logging.NullLogger;
|
||||
|
||||
public class App extends Application {
|
||||
private static final String TAG = "App";
|
||||
private static App instance;
|
||||
private static ApiClient apiClient;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
ThemeHelper.applyTheme(PreferenceUtil.getInstance(getApplicationContext()).getTheme());
|
||||
}
|
||||
|
||||
public static App getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new App();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static ApiClient getApiClientInstance(Context context) {
|
||||
if (apiClient == null) {
|
||||
apiClient = getApiClient(context);
|
||||
}
|
||||
return apiClient;
|
||||
}
|
||||
|
||||
public RequestQueue getRequestQueue(Context context) {
|
||||
return Volley.newRequestQueue(context);
|
||||
}
|
||||
|
||||
private static ApiClient getApiClient(Context context) {
|
||||
String server = PreferenceUtil.getInstance(context).getServer();
|
||||
|
||||
JellyfinOptions.Builder options = new JellyfinOptions.Builder();
|
||||
options.setLogger(new NullLogger());
|
||||
options.setAppInfo(new AppInfo(context.getString(R.string.app_name), BuildConfig.VERSION_NAME));
|
||||
JellyfinAndroidKt.android(options, context);
|
||||
|
||||
Jellyfin jellyfin = new Jellyfin(options.build());
|
||||
|
||||
return jellyfin.createApi(server, null, AndroidDevice.fromContext(context), new ApiEventListener());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.cappielloantonio.play.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder> {
|
||||
private static final String TAG = "RecentMusicAdapter";
|
||||
private List<Album> albums;
|
||||
private LayoutInflater mInflater;
|
||||
private Context context;
|
||||
private ItemClickListener itemClickListener;
|
||||
|
||||
public AlbumAdapter(Context context, List<Album> albums) {
|
||||
this.context = context;
|
||||
this.mInflater = LayoutInflater.from(context);
|
||||
this.albums = albums;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = mInflater.inflate(R.layout.item_library_album, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
Album album = albums.get(position);
|
||||
|
||||
holder.textAlbumName.setText(album.getTitle());
|
||||
holder.textArtistName.setText(album.getArtistName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return albums.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
TextView textAlbumName;
|
||||
TextView textArtistName;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
textAlbumName = itemView.findViewById(R.id.album_name_label);
|
||||
textArtistName = itemView.findViewById(R.id.artist_name_label);
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (itemClickListener != null) itemClickListener.onItemClick(view, getAdapterPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public void setItems(List<Album> albums) {
|
||||
this.albums = albums;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setClickListener(ItemClickListener itemClickListener) {
|
||||
this.itemClickListener = itemClickListener;
|
||||
}
|
||||
|
||||
public interface ItemClickListener {
|
||||
void onItemClick(View view, int position);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.cappielloantonio.play.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder> {
|
||||
private static final String TAG = "ArtistAdapter";
|
||||
private List<Artist> artists;
|
||||
private LayoutInflater mInflater;
|
||||
private Context context;
|
||||
private ItemClickListener itemClickListener;
|
||||
|
||||
public ArtistAdapter(Context context, List<Artist> artists) {
|
||||
this.context = context;
|
||||
this.mInflater = LayoutInflater.from(context);
|
||||
this.artists = artists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = mInflater.inflate(R.layout.item_library_artist, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
Artist artist = artists.get(position);
|
||||
|
||||
holder.textArtistName.setText(artist.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return artists.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
TextView textArtistName;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
textArtistName = itemView.findViewById(R.id.artist_name_label);
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (itemClickListener != null) itemClickListener.onItemClick(view, getAdapterPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public void setItems(List<Artist> artists) {
|
||||
this.artists = artists;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setClickListener(ItemClickListener itemClickListener) {
|
||||
this.itemClickListener = itemClickListener;
|
||||
}
|
||||
|
||||
public interface ItemClickListener {
|
||||
void onItemClick(View view, int position);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.cappielloantonio.play.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DiscoverSongAdapter extends PagerAdapter {
|
||||
|
||||
private List<Song> songs;
|
||||
private LayoutInflater layoutInflater;
|
||||
private Context context;
|
||||
|
||||
public DiscoverSongAdapter(Context context, List<Song> models) {
|
||||
this.context = context;
|
||||
this.songs = models;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return songs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
|
||||
return view.equals(object);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Object instantiateItem(@NonNull ViewGroup container, final int position) {
|
||||
layoutInflater = LayoutInflater.from(context);
|
||||
View view = layoutInflater.inflate(R.layout.item_discover_song, container, false);
|
||||
|
||||
TextView title;
|
||||
TextView desc;
|
||||
|
||||
title = view.findViewById(R.id.title_discover_song_label);
|
||||
desc = view.findViewById(R.id.artist_discover_song_label);
|
||||
|
||||
title.setText(songs.get(position).getTitle());
|
||||
desc.setText(songs.get(position).getAlbumName());
|
||||
|
||||
view.setOnClickListener(v -> Toast.makeText(context, songs.get(position).getTitle(), Toast.LENGTH_SHORT).show());
|
||||
|
||||
container.addView(view, 0);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
|
||||
container.removeView((View)object);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.cappielloantonio.play.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GenreAdapter extends RecyclerView.Adapter<GenreAdapter.ViewHolder> {
|
||||
private static final String TAG = "GenreAdapter";
|
||||
private List<Genre> genres;
|
||||
private LayoutInflater mInflater;
|
||||
private Context context;
|
||||
private ItemClickListener itemClickListener;
|
||||
|
||||
public GenreAdapter(Context context, List<Genre> genres) {
|
||||
this.context = context;
|
||||
this.mInflater = LayoutInflater.from(context);
|
||||
this.genres = genres;
|
||||
}
|
||||
|
||||
// inflates the row layout from xml when needed
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = mInflater.inflate(R.layout.item_library_genre, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
Genre genre = genres.get(position);
|
||||
|
||||
holder.textGenre.setText(genre.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return genres.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
TextView textGenre;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
textGenre = itemView.findViewById(R.id.genre_label);
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (itemClickListener != null) itemClickListener.onItemClick(view, getAdapterPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public void setItems(List<Genre> genres) {
|
||||
this.genres = genres;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setClickListener(ItemClickListener itemClickListener) {
|
||||
this.itemClickListener = itemClickListener;
|
||||
}
|
||||
|
||||
public interface ItemClickListener {
|
||||
void onItemClick(View view, int position);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.cappielloantonio.play.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.ViewHolder> {
|
||||
private static final String TAG = "PlaylistAdapter";
|
||||
private List<Playlist> playlists;
|
||||
private LayoutInflater mInflater;
|
||||
private Context context;
|
||||
private ItemClickListener itemClickListener;
|
||||
|
||||
public PlaylistAdapter(Context context, List<Playlist> playlists) {
|
||||
this.context = context;
|
||||
this.mInflater = LayoutInflater.from(context);
|
||||
this.playlists = playlists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = mInflater.inflate(R.layout.item_library_playlist, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
Playlist playlist = playlists.get(position);
|
||||
|
||||
holder.textPlaylistName.setText(playlist.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return playlists.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
TextView textPlaylistName;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
textPlaylistName = itemView.findViewById(R.id.playlist_name_text);
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (itemClickListener != null) itemClickListener.onItemClick(view, getAdapterPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public void setItems(List<Playlist> playlists) {
|
||||
this.playlists = playlists;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setClickListener(ItemClickListener itemClickListener) {
|
||||
this.itemClickListener = itemClickListener;
|
||||
}
|
||||
|
||||
public interface ItemClickListener {
|
||||
void onItemClick(View view, int position);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.cappielloantonio.play.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RecentMusicAdapter extends RecyclerView.Adapter<RecentMusicAdapter.ViewHolder> {
|
||||
private static final String TAG = "RecentMusicAdapter";
|
||||
private List<Song> songs;
|
||||
private LayoutInflater mInflater;
|
||||
private Context context;
|
||||
private ItemClickListener itemClickListener;
|
||||
|
||||
public RecentMusicAdapter(Context context, List<Song> songs) {
|
||||
this.context = context;
|
||||
this.mInflater = LayoutInflater.from(context);
|
||||
this.songs = songs;
|
||||
}
|
||||
|
||||
// inflates the row layout from xml when needed
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = mInflater.inflate(R.layout.item_recent_track, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
Song song = songs.get(position);
|
||||
|
||||
holder.textTitle.setText(song.getTitle());
|
||||
holder.textArtist.setText(song.getAlbumName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return songs.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
TextView textTitle;
|
||||
TextView textArtist;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
textTitle = itemView.findViewById(R.id.title_track_label);
|
||||
textArtist = itemView.findViewById(R.id.artist_track_label);
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (itemClickListener != null) itemClickListener.onItemClick(view, getAdapterPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public void setClickListener(ItemClickListener itemClickListener) {
|
||||
this.itemClickListener = itemClickListener;
|
||||
}
|
||||
|
||||
public interface ItemClickListener {
|
||||
void onItemClick(View view, int position);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.cappielloantonio.play.database;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
import com.cappielloantonio.play.database.dao.AlbumDao;
|
||||
import com.cappielloantonio.play.database.dao.ArtistDao;
|
||||
import com.cappielloantonio.play.database.dao.GenreDao;
|
||||
import com.cappielloantonio.play.database.dao.PlaylistDao;
|
||||
import com.cappielloantonio.play.database.dao.SongDao;
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
|
||||
@Database(entities = {Album.class, Artist.class, Genre.class, Playlist.class, Song.class}, version = 2, exportSchema = false)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
private static final String TAG = "AppDatabase";
|
||||
|
||||
private static AppDatabase instance;
|
||||
private final static String DB_NAME = "play_db";
|
||||
|
||||
public static synchronized AppDatabase getInstance(Context context) {
|
||||
|
||||
if (instance == null) {
|
||||
instance = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DB_NAME)
|
||||
.fallbackToDestructiveMigration()
|
||||
.build();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public abstract AlbumDao albumDao();
|
||||
|
||||
public abstract ArtistDao artistDao();
|
||||
|
||||
public abstract GenreDao genreDao();
|
||||
|
||||
public abstract PlaylistDao playlistDao();
|
||||
|
||||
public abstract SongDao songDao();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.cappielloantonio.play.database.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface AlbumDao {
|
||||
@Query("SELECT * FROM album")
|
||||
LiveData<List<Album>> getAll();
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM album WHERE id = :id)")
|
||||
boolean exist(String id);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insert(Album album);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insertAll(List<Album> albums);
|
||||
|
||||
@Delete
|
||||
void delete(Album album);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.cappielloantonio.play.database.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface ArtistDao {
|
||||
@Query("SELECT * FROM artist")
|
||||
LiveData<List<Artist>> getAll();
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM artist WHERE id = :id)")
|
||||
boolean exist(String id);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insert(Artist artist);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insertAll(List<Artist> artists);
|
||||
|
||||
@Delete
|
||||
void delete(Artist artist);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.cappielloantonio.play.database.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface GenreDao {
|
||||
@Query("SELECT * FROM genre")
|
||||
LiveData<List<Genre>> getAll();
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM genre WHERE id = :id)")
|
||||
boolean exist(String id);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insert(Genre genre);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insertAll(List<Genre> genres);
|
||||
|
||||
@Delete
|
||||
void delete(Genre genre);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.cappielloantonio.play.database.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface PlaylistDao {
|
||||
@Query("SELECT * FROM playlist")
|
||||
LiveData<List<Playlist>> getAll();
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM playlist WHERE id = :id)")
|
||||
boolean exist(String id);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insert(Playlist playlist);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insertAll(List<Playlist> playlists);
|
||||
|
||||
@Delete
|
||||
void delete(Playlist playlist);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.cappielloantonio.play.database.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface SongDao {
|
||||
@Query("SELECT * FROM song")
|
||||
LiveData<List<Song>> getAll();
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM song WHERE id = :id)")
|
||||
boolean exist(String id);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insert(Song song);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insertAll(List<Song> songs);
|
||||
|
||||
@Delete
|
||||
void delete(Song song);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.cappielloantonio.play.glide;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.bumptech.glide.GlideBuilder;
|
||||
import com.bumptech.glide.annotation.GlideModule;
|
||||
import com.bumptech.glide.load.DecodeFormat;
|
||||
import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory;
|
||||
import com.bumptech.glide.module.AppGlideModule;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.cappielloantonio.play.util.PreferenceUtil;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@GlideModule
|
||||
public class CustomGlideModule extends AppGlideModule {
|
||||
@Override
|
||||
public void applyOptions(@NonNull Context context, GlideBuilder builder) {
|
||||
File file = new File(context.getCacheDir() + "glide");
|
||||
int size = PreferenceUtil.getInstance(context).getImageCacheSize();
|
||||
|
||||
builder.setDiskCache(new DiskLruCacheFactory(() -> file, size));
|
||||
builder.setDefaultRequestOptions(new RequestOptions().format(DecodeFormat.PREFER_RGB_565));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.cappielloantonio.play.helper;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.ApiClient;
|
||||
import org.jellyfin.apiclient.interaction.ApiEventListener;
|
||||
import org.jellyfin.apiclient.model.apiclient.RemoteLogoutReason;
|
||||
import org.jellyfin.apiclient.model.apiclient.SessionUpdatesEventArgs;
|
||||
import org.jellyfin.apiclient.model.dto.UserDto;
|
||||
import org.jellyfin.apiclient.model.entities.LibraryUpdateInfo;
|
||||
import org.jellyfin.apiclient.model.session.BrowseRequest;
|
||||
import org.jellyfin.apiclient.model.session.GeneralCommand;
|
||||
import org.jellyfin.apiclient.model.session.MessageCommand;
|
||||
import org.jellyfin.apiclient.model.session.PlayRequest;
|
||||
import org.jellyfin.apiclient.model.session.PlaystateRequest;
|
||||
import org.jellyfin.apiclient.model.session.SessionInfoDto;
|
||||
import org.jellyfin.apiclient.model.session.UserDataChangeInfo;
|
||||
|
||||
public class EventListenerHelper extends ApiEventListener {
|
||||
private static final String TAG = "EventListenerHelper";
|
||||
|
||||
@Override
|
||||
public void onRemoteLoggedOut(ApiClient client, RemoteLogoutReason reason) {
|
||||
Log.i(TAG, "onRemoteLoggedOut: " + reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserUpdated(ApiClient client, UserDto userDto) {
|
||||
Log.i(TAG, "onUserUpdated: " + userDto.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLibraryChanged(ApiClient client, LibraryUpdateInfo info) {
|
||||
Log.i(TAG, "onLibraryChanged");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserConfigurationUpdated(ApiClient client, UserDto userDto) {
|
||||
Log.i(TAG, "onUserConfigurationUpdated");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBrowseCommand(ApiClient client, BrowseRequest command) {
|
||||
Log.i(TAG, "onBrowseCommand: " + command.getItemName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayCommand(ApiClient client, PlayRequest command) {
|
||||
Log.i(TAG, "onPlayCommand: " + command.getPlayCommand());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaystateCommand(ApiClient client, PlaystateRequest command) {
|
||||
Log.i(TAG, "onPlayStateCommand");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageCommand(ApiClient client, MessageCommand command) {
|
||||
Log.i(TAG, "onMessageCommand");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeneralCommand(ApiClient client, GeneralCommand command) {
|
||||
Log.i(TAG, "onGeneralCommand: " + command.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendStringCommand(ApiClient client, String value) {
|
||||
Log.i(TAG, "onSendStringCommand");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetVolumeCommand(ApiClient client, int value) {
|
||||
Log.i(TAG, "onSetVolumeCommand");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetAudioStreamIndexCommand(ApiClient client, int value) {
|
||||
Log.i(TAG, "onSetAudioStreamIndexCommand");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetSubtitleStreamIndexCommand(ApiClient client, int value) {
|
||||
Log.i(TAG, "onSetSubtitleStreamIndexCommand");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserDataChanged(ApiClient client, UserDataChangeInfo info) {
|
||||
Log.i(TAG, "onUserDataChanged");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionsUpdated(ApiClient client, SessionUpdatesEventArgs args) {
|
||||
Log.i(TAG, "onSessionsUpdated");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackStart(ApiClient client, SessionInfoDto info) {
|
||||
Log.i(TAG, "onPlaybackStart");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackStopped(ApiClient client, SessionInfoDto info) {
|
||||
Log.i(TAG, "onPlaybackStopped");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionEnded(ApiClient client, SessionInfoDto info) {
|
||||
Log.i(TAG, "onSessionEnded");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.cappielloantonio.play.helper;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
|
||||
public class ThemeHelper {
|
||||
public static final String LIGHT_MODE = "light";
|
||||
public static final String DARK_MODE = "dark";
|
||||
public static final String DEFAULT_MODE = "default";
|
||||
|
||||
public static void applyTheme(@NonNull String themePref) {
|
||||
switch (themePref) {
|
||||
case LIGHT_MODE: {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
break;
|
||||
}
|
||||
case DARK_MODE: {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.cappielloantonio.play.interfaces;
|
||||
|
||||
import com.android.volley.VolleyError;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MediaCallback {
|
||||
void onError(Exception exception);
|
||||
void onLoadMedia(List<?> media);
|
||||
}
|
||||
193
app/src/main/java/com/cappielloantonio/play/model/Album.java
Normal file
193
app/src/main/java/com/cappielloantonio/play/model/Album.java
Normal file
@@ -0,0 +1,193 @@
|
||||
package com.cappielloantonio.play.model;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.entities.ImageType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity(tableName = "album")
|
||||
public class Album implements Parcelable {
|
||||
@Ignore
|
||||
public List<Song> songs;
|
||||
|
||||
@NonNull
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "id")
|
||||
public String id;
|
||||
|
||||
@ColumnInfo(name = "title")
|
||||
public String title;
|
||||
|
||||
@ColumnInfo(name = "year")
|
||||
public int year;
|
||||
|
||||
@ColumnInfo(name = "artistId")
|
||||
public String artistId;
|
||||
|
||||
@ColumnInfo(name = "artistName")
|
||||
public String artistName;
|
||||
|
||||
@ColumnInfo(name = "primary")
|
||||
public String primary;
|
||||
|
||||
@ColumnInfo(name = "blurHash")
|
||||
public String blurHash;
|
||||
|
||||
public Album(@NonNull String id, String title, int year, String artistId, String artistName, String primary, String blurHash) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.year = year;
|
||||
this.artistId = artistId;
|
||||
this.artistName = artistName;
|
||||
this.primary = primary;
|
||||
this.blurHash = blurHash;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public Album(BaseItemDto itemDto) {
|
||||
this.id = itemDto.getId();
|
||||
this.title = itemDto.getName();
|
||||
this.year = itemDto.getProductionYear() != null ? itemDto.getProductionYear() : 0;
|
||||
|
||||
if (itemDto.getAlbumArtists().size() != 0) {
|
||||
this.artistId = itemDto.getAlbumArtists().get(0).getId();
|
||||
this.artistName = itemDto.getAlbumArtists().get(0).getName();
|
||||
} else if (itemDto.getArtistItems().size() != 0) {
|
||||
this.artistId = itemDto.getArtistItems().get(0).getId();
|
||||
this.artistName = itemDto.getArtistItems().get(0).getName();
|
||||
}
|
||||
|
||||
this.primary = itemDto.getImageTags().containsKey(ImageType.Primary) ? id : null;
|
||||
if (itemDto.getImageBlurHashes() != null && itemDto.getImageBlurHashes().get(ImageType.Primary) != null) {
|
||||
this.blurHash = (String) itemDto.getImageBlurHashes().get(ImageType.Primary).values().toArray()[0];
|
||||
}
|
||||
|
||||
this.songs = new ArrayList<>();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(@NonNull String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public int getYear() {
|
||||
return year;
|
||||
}
|
||||
|
||||
public void setYear(int year) {
|
||||
this.year = year;
|
||||
}
|
||||
|
||||
public String getArtistId() {
|
||||
return artistId;
|
||||
}
|
||||
|
||||
public void setArtistId(String artistId) {
|
||||
this.artistId = artistId;
|
||||
}
|
||||
|
||||
public String getArtistName() {
|
||||
return artistName;
|
||||
}
|
||||
|
||||
public void setArtistName(String artistName) {
|
||||
this.artistName = artistName;
|
||||
}
|
||||
|
||||
public String getPrimary() {
|
||||
return primary;
|
||||
}
|
||||
|
||||
public void setPrimary(String primary) {
|
||||
this.primary = primary;
|
||||
}
|
||||
|
||||
public String getBlurHash() {
|
||||
return blurHash;
|
||||
}
|
||||
|
||||
public void setBlurHash(String blurHash) {
|
||||
this.blurHash = blurHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Album album = (Album) o;
|
||||
return id.equals(album.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(id);
|
||||
dest.writeString(title);
|
||||
dest.writeInt(year);
|
||||
dest.writeString(artistId);
|
||||
dest.writeString(artistName);
|
||||
dest.writeString(primary);
|
||||
dest.writeString(blurHash);
|
||||
}
|
||||
|
||||
protected Album(Parcel in) {
|
||||
this.songs = new ArrayList<>();
|
||||
|
||||
this.id = in.readString();
|
||||
this.title = in.readString();
|
||||
this.year = in.readInt();
|
||||
this.artistId = in.readString();
|
||||
this.artistName = in.readString();
|
||||
this.primary = in.readString();
|
||||
this.blurHash = in.readString();
|
||||
}
|
||||
|
||||
public static final Creator<Album> CREATOR = new Creator<Album>() {
|
||||
public Album createFromParcel(Parcel source) {
|
||||
return new Album(source);
|
||||
}
|
||||
|
||||
public Album[] newArray(int size) {
|
||||
return new Album[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
157
app/src/main/java/com/cappielloantonio/play/model/Artist.java
Normal file
157
app/src/main/java/com/cappielloantonio/play/model/Artist.java
Normal file
@@ -0,0 +1,157 @@
|
||||
package com.cappielloantonio.play.model;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.dto.GenreDto;
|
||||
import org.jellyfin.apiclient.model.entities.ImageType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity(tableName = "artist")
|
||||
public class Artist implements Parcelable {
|
||||
@Ignore
|
||||
public List<Genre> genres;
|
||||
@Ignore
|
||||
public List<Album> albums;
|
||||
@Ignore
|
||||
public List<Song> songs;
|
||||
|
||||
@NonNull
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "id")
|
||||
public String id;
|
||||
|
||||
@ColumnInfo(name = "name")
|
||||
public String name;
|
||||
|
||||
@ColumnInfo(name = "primary")
|
||||
public String primary;
|
||||
|
||||
@ColumnInfo(name = "blurHash")
|
||||
public String blurHash;
|
||||
|
||||
public Artist(@NonNull String id, String name, String primary, String blurHash) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.primary = primary;
|
||||
this.blurHash = blurHash;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public Artist(BaseItemDto itemDto) {
|
||||
this.id = itemDto.getId();
|
||||
this.name = itemDto.getName();
|
||||
|
||||
this.primary = itemDto.getImageTags().containsKey(ImageType.Primary) ? id : null;
|
||||
if (itemDto.getImageBlurHashes() != null && itemDto.getImageBlurHashes().get(ImageType.Primary) != null) {
|
||||
this.blurHash = (String) itemDto.getImageBlurHashes().get(ImageType.Primary).values().toArray()[0];
|
||||
}
|
||||
|
||||
this.genres = new ArrayList<>();
|
||||
this.albums = new ArrayList<>();
|
||||
this.songs = new ArrayList<>();
|
||||
|
||||
if (itemDto.getGenreItems() != null) {
|
||||
for (GenreDto genre : itemDto.getGenreItems()) {
|
||||
genres.add(new Genre(genre));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(@NonNull String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPrimary() {
|
||||
return primary;
|
||||
}
|
||||
|
||||
public void setPrimary(String primary) {
|
||||
this.primary = primary;
|
||||
}
|
||||
|
||||
public String getBlurHash() {
|
||||
return blurHash;
|
||||
}
|
||||
|
||||
public void setBlurHash(String blurHash) {
|
||||
this.blurHash = blurHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Artist artist = (Artist) o;
|
||||
return id.equals(artist.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(id);
|
||||
dest.writeString(name);
|
||||
dest.writeString(primary);
|
||||
dest.writeString(blurHash);
|
||||
}
|
||||
|
||||
protected Artist(Parcel in) {
|
||||
this.genres = new ArrayList<>();
|
||||
this.albums = new ArrayList<>();
|
||||
this.songs = new ArrayList<>();
|
||||
this.id = in.readString();
|
||||
this.name = in.readString();
|
||||
this.primary = in.readString();
|
||||
this.blurHash = in.readString();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Artist> CREATOR = new Parcelable.Creator<Artist>() {
|
||||
@Override
|
||||
public Artist createFromParcel(Parcel source) {
|
||||
return new Artist(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Artist[] newArray(int size) {
|
||||
return new Artist[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
140
app/src/main/java/com/cappielloantonio/play/model/Genre.java
Normal file
140
app/src/main/java/com/cappielloantonio/play/model/Genre.java
Normal file
@@ -0,0 +1,140 @@
|
||||
package com.cappielloantonio.play.model;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.dto.GenreDto;
|
||||
import org.jellyfin.apiclient.model.entities.ImageType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity(tableName = "genre")
|
||||
public class Genre implements Parcelable {
|
||||
@NonNull
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "id")
|
||||
public String id;
|
||||
|
||||
@ColumnInfo(name = "name")
|
||||
public String name;
|
||||
|
||||
@ColumnInfo(name = "songCount")
|
||||
public int songCount;
|
||||
|
||||
@ColumnInfo(name = "primary")
|
||||
public String primary;
|
||||
|
||||
@ColumnInfo(name = "blurHash")
|
||||
public String blurHash;
|
||||
|
||||
public Genre(@NonNull String id, String name, int songCount, String primary, String blurHash) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.songCount = songCount;
|
||||
this.primary = primary;
|
||||
this.blurHash = blurHash;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public Genre(GenreDto genreDto) {
|
||||
this.id = genreDto.getId();
|
||||
this.name = genreDto.getName();
|
||||
this.songCount = 0;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public Genre(BaseItemDto itemDto) {
|
||||
this.id = itemDto.getId();
|
||||
this.name = itemDto.getName();
|
||||
this.songCount = itemDto.getSongCount() != null ? itemDto.getSongCount() : 0;
|
||||
|
||||
this.primary = itemDto.getImageTags().containsKey(ImageType.Primary) ? id : null;
|
||||
if (itemDto.getImageBlurHashes() != null && itemDto.getImageBlurHashes().get(ImageType.Primary) != null) {
|
||||
this.blurHash = (String) itemDto.getImageBlurHashes().get(ImageType.Primary).values().toArray()[0];
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getSongCount() {
|
||||
return songCount;
|
||||
}
|
||||
|
||||
public String getPrimary() {
|
||||
return primary;
|
||||
}
|
||||
|
||||
public void setPrimary(String primary) {
|
||||
this.primary = primary;
|
||||
}
|
||||
|
||||
public String getBlurHash() {
|
||||
return blurHash;
|
||||
}
|
||||
|
||||
public void setBlurHash(String blurHash) {
|
||||
this.blurHash = blurHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Genre genre = (Genre) o;
|
||||
return id.equals(genre.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(this.id);
|
||||
dest.writeString(this.name);
|
||||
dest.writeInt(this.songCount);
|
||||
}
|
||||
|
||||
protected Genre(Parcel in) {
|
||||
this.id = in.readString();
|
||||
this.name = in.readString();
|
||||
this.songCount = in.readInt();
|
||||
}
|
||||
|
||||
public static final Creator<Genre> CREATOR = new Creator<Genre>() {
|
||||
public Genre createFromParcel(Parcel source) {
|
||||
return new Genre(source);
|
||||
}
|
||||
|
||||
public Genre[] newArray(int size) {
|
||||
return new Genre[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
119
app/src/main/java/com/cappielloantonio/play/model/Playlist.java
Normal file
119
app/src/main/java/com/cappielloantonio/play/model/Playlist.java
Normal file
@@ -0,0 +1,119 @@
|
||||
package com.cappielloantonio.play.model;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.entities.ImageType;
|
||||
|
||||
@Entity(tableName = "playlist")
|
||||
public class Playlist implements Parcelable {
|
||||
@NonNull
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "id")
|
||||
public String id;
|
||||
|
||||
@ColumnInfo(name = "name")
|
||||
public String name;
|
||||
|
||||
@ColumnInfo(name = "primary")
|
||||
public String primary;
|
||||
|
||||
@ColumnInfo(name = "blurHash")
|
||||
public String blurHash;
|
||||
|
||||
public Playlist(@NonNull String id, String name, String primary, String blurHash) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.primary = primary;
|
||||
this.blurHash = blurHash;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public Playlist(BaseItemDto itemDto) {
|
||||
this.id = itemDto.getId();
|
||||
this.name = itemDto.getName();
|
||||
|
||||
this.primary = itemDto.getImageTags().containsKey(ImageType.Primary) ? id : null;
|
||||
if (itemDto.getImageBlurHashes() != null && itemDto.getImageBlurHashes().get(ImageType.Primary) != null) {
|
||||
this.blurHash = (String) itemDto.getImageBlurHashes().get(ImageType.Primary).values().toArray()[0];
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPrimary() {
|
||||
return primary;
|
||||
}
|
||||
|
||||
public void setPrimary(String primary) {
|
||||
this.primary = primary;
|
||||
}
|
||||
|
||||
public String getBlurHash() {
|
||||
return blurHash;
|
||||
}
|
||||
|
||||
public void setBlurHash(String blurHash) {
|
||||
this.blurHash = blurHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Playlist playlist = (Playlist) o;
|
||||
return id.equals(playlist.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(this.id);
|
||||
dest.writeString(this.name);
|
||||
}
|
||||
|
||||
protected Playlist(Parcel in) {
|
||||
this.id = in.readString();
|
||||
this.name = in.readString();
|
||||
}
|
||||
|
||||
public static final Creator<Playlist> CREATOR = new Creator<Playlist>() {
|
||||
public Playlist createFromParcel(Parcel source) {
|
||||
return new Playlist(source);
|
||||
}
|
||||
|
||||
public Playlist[] newArray(int size) {
|
||||
return new Playlist[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
415
app/src/main/java/com/cappielloantonio/play/model/Song.java
Normal file
415
app/src/main/java/com/cappielloantonio/play/model/Song.java
Normal file
@@ -0,0 +1,415 @@
|
||||
package com.cappielloantonio.play.model;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.dto.MediaSourceInfo;
|
||||
import org.jellyfin.apiclient.model.entities.ImageType;
|
||||
import org.jellyfin.apiclient.model.entities.MediaStream;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity(tableName = "song")
|
||||
public class Song implements Parcelable {
|
||||
@NonNull
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "id")
|
||||
private String id;
|
||||
|
||||
@ColumnInfo(name = "title")
|
||||
private String title;
|
||||
|
||||
@ColumnInfo(name = "trackNumber")
|
||||
private int trackNumber;
|
||||
|
||||
@ColumnInfo(name = "discNumber")
|
||||
private int discNumber;
|
||||
|
||||
@ColumnInfo(name = "year")
|
||||
private int year;
|
||||
|
||||
@ColumnInfo(name = "duration")
|
||||
private long duration;
|
||||
|
||||
@ColumnInfo(name = "albumId")
|
||||
private String albumId;
|
||||
|
||||
@ColumnInfo(name = "albumName")
|
||||
private String albumName;
|
||||
|
||||
@ColumnInfo(name = "artistId")
|
||||
private String artistId;
|
||||
|
||||
@ColumnInfo(name = "artistName")
|
||||
private String artistName;
|
||||
|
||||
@ColumnInfo(name = "primary")
|
||||
private String primary;
|
||||
|
||||
@ColumnInfo(name = "blurHash")
|
||||
private String blurHash;
|
||||
|
||||
@ColumnInfo(name = "favorite")
|
||||
private boolean favorite;
|
||||
|
||||
@ColumnInfo(name = "path")
|
||||
private String path;
|
||||
|
||||
@ColumnInfo(name = "size")
|
||||
private long size;
|
||||
|
||||
@ColumnInfo(name = "container")
|
||||
private String container;
|
||||
|
||||
@ColumnInfo(name = "codec")
|
||||
private String codec;
|
||||
|
||||
@ColumnInfo(name = "sampleRate")
|
||||
private int sampleRate;
|
||||
|
||||
@ColumnInfo(name = "bitRate")
|
||||
private int bitRate;
|
||||
|
||||
@ColumnInfo(name = "bitDepth")
|
||||
private int bitDepth;
|
||||
|
||||
@ColumnInfo(name = "channels")
|
||||
private int channels;
|
||||
|
||||
public Song(@NonNull String id, String title, int trackNumber, int discNumber, int year, long duration, String albumId, String albumName, String artistId, String artistName, String primary, String blurHash, boolean favorite, String path, long size, String container, String codec, int sampleRate, int bitRate, int bitDepth, int channels) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.trackNumber = trackNumber;
|
||||
this.discNumber = discNumber;
|
||||
this.year = year;
|
||||
this.duration = duration;
|
||||
this.albumId = albumId;
|
||||
this.albumName = albumName;
|
||||
this.artistId = artistId;
|
||||
this.artistName = artistName;
|
||||
this.primary = primary;
|
||||
this.blurHash = blurHash;
|
||||
this.favorite = favorite;
|
||||
this.path = path;
|
||||
this.size = size;
|
||||
this.container = container;
|
||||
this.codec = codec;
|
||||
this.sampleRate = sampleRate;
|
||||
this.bitRate = bitRate;
|
||||
this.bitDepth = bitDepth;
|
||||
this.channels = channels;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public Song(BaseItemDto itemDto) {
|
||||
this.id = itemDto.getId();
|
||||
this.title = itemDto.getName();
|
||||
this.trackNumber = itemDto.getIndexNumber() != null ? itemDto.getIndexNumber() : 0;
|
||||
this.discNumber = itemDto.getParentIndexNumber() != null ? itemDto.getParentIndexNumber() : 0;
|
||||
this.year = itemDto.getProductionYear() != null ? itemDto.getProductionYear() : 0;
|
||||
this.duration = itemDto.getRunTimeTicks() != null ? itemDto.getRunTimeTicks() / 10000 : 0;
|
||||
|
||||
this.albumId = itemDto.getAlbumId();
|
||||
this.albumName = itemDto.getAlbum();
|
||||
|
||||
if (itemDto.getAlbumArtists().size() != 0) {
|
||||
this.artistId = itemDto.getAlbumArtists().get(0).getId();
|
||||
this.artistName = itemDto.getAlbumArtists().get(0).getName();
|
||||
} else if (itemDto.getArtistItems().size() != 0) {
|
||||
this.artistId = itemDto.getArtistItems().get(0).getId();
|
||||
this.artistName = itemDto.getArtistItems().get(0).getName();
|
||||
}
|
||||
|
||||
this.primary = itemDto.getAlbumPrimaryImageTag() != null ? albumId : null;
|
||||
if (itemDto.getImageBlurHashes() != null && itemDto.getImageBlurHashes().get(ImageType.Primary) != null) {
|
||||
this.blurHash = (String) itemDto.getImageBlurHashes().get(ImageType.Primary).values().toArray()[0];
|
||||
}
|
||||
|
||||
this.favorite = itemDto.getUserData() != null && itemDto.getUserData().getIsFavorite();
|
||||
|
||||
if (itemDto.getMediaSources() != null && itemDto.getMediaSources().get(0) != null) {
|
||||
MediaSourceInfo source = itemDto.getMediaSources().get(0);
|
||||
|
||||
this.path = source.getPath();
|
||||
this.size = source.getSize() != null ? source.getSize() : 0;
|
||||
|
||||
this.container = source.getContainer();
|
||||
this.bitRate = source.getBitrate() != null ? source.getBitrate() : 0;
|
||||
|
||||
if (source.getMediaStreams() != null && source.getMediaStreams().size() != 0) {
|
||||
MediaStream stream = source.getMediaStreams().get(0);
|
||||
|
||||
this.codec = stream.getCodec();
|
||||
this.sampleRate = stream.getSampleRate() != null ? stream.getSampleRate() : 0;
|
||||
this.bitDepth = stream.getBitDepth() != null ? stream.getBitDepth() : 0;
|
||||
this.channels = stream.getChannels() != null ? stream.getChannels() : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public Song(String title, String albumName) {
|
||||
this.id = UUID.randomUUID().toString();
|
||||
this.title = title;
|
||||
this.albumName = albumName;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public int getTrackNumber() {
|
||||
return trackNumber;
|
||||
}
|
||||
|
||||
public int getDiscNumber() {
|
||||
return discNumber;
|
||||
}
|
||||
|
||||
public int getYear() {
|
||||
return year;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public String getAlbumId() {
|
||||
return albumId;
|
||||
}
|
||||
|
||||
public String getAlbumName() {
|
||||
return albumName;
|
||||
}
|
||||
|
||||
public String getArtistId() {
|
||||
return artistId;
|
||||
}
|
||||
|
||||
public String getArtistName() {
|
||||
return artistName;
|
||||
}
|
||||
|
||||
public String getPrimary() {
|
||||
return primary;
|
||||
}
|
||||
|
||||
public String getBlurHash() {
|
||||
return blurHash;
|
||||
}
|
||||
|
||||
public boolean isFavorite() {
|
||||
return favorite;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getContainer() {
|
||||
return container;
|
||||
}
|
||||
|
||||
public String getCodec() {
|
||||
return codec;
|
||||
}
|
||||
|
||||
public int getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
public int getBitRate() {
|
||||
return bitRate;
|
||||
}
|
||||
|
||||
public int getBitDepth() {
|
||||
return bitDepth;
|
||||
}
|
||||
|
||||
public int getChannels() {
|
||||
return channels;
|
||||
}
|
||||
|
||||
public void setId(@NonNull String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void setTrackNumber(int trackNumber) {
|
||||
this.trackNumber = trackNumber;
|
||||
}
|
||||
|
||||
public void setDiscNumber(int discNumber) {
|
||||
this.discNumber = discNumber;
|
||||
}
|
||||
|
||||
public void setYear(int year) {
|
||||
this.year = year;
|
||||
}
|
||||
|
||||
public void setDuration(long duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public void setAlbumId(String albumId) {
|
||||
this.albumId = albumId;
|
||||
}
|
||||
|
||||
public void setAlbumName(String albumName) {
|
||||
this.albumName = albumName;
|
||||
}
|
||||
|
||||
public void setArtistId(String artistId) {
|
||||
this.artistId = artistId;
|
||||
}
|
||||
|
||||
public void setArtistName(String artistName) {
|
||||
this.artistName = artistName;
|
||||
}
|
||||
|
||||
public void setPrimary(String primary) {
|
||||
this.primary = primary;
|
||||
}
|
||||
|
||||
public void setBlurHash(String blurHash) {
|
||||
this.blurHash = blurHash;
|
||||
}
|
||||
|
||||
public void setFavorite(boolean favorite) {
|
||||
this.favorite = favorite;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void setContainer(String container) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
public void setCodec(String codec) {
|
||||
this.codec = codec;
|
||||
}
|
||||
|
||||
public void setSampleRate(int sampleRate) {
|
||||
this.sampleRate = sampleRate;
|
||||
}
|
||||
|
||||
public void setBitRate(int bitRate) {
|
||||
this.bitRate = bitRate;
|
||||
}
|
||||
|
||||
public void setBitDepth(int bitDepth) {
|
||||
this.bitDepth = bitDepth;
|
||||
}
|
||||
|
||||
public void setChannels(int channels) {
|
||||
this.channels = channels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Song song = (Song) o;
|
||||
return id.equals(song.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(this.id);
|
||||
dest.writeString(this.title);
|
||||
dest.writeInt(this.trackNumber);
|
||||
dest.writeInt(this.discNumber);
|
||||
dest.writeInt(this.year);
|
||||
dest.writeLong(this.duration);
|
||||
dest.writeString(this.albumId);
|
||||
dest.writeString(this.albumName);
|
||||
dest.writeString(this.artistId);
|
||||
dest.writeString(this.artistName);
|
||||
dest.writeString(this.primary);
|
||||
dest.writeString(Boolean.toString(favorite));
|
||||
dest.writeString(this.blurHash);
|
||||
dest.writeString(this.path);
|
||||
dest.writeLong(this.size);
|
||||
dest.writeString(this.container);
|
||||
dest.writeString(this.codec);
|
||||
dest.writeInt(this.sampleRate);
|
||||
dest.writeInt(this.bitRate);
|
||||
dest.writeInt(this.bitDepth);
|
||||
dest.writeInt(this.channels);
|
||||
}
|
||||
|
||||
protected Song(Parcel in) {
|
||||
this.id = in.readString();
|
||||
this.title = in.readString();
|
||||
this.trackNumber = in.readInt();
|
||||
this.discNumber = in.readInt();
|
||||
this.year = in.readInt();
|
||||
this.duration = in.readLong();
|
||||
this.albumId = in.readString();
|
||||
this.albumName = in.readString();
|
||||
this.artistId = in.readString();
|
||||
this.artistName = in.readString();
|
||||
this.primary = in.readString();
|
||||
this.favorite = Boolean.parseBoolean(in.readString());
|
||||
this.blurHash = in.readString();
|
||||
this.path = in.readString();
|
||||
this.size = in.readLong();
|
||||
this.container = in.readString();
|
||||
this.codec = in.readString();
|
||||
this.sampleRate = in.readInt();
|
||||
this.bitRate = in.readInt();
|
||||
this.bitDepth = in.readInt();
|
||||
this.channels = in.readInt();
|
||||
}
|
||||
|
||||
public static final Creator<Song> CREATOR = new Creator<Song>() {
|
||||
public Song createFromParcel(Parcel source) {
|
||||
return new Song(source);
|
||||
}
|
||||
|
||||
public Song[] newArray(int size) {
|
||||
return new Song[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.cappielloantonio.play.repository;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.cappielloantonio.play.database.AppDatabase;
|
||||
import com.cappielloantonio.play.database.dao.AlbumDao;
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AlbumRepository {
|
||||
private AlbumDao albumDao;
|
||||
private LiveData<List<Album>> listLiveAlbums;
|
||||
|
||||
public AlbumRepository(Application application) {
|
||||
AppDatabase database = AppDatabase.getInstance(application);
|
||||
albumDao = database.albumDao();
|
||||
listLiveAlbums = albumDao.getAll();
|
||||
}
|
||||
|
||||
public LiveData<List<Album>> getListLiveAlbums() {
|
||||
return listLiveAlbums;
|
||||
}
|
||||
|
||||
public boolean exist(Album album) {
|
||||
boolean exist = false;
|
||||
|
||||
ExistThreadSafe existThread = new ExistThreadSafe(albumDao, album);
|
||||
Thread thread = new Thread(existThread);
|
||||
thread.start();
|
||||
|
||||
try {
|
||||
thread.join();
|
||||
exist = existThread.exist();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
public void insert(Album album) {
|
||||
InsertThreadSafe insert = new InsertThreadSafe(albumDao, album);
|
||||
Thread thread = new Thread(insert);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void insertAll(ArrayList<Album> albums) {
|
||||
InsertAllThreadSafe insertAll = new InsertAllThreadSafe(albumDao, albums);
|
||||
Thread thread = new Thread(insertAll);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void delete(Album album) {
|
||||
DeleteThreadSafe delete = new DeleteThreadSafe(albumDao, album);
|
||||
Thread thread = new Thread(delete);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private static class ExistThreadSafe implements Runnable {
|
||||
private AlbumDao albumDao;
|
||||
private Album album;
|
||||
private boolean exist = false;
|
||||
|
||||
public ExistThreadSafe(AlbumDao albumDao, Album album) {
|
||||
this.albumDao = albumDao;
|
||||
this.album = album;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
exist = albumDao.exist(album.getId());
|
||||
}
|
||||
|
||||
public boolean exist() {
|
||||
return exist;
|
||||
}
|
||||
}
|
||||
|
||||
private static class InsertThreadSafe implements Runnable {
|
||||
private AlbumDao albumDao;
|
||||
private Album album;
|
||||
|
||||
public InsertThreadSafe(AlbumDao albumDao, Album album) {
|
||||
this.albumDao = albumDao;
|
||||
this.album = album;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
albumDao.insert(album);
|
||||
}
|
||||
}
|
||||
|
||||
private static class InsertAllThreadSafe implements Runnable {
|
||||
private AlbumDao albumDao;
|
||||
private ArrayList<Album> albums;
|
||||
|
||||
public InsertAllThreadSafe(AlbumDao albumDao, ArrayList<Album> albums) {
|
||||
this.albumDao = albumDao;
|
||||
this.albums = albums;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
albumDao.insertAll(albums);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeleteThreadSafe implements Runnable {
|
||||
private AlbumDao albumDao;
|
||||
private Album album;
|
||||
|
||||
public DeleteThreadSafe(AlbumDao albumDao, Album album) {
|
||||
this.albumDao = albumDao;
|
||||
this.album = album;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
albumDao.delete(album);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.cappielloantonio.play.repository;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.cappielloantonio.play.database.AppDatabase;
|
||||
import com.cappielloantonio.play.database.dao.ArtistDao;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ArtistRepository {
|
||||
private ArtistDao artistDao;
|
||||
private LiveData<List<Artist>> listLiveArtists;
|
||||
|
||||
public ArtistRepository(Application application) {
|
||||
AppDatabase database = AppDatabase.getInstance(application);
|
||||
artistDao = database.artistDao();
|
||||
listLiveArtists = artistDao.getAll();
|
||||
}
|
||||
|
||||
public LiveData<List<Artist>> getListLiveArtists() {
|
||||
return listLiveArtists;
|
||||
}
|
||||
|
||||
public boolean exist(Artist artist) {
|
||||
boolean exist = false;
|
||||
|
||||
ExistThreadSafe existThread = new ExistThreadSafe(artistDao, artist);
|
||||
Thread thread = new Thread(existThread);
|
||||
thread.start();
|
||||
|
||||
try {
|
||||
thread.join();
|
||||
exist = existThread.exist();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
public void insert(Artist artist) {
|
||||
InsertThreadSafe insert = new InsertThreadSafe(artistDao, artist);
|
||||
Thread thread = new Thread(insert);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void insertAll(ArrayList<Artist> artists) {
|
||||
InsertAllThreadSafe insertAll = new InsertAllThreadSafe(artistDao, artists);
|
||||
Thread thread = new Thread(insertAll);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void delete(Artist artist) {
|
||||
DeleteThreadSafe delete = new DeleteThreadSafe(artistDao, artist);
|
||||
Thread thread = new Thread(delete);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private static class ExistThreadSafe implements Runnable {
|
||||
private ArtistDao artistDao;
|
||||
private Artist artist;
|
||||
private boolean exist = false;
|
||||
|
||||
public ExistThreadSafe(ArtistDao artistDao, Artist artist) {
|
||||
this.artistDao = artistDao;
|
||||
this.artist = artist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
exist = artistDao.exist(artist.getId());
|
||||
}
|
||||
|
||||
public boolean exist() {
|
||||
return exist;
|
||||
}
|
||||
}
|
||||
|
||||
private static class InsertThreadSafe implements Runnable {
|
||||
private ArtistDao artistDao;
|
||||
private Artist artist;
|
||||
|
||||
public InsertThreadSafe(ArtistDao artistDao, Artist artist) {
|
||||
this.artistDao = artistDao;
|
||||
this.artist = artist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
artistDao.insert(artist);
|
||||
}
|
||||
}
|
||||
|
||||
private static class InsertAllThreadSafe implements Runnable {
|
||||
private ArtistDao artistDao;
|
||||
private ArrayList<Artist> artists;
|
||||
|
||||
public InsertAllThreadSafe(ArtistDao artistDao, ArrayList<Artist> artists) {
|
||||
this.artistDao = artistDao;
|
||||
this.artists = artists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
artistDao.insertAll(artists);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeleteThreadSafe implements Runnable {
|
||||
private ArtistDao artistDao;
|
||||
private Artist artist;
|
||||
|
||||
public DeleteThreadSafe(ArtistDao artistDao, Artist artist) {
|
||||
this.artistDao = artistDao;
|
||||
this.artist = artist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
artistDao.delete(artist);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.cappielloantonio.play.repository;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.cappielloantonio.play.database.AppDatabase;
|
||||
import com.cappielloantonio.play.database.dao.GenreDao;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GenreRepository {
|
||||
private GenreDao genreDao;
|
||||
private LiveData<List<Genre>> listLiveGenres;
|
||||
|
||||
public GenreRepository(Application application) {
|
||||
AppDatabase database = AppDatabase.getInstance(application);
|
||||
genreDao = database.genreDao();
|
||||
listLiveGenres = genreDao.getAll();
|
||||
}
|
||||
|
||||
public LiveData<List<Genre>> getListLiveGenres() {
|
||||
return listLiveGenres;
|
||||
}
|
||||
|
||||
public boolean exist(Genre genre) {
|
||||
boolean exist = false;
|
||||
|
||||
ExistThreadSafe existThread = new ExistThreadSafe(genreDao, genre);
|
||||
Thread thread = new Thread(existThread);
|
||||
thread.start();
|
||||
|
||||
try {
|
||||
thread.join();
|
||||
exist = existThread.exist();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
public void insert(Genre genre) {
|
||||
InsertThreadSafe insert = new InsertThreadSafe(genreDao, genre);
|
||||
Thread thread = new Thread(insert);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void insertAll(ArrayList<Genre> genres) {
|
||||
InsertAllThreadSafe insertAll = new InsertAllThreadSafe(genreDao, genres);
|
||||
Thread thread = new Thread(insertAll);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void delete(Genre genre) {
|
||||
DeleteThreadSafe delete = new DeleteThreadSafe(genreDao, genre);
|
||||
Thread thread = new Thread(delete);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private static class ExistThreadSafe implements Runnable {
|
||||
private GenreDao genreDao;
|
||||
private Genre genre;
|
||||
private boolean exist = false;
|
||||
|
||||
public ExistThreadSafe(GenreDao genreDao, Genre genre) {
|
||||
this.genreDao = genreDao;
|
||||
this.genre = genre;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
exist = genreDao.exist(genre.getId());
|
||||
}
|
||||
|
||||
public boolean exist() {
|
||||
return exist;
|
||||
}
|
||||
}
|
||||
|
||||
private static class InsertThreadSafe implements Runnable {
|
||||
private GenreDao genreDao;
|
||||
private Genre genre;
|
||||
|
||||
public InsertThreadSafe(GenreDao genreDao, Genre genre) {
|
||||
this.genreDao = genreDao;
|
||||
this.genre = genre;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
genreDao.insert(genre);
|
||||
}
|
||||
}
|
||||
|
||||
private static class InsertAllThreadSafe implements Runnable {
|
||||
private GenreDao genreDao;
|
||||
private ArrayList<Genre> genres;
|
||||
|
||||
public InsertAllThreadSafe(GenreDao genreDao, ArrayList<Genre> genres) {
|
||||
this.genreDao = genreDao;
|
||||
this.genres = genres;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
genreDao.insertAll(genres);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeleteThreadSafe implements Runnable {
|
||||
private GenreDao genreDao;
|
||||
private Genre genre;
|
||||
|
||||
public DeleteThreadSafe(GenreDao genreDao, Genre genre) {
|
||||
this.genreDao = genreDao;
|
||||
this.genre = genre;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
genreDao.delete(genre);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.cappielloantonio.play.repository;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.cappielloantonio.play.database.AppDatabase;
|
||||
import com.cappielloantonio.play.database.dao.PlaylistDao;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PlaylistRepository {
|
||||
private PlaylistDao playlistDao;
|
||||
private LiveData<List<Playlist>> listLivePlaylists;
|
||||
|
||||
public PlaylistRepository(Application application) {
|
||||
AppDatabase database = AppDatabase.getInstance(application);
|
||||
playlistDao = database.playlistDao();
|
||||
listLivePlaylists = playlistDao.getAll();
|
||||
}
|
||||
|
||||
public LiveData<List<Playlist>> getListLivePlaylists() {
|
||||
return listLivePlaylists;
|
||||
}
|
||||
|
||||
public boolean exist(Playlist playlist) {
|
||||
boolean exist = false;
|
||||
|
||||
ExistThreadSafe existThread = new ExistThreadSafe(playlistDao, playlist);
|
||||
Thread thread = new Thread(existThread);
|
||||
thread.start();
|
||||
|
||||
try {
|
||||
thread.join();
|
||||
exist = existThread.exist();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
public void insert(Playlist playlist) {
|
||||
InsertThreadSafe insert = new InsertThreadSafe(playlistDao, playlist);
|
||||
Thread thread = new Thread(insert);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void insertAll(ArrayList<Playlist> playlists) {
|
||||
InsertAllThreadSafe insertAll = new InsertAllThreadSafe(playlistDao, playlists);
|
||||
Thread thread = new Thread(insertAll);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void delete(Playlist playlist) {
|
||||
DeleteThreadSafe delete = new DeleteThreadSafe(playlistDao, playlist);
|
||||
Thread thread = new Thread(delete);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private static class ExistThreadSafe implements Runnable {
|
||||
private PlaylistDao playlistDao;
|
||||
private Playlist playlist;
|
||||
private boolean exist = false;
|
||||
|
||||
public ExistThreadSafe(PlaylistDao playlistDao, Playlist playlist) {
|
||||
this.playlistDao = playlistDao;
|
||||
this.playlist = playlist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
exist = playlistDao.exist(playlist.getId());
|
||||
}
|
||||
|
||||
public boolean exist() {
|
||||
return exist;
|
||||
}
|
||||
}
|
||||
|
||||
private static class InsertThreadSafe implements Runnable {
|
||||
private PlaylistDao playlistDao;
|
||||
private Playlist playlist;
|
||||
|
||||
public InsertThreadSafe(PlaylistDao playlistDao, Playlist playlist) {
|
||||
this.playlistDao = playlistDao;
|
||||
this.playlist = playlist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
playlistDao.insert(playlist);
|
||||
}
|
||||
}
|
||||
|
||||
private static class InsertAllThreadSafe implements Runnable {
|
||||
private PlaylistDao playlistDao;
|
||||
private ArrayList<Playlist> playlists;
|
||||
|
||||
public InsertAllThreadSafe(PlaylistDao playlistDao, ArrayList<Playlist> playlists) {
|
||||
this.playlistDao = playlistDao;
|
||||
this.playlists = playlists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
playlistDao.insertAll(playlists);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeleteThreadSafe implements Runnable {
|
||||
private PlaylistDao playlistDao;
|
||||
private Playlist playlist;
|
||||
|
||||
public DeleteThreadSafe(PlaylistDao playlistDao, Playlist playlist) {
|
||||
this.playlistDao = playlistDao;
|
||||
this.playlist = playlist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
playlistDao.delete(playlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.cappielloantonio.play.repository;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.cappielloantonio.play.database.AppDatabase;
|
||||
import com.cappielloantonio.play.database.dao.SongDao;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SongRepository {
|
||||
private SongDao songDao;
|
||||
private LiveData<List<Song>> listLiveSongs;
|
||||
|
||||
public SongRepository(Application application) {
|
||||
AppDatabase database = AppDatabase.getInstance(application);
|
||||
songDao = database.songDao();
|
||||
listLiveSongs = songDao.getAll();
|
||||
}
|
||||
|
||||
public LiveData<List<Song>> getListLiveSongs() {
|
||||
return listLiveSongs;
|
||||
}
|
||||
|
||||
public boolean exist(Song song) {
|
||||
boolean exist = false;
|
||||
|
||||
ExistThreadSafe existThread = new ExistThreadSafe(songDao, song);
|
||||
Thread thread = new Thread(existThread);
|
||||
thread.start();
|
||||
|
||||
try {
|
||||
thread.join();
|
||||
exist = existThread.exist();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
public void insert(Song song) {
|
||||
InsertThreadSafe insert = new InsertThreadSafe(songDao, song);
|
||||
Thread thread = new Thread(insert);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void insertAll(ArrayList<Song> songs) {
|
||||
InsertAllThreadSafe insertAll = new InsertAllThreadSafe(songDao, songs);
|
||||
Thread thread = new Thread(insertAll);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void delete(Song song) {
|
||||
DeleteThreadSafe delete = new DeleteThreadSafe(songDao, song);
|
||||
Thread thread = new Thread(delete);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private static class ExistThreadSafe implements Runnable {
|
||||
private SongDao songDao;
|
||||
private Song song;
|
||||
private boolean exist = false;
|
||||
|
||||
public ExistThreadSafe(SongDao songDao, Song song) {
|
||||
this.songDao = songDao;
|
||||
this.song = song;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
exist = songDao.exist(song.getId());
|
||||
}
|
||||
|
||||
public boolean exist() {
|
||||
return exist;
|
||||
}
|
||||
}
|
||||
|
||||
private static class InsertThreadSafe implements Runnable {
|
||||
private SongDao songDao;
|
||||
private Song song;
|
||||
|
||||
public InsertThreadSafe(SongDao songDao, Song song) {
|
||||
this.songDao = songDao;
|
||||
this.song = song;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
songDao.insert(song);
|
||||
}
|
||||
}
|
||||
|
||||
private static class InsertAllThreadSafe implements Runnable {
|
||||
private SongDao songDao;
|
||||
private ArrayList<Song> songs;
|
||||
|
||||
public InsertAllThreadSafe(SongDao songDao, ArrayList<Song> songs) {
|
||||
this.songDao = songDao;
|
||||
this.songs = songs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
songDao.insertAll(songs);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeleteThreadSafe implements Runnable {
|
||||
private SongDao songDao;
|
||||
private Song song;
|
||||
|
||||
public DeleteThreadSafe(SongDao songDao, Song song) {
|
||||
this.songDao = songDao;
|
||||
this.song = song;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
songDao.delete(song);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.cappielloantonio.play.ui.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
|
||||
import com.cappielloantonio.play.App;
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.databinding.ActivityMainBinding;
|
||||
import com.cappielloantonio.play.ui.activities.base.BaseActivity;
|
||||
import com.cappielloantonio.play.util.PreferenceUtil;
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.EmptyResponse;
|
||||
import org.jellyfin.apiclient.interaction.Response;
|
||||
import org.jellyfin.apiclient.model.session.ClientCapabilities;
|
||||
import org.jellyfin.apiclient.model.system.SystemInfo;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MainActivity extends BaseActivity {
|
||||
private static final String TAG = "MainActivity";
|
||||
|
||||
private ActivityMainBinding activityMainBinding;
|
||||
|
||||
private FragmentManager fragmentManager;
|
||||
private NavHostFragment navHostFragment;
|
||||
private BottomNavigationView bottomNavigationView;
|
||||
public NavController navController;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
activityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
View view = activityMainBinding.getRoot();
|
||||
setContentView(view);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
fragmentManager = getSupportFragmentManager();
|
||||
bottomNavigationView = findViewById(R.id.bottom_navigation);
|
||||
|
||||
navHostFragment = (NavHostFragment) fragmentManager.findFragmentById(R.id.nav_host_fragment);
|
||||
navController = navHostFragment.getNavController();
|
||||
NavigationUI.setupWithNavController(bottomNavigationView, navController);
|
||||
|
||||
if (PreferenceUtil.getInstance(this).getToken() != null) {
|
||||
checkPreviousSession();
|
||||
} else {
|
||||
goToLogin();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPreviousSession() {
|
||||
App.getApiClientInstance(getApplicationContext()).ChangeServerLocation(PreferenceUtil.getInstance(this).getServer());
|
||||
App.getApiClientInstance(getApplicationContext()).SetAuthenticationInfo(PreferenceUtil.getInstance(this).getToken(), PreferenceUtil.getInstance(this).getUser());
|
||||
App.getApiClientInstance(getApplicationContext()).GetSystemInfoAsync(new Response<SystemInfo>() {
|
||||
@Override
|
||||
public void onResponse(SystemInfo result) {
|
||||
ClientCapabilities clientCapabilities = new ClientCapabilities();
|
||||
clientCapabilities.setSupportsMediaControl(true);
|
||||
clientCapabilities.setSupportsPersistentIdentifier(true);
|
||||
|
||||
App.getApiClientInstance(getApplicationContext()).ensureWebSocket();
|
||||
App.getApiClientInstance(getApplicationContext()).ReportCapabilities(clientCapabilities, new EmptyResponse());
|
||||
|
||||
goFromLogin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
goToLogin();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void goToLogin() {
|
||||
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.landingFragment)
|
||||
navController.navigate(R.id.action_landingFragment_to_loginFragment);
|
||||
}
|
||||
|
||||
public void goToSync() {
|
||||
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.landingFragment) {
|
||||
navController.navigate(R.id.action_landingFragment_to_syncFragment);
|
||||
} else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.loginFragment) {
|
||||
navController.navigate(R.id.action_loginFragment_to_syncFragment);
|
||||
} else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.homeFragment) {
|
||||
navController.navigate(R.id.action_homeFragment_to_syncFragment);
|
||||
}
|
||||
}
|
||||
|
||||
public void goToHome() {
|
||||
bottomNavigationView.setVisibility(View.VISIBLE);
|
||||
|
||||
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.landingFragment) {
|
||||
navController.navigate(R.id.action_landingFragment_to_homeFragment);
|
||||
} else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.syncFragment) {
|
||||
navController.navigate(R.id.action_syncFragment_to_homeFragment);
|
||||
} else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.loginFragment) {
|
||||
navController.navigate(R.id.action_loginFragment_to_homeFragment);
|
||||
}
|
||||
}
|
||||
|
||||
public void goFromLogin() {
|
||||
if (PreferenceUtil.getInstance(getApplicationContext()).getSync()) {
|
||||
goToHome();
|
||||
} else {
|
||||
goToSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.cappielloantonio.play.ui.activities.base;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pub.devrel.easypermissions.AppSettingsDialog;
|
||||
import pub.devrel.easypermissions.EasyPermissions;
|
||||
|
||||
public class BaseActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks {
|
||||
public static final int REQUEST_PERM_ACCESS = 1;
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
checkPermissions();
|
||||
// checkBatteryOptimization();
|
||||
}
|
||||
|
||||
private void checkBatteryOptimization() {
|
||||
if (detectBatteryOptimization()) {
|
||||
showBatteryOptimizationDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean detectBatteryOptimization() {
|
||||
String packageName = getPackageName();
|
||||
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
|
||||
return !powerManager.isIgnoringBatteryOptimizations(packageName);
|
||||
}
|
||||
|
||||
private void showBatteryOptimizationDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(R.string.battery_optimizations_message)
|
||||
.setTitle(R.string.battery_optimizations_title)
|
||||
.setNegativeButton(R.string.ignore, null)
|
||||
.setPositiveButton(R.string.disable, (dialog, id) -> openPowerSettings())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void openPowerSettings() {
|
||||
Intent intent = new Intent();
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void checkPermissions() {
|
||||
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
||||
|
||||
if (!EasyPermissions.hasPermissions(this, permissions)) {
|
||||
EasyPermissions.requestPermissions(this, getString(R.string.storage_permission_rationale), REQUEST_PERM_ACCESS, permissions);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
|
||||
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
|
||||
new AppSettingsDialog.Builder(this).build().show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.cappielloantonio.play.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.cappielloantonio.play.adapter.DiscoverSongAdapter;
|
||||
import com.cappielloantonio.play.adapter.RecentMusicAdapter;
|
||||
import com.cappielloantonio.play.databinding.FragmentHomeBinding;
|
||||
import com.cappielloantonio.play.ui.activities.MainActivity;
|
||||
import com.cappielloantonio.play.util.PreferenceUtil;
|
||||
import com.cappielloantonio.play.viewmodel.HomeViewModel;
|
||||
|
||||
public class HomeFragment extends Fragment implements RecentMusicAdapter.ItemClickListener {
|
||||
private static final String TAG = "CategoriesFragment";
|
||||
|
||||
private FragmentHomeBinding bind;
|
||||
private MainActivity activity;
|
||||
private HomeViewModel homeViewModel;
|
||||
|
||||
private DiscoverSongAdapter discoverSongAdapter;
|
||||
private RecentMusicAdapter recentMusicAdapter;
|
||||
private RecentMusicAdapter mostPlayedMusicAdapter;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
activity = (MainActivity) getActivity();
|
||||
|
||||
bind = FragmentHomeBinding.inflate(inflater, container, false);
|
||||
View view = bind.getRoot();
|
||||
homeViewModel = new ViewModelProvider(requireActivity()).get(HomeViewModel.class);
|
||||
|
||||
init();
|
||||
initDiscoverSongSlideView();
|
||||
initRecentPlayedSongView();
|
||||
initMostPlayedSongView();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
bind = null;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
bind.resyncButton.setOnClickListener(v -> {
|
||||
PreferenceUtil.getInstance(requireContext()).setSync(false);
|
||||
activity.goToSync();
|
||||
});
|
||||
}
|
||||
|
||||
private void initDiscoverSongSlideView() {
|
||||
discoverSongAdapter = new DiscoverSongAdapter(requireContext(), homeViewModel.getDiscoverSongList());
|
||||
bind.discoverSongViewPager.setAdapter(discoverSongAdapter);
|
||||
bind.discoverSongViewPager.setPageMargin(20);
|
||||
}
|
||||
|
||||
private void initRecentPlayedSongView() {
|
||||
bind.recentlyPlayedTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.recentlyPlayedTracksRecyclerView.setHasFixedSize(true);
|
||||
|
||||
recentMusicAdapter = new RecentMusicAdapter(requireContext(), homeViewModel.getRecentSongList());
|
||||
recentMusicAdapter.setClickListener(this);
|
||||
bind.recentlyPlayedTracksRecyclerView.setAdapter(recentMusicAdapter);
|
||||
}
|
||||
|
||||
private void initMostPlayedSongView() {
|
||||
bind.mostPlayedTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.mostPlayedTracksRecyclerView.setHasFixedSize(true);
|
||||
|
||||
mostPlayedMusicAdapter = new RecentMusicAdapter(requireContext(), homeViewModel.getMostPlayedSongList());
|
||||
mostPlayedMusicAdapter.setClickListener(this);
|
||||
bind.mostPlayedTracksRecyclerView.setAdapter(mostPlayedMusicAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(View view, int position) {
|
||||
Toast.makeText(requireContext(), "Click: " + position, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.cappielloantonio.play.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
|
||||
public class LandingFragment extends Fragment {
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_landing, container, false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.cappielloantonio.play.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.cappielloantonio.play.adapter.AlbumAdapter;
|
||||
import com.cappielloantonio.play.adapter.ArtistAdapter;
|
||||
import com.cappielloantonio.play.adapter.GenreAdapter;
|
||||
import com.cappielloantonio.play.adapter.PlaylistAdapter;
|
||||
import com.cappielloantonio.play.databinding.FragmentLibraryBinding;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.ui.activities.MainActivity;
|
||||
import com.cappielloantonio.play.viewmodel.LibraryViewModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LibraryFragment extends Fragment {
|
||||
private static final String TAG = "LibraryFragment";
|
||||
|
||||
private FragmentLibraryBinding bind;
|
||||
private MainActivity activity;
|
||||
private LibraryViewModel libraryViewModel;
|
||||
|
||||
private AlbumAdapter albumAdapter;
|
||||
private ArtistAdapter artistAdapter;
|
||||
private GenreAdapter genreAdapter;
|
||||
private PlaylistAdapter playlistAdapter;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
activity = (MainActivity) getActivity();
|
||||
|
||||
bind = FragmentLibraryBinding.inflate(inflater, container, false);
|
||||
View view = bind.getRoot();
|
||||
libraryViewModel = new ViewModelProvider(requireActivity()).get(LibraryViewModel.class);
|
||||
|
||||
initAlbumView();
|
||||
initArtistView();
|
||||
initGenreView();
|
||||
initPlaylistView();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
bind = null;
|
||||
}
|
||||
|
||||
private void initAlbumView() {
|
||||
bind.albumRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.albumRecyclerView.setHasFixedSize(true);
|
||||
|
||||
albumAdapter = new AlbumAdapter(requireContext(), libraryViewModel.getAlbumSample());
|
||||
albumAdapter.setClickListener((view, position) -> Toast.makeText(requireContext(), "Album: " + position, Toast.LENGTH_SHORT).show());
|
||||
bind.albumRecyclerView.setAdapter(albumAdapter);
|
||||
}
|
||||
|
||||
private void initArtistView() {
|
||||
bind.artistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.artistRecyclerView.setHasFixedSize(true);
|
||||
|
||||
artistAdapter = new ArtistAdapter(requireContext(), libraryViewModel.getArtistSample());
|
||||
artistAdapter.setClickListener((view, position) -> Toast.makeText(requireContext(), "Artist: " + position, Toast.LENGTH_SHORT).show());
|
||||
bind.artistRecyclerView.setAdapter(artistAdapter);
|
||||
}
|
||||
|
||||
private void initGenreView() {
|
||||
bind.genreRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 3, GridLayoutManager.HORIZONTAL, false));
|
||||
bind.genreRecyclerView.setHasFixedSize(true);
|
||||
|
||||
genreAdapter = new GenreAdapter(requireContext(), new ArrayList<>());
|
||||
genreAdapter.setClickListener((view, position) -> Toast.makeText(requireContext(), "Genre: " + position, Toast.LENGTH_SHORT).show());
|
||||
bind.genreRecyclerView.setAdapter(genreAdapter);
|
||||
libraryViewModel.getGenreList().observe(requireActivity(), genres -> genreAdapter.setItems(genres));
|
||||
}
|
||||
|
||||
private void initPlaylistView() {
|
||||
bind.playlistRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
|
||||
bind.playlistRecyclerView.setHasFixedSize(true);
|
||||
|
||||
playlistAdapter = new PlaylistAdapter(requireContext(), libraryViewModel.getPlaylist());
|
||||
playlistAdapter.setClickListener((view, position) -> Toast.makeText(requireContext(), "Playlist: " + position, Toast.LENGTH_SHORT).show());
|
||||
bind.playlistRecyclerView.setAdapter(playlistAdapter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.cappielloantonio.play.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.cappielloantonio.play.App;
|
||||
import com.cappielloantonio.play.databinding.FragmentLoginBinding;
|
||||
import com.cappielloantonio.play.ui.activities.MainActivity;
|
||||
import com.cappielloantonio.play.util.PreferenceUtil;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.Response;
|
||||
import org.jellyfin.apiclient.model.system.SystemInfo;
|
||||
import org.jellyfin.apiclient.model.users.AuthenticationResult;
|
||||
|
||||
public class LoginFragment extends Fragment {
|
||||
private static final String TAG = "LoginFragment";
|
||||
|
||||
private FragmentLoginBinding bind;
|
||||
private MainActivity activity;
|
||||
|
||||
// private TextView usernameTextView;
|
||||
// private TextView passwordTextView;
|
||||
// private TextView serverTextView;
|
||||
private String username;
|
||||
private String password;
|
||||
private String server;
|
||||
|
||||
// private Button loginButton;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
activity = (MainActivity) getActivity();
|
||||
|
||||
bind = FragmentLoginBinding.inflate(inflater, container, false);
|
||||
View view = bind.getRoot();
|
||||
init();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
bind = null;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
bind.loginButton.setOnClickListener(v -> {
|
||||
if (validateInput()) {
|
||||
saveServerPreference(username, server);
|
||||
authenticate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean validateInput() {
|
||||
username = bind.usernameTextView.getText().toString().trim();
|
||||
password = bind.passwordTextView.getText().toString().trim();
|
||||
server = bind.serverTextView.getText().toString().trim();
|
||||
|
||||
if (TextUtils.isEmpty(username)) {
|
||||
Toast.makeText(requireContext(), "Empty username", Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(server)) {
|
||||
Toast.makeText(requireContext(), "Empty server", Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void saveServerPreference(String user, String server) {
|
||||
PreferenceUtil.getInstance(requireContext()).setUser(user);
|
||||
PreferenceUtil.getInstance(requireContext()).setServer(server);
|
||||
}
|
||||
|
||||
private void authenticate() {
|
||||
App.getApiClientInstance(requireContext()).ChangeServerLocation(server);
|
||||
App.getApiClientInstance(requireContext()).AuthenticateUserAsync(username, password, new Response<AuthenticationResult>() {
|
||||
@Override
|
||||
public void onResponse(AuthenticationResult result) {
|
||||
if (result.getAccessToken() == null) return;
|
||||
enter(result.getUser().getId(), result.getAccessToken());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
if (exception.getMessage().contains("AuthFailureError")) {
|
||||
Toast.makeText(requireContext(), "Fail to authenticate", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Server unreachable", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void enter(String user, String token) {
|
||||
App.getApiClientInstance(requireContext()).GetSystemInfoAsync(new Response<SystemInfo>() {
|
||||
@Override
|
||||
public void onResponse(SystemInfo result) {
|
||||
if (result.getVersion().charAt(0) == '1') {
|
||||
PreferenceUtil.getInstance(requireContext()).setUser(user);
|
||||
PreferenceUtil.getInstance(requireContext()).setToken(token);
|
||||
|
||||
activity.goFromLogin();
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Error version", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.cappielloantonio.play.ui.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.cappielloantonio.play.databinding.FragmentSearchBinding;
|
||||
import com.cappielloantonio.play.ui.activities.MainActivity;
|
||||
import com.paulrybitskyi.persistentsearchview.utils.VoiceRecognitionDelegate;
|
||||
|
||||
public class SearchFragment extends Fragment {
|
||||
private static final String TAG = "SearchFragment";
|
||||
public static final int REQUEST_CODE = 64545;
|
||||
|
||||
private FragmentSearchBinding bind;
|
||||
private MainActivity activity;
|
||||
|
||||
protected LinearLayout emptyLinearLayout;
|
||||
|
||||
protected String query = "";
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
activity = (MainActivity) getActivity();
|
||||
|
||||
bind = FragmentSearchBinding.inflate(inflater, container, false);
|
||||
View view = bind.getRoot();
|
||||
|
||||
searchInit();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
bind = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (requestCode == REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
String code = data.getStringExtra("result");
|
||||
search(code);
|
||||
}
|
||||
}
|
||||
|
||||
VoiceRecognitionDelegate.handleResult(bind.persistentSearchView, requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
private void searchInit() {
|
||||
bind.persistentSearchView.showRightButton();
|
||||
|
||||
bind.persistentSearchView.setOnSearchQueryChangeListener((searchView, oldQuery, newQuery) -> {
|
||||
});
|
||||
|
||||
bind.persistentSearchView.setOnLeftBtnClickListener(view -> {
|
||||
});
|
||||
|
||||
bind.persistentSearchView.setOnRightBtnClickListener(view -> {
|
||||
});
|
||||
|
||||
bind.persistentSearchView.setVoiceRecognitionDelegate(new VoiceRecognitionDelegate(this));
|
||||
|
||||
bind.persistentSearchView.setOnSearchConfirmedListener((searchView, query) -> {
|
||||
if (!query.equals("")) {
|
||||
searchView.collapse();
|
||||
search(query);
|
||||
}
|
||||
});
|
||||
|
||||
bind.persistentSearchView.setSuggestionsDisabled(true);
|
||||
}
|
||||
|
||||
public void search(String query) {
|
||||
emptyScreen();
|
||||
this.query = query;
|
||||
|
||||
bind.persistentSearchView.setInputQuery(query);
|
||||
performSearch(query);
|
||||
}
|
||||
|
||||
private void performSearch(String query) {
|
||||
|
||||
}
|
||||
|
||||
private void loadMoreItemSearch(String query, int page) {
|
||||
manageProgressBar(true);
|
||||
|
||||
}
|
||||
|
||||
private void emptyScreen() {
|
||||
emptyLinearLayout.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
private void manageProgressBar(boolean show) {
|
||||
if (show) {
|
||||
bind.persistentSearchView.hideLeftButton();
|
||||
bind.persistentSearchView.showProgressBar(true);
|
||||
} else {
|
||||
bind.persistentSearchView.showLeftButton();
|
||||
bind.persistentSearchView.hideProgressBar(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.cappielloantonio.play.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.helper.ThemeHelper;
|
||||
|
||||
public class SettingsFragment extends PreferenceFragmentCompat {
|
||||
private static final String TAG = "SettingsFragment";
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.global_preferences, rootKey);
|
||||
|
||||
ListPreference themePreference = findPreference("themePref");
|
||||
if (themePreference != null) {
|
||||
themePreference.setOnPreferenceChangeListener(
|
||||
(preference, newValue) -> {
|
||||
String themeOption = (String) newValue;
|
||||
ThemeHelper.applyTheme(themeOption);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package com.cappielloantonio.play.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.cappielloantonio.play.databinding.FragmentSyncBinding;
|
||||
import com.cappielloantonio.play.interfaces.MediaCallback;
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
import com.cappielloantonio.play.repository.AlbumRepository;
|
||||
import com.cappielloantonio.play.repository.ArtistRepository;
|
||||
import com.cappielloantonio.play.repository.GenreRepository;
|
||||
import com.cappielloantonio.play.repository.PlaylistRepository;
|
||||
import com.cappielloantonio.play.repository.SongRepository;
|
||||
import com.cappielloantonio.play.ui.activities.MainActivity;
|
||||
import com.cappielloantonio.play.util.PreferenceUtil;
|
||||
import com.cappielloantonio.play.util.SyncUtil;
|
||||
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SyncFragment extends Fragment {
|
||||
private static final String TAG = "SyncFragment";
|
||||
|
||||
private MainActivity activity;
|
||||
private FragmentSyncBinding bind;
|
||||
|
||||
private ArrayList<Integer> progressing;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
activity = (MainActivity) getActivity();
|
||||
|
||||
bind = FragmentSyncBinding.inflate(inflater, container, false);
|
||||
View view = bind.getRoot();
|
||||
syncLibraries();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
bind = null;
|
||||
}
|
||||
|
||||
private void showProgressBar() {
|
||||
bind.loadingProgressBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void syncLibraries() {
|
||||
progressing = new ArrayList<>();
|
||||
|
||||
SyncUtil.getLibraries(requireContext(), new MediaCallback() {
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
Log.e(TAG, "onError: " + exception.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
List<BaseItemDto> libraries = (List<BaseItemDto>) media;
|
||||
|
||||
for (BaseItemDto itemDto : libraries) {
|
||||
if (itemDto.getCollectionType().equals("music"))
|
||||
SyncUtil.musicLibrary = itemDto;
|
||||
}
|
||||
|
||||
startSyncing();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void startSyncing() {
|
||||
showProgressBar();
|
||||
syncAlbums();
|
||||
syncArtists();
|
||||
syncGenres();
|
||||
syncPlaylist();
|
||||
syncSongs();
|
||||
}
|
||||
|
||||
private void syncAlbums() {
|
||||
SyncUtil.getAlbums(requireContext(), new MediaCallback() {
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
Log.e(TAG, "onError: " + exception.getMessage());
|
||||
setProgress(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
AlbumRepository repository = new AlbumRepository(activity.getApplication());
|
||||
repository.insertAll((ArrayList<Album>) media);
|
||||
setProgress(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void syncArtists() {
|
||||
SyncUtil.getArtists(requireContext(), new MediaCallback() {
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
Log.e(TAG, "onError: " + exception.getMessage());
|
||||
setProgress(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
ArtistRepository repository = new ArtistRepository(activity.getApplication());
|
||||
repository.insertAll((ArrayList<Artist>) media);
|
||||
setProgress(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void syncGenres() {
|
||||
SyncUtil.getGenres(requireContext(), new MediaCallback() {
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
Log.e(TAG, "onError: " + exception.getMessage());
|
||||
setProgress(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
GenreRepository repository = new GenreRepository(activity.getApplication());
|
||||
repository.insertAll((ArrayList<Genre>) media);
|
||||
setProgress(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void syncPlaylist() {
|
||||
SyncUtil.getPlaylists(requireContext(), new MediaCallback() {
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
Log.e(TAG, "onError: " + exception.getMessage());
|
||||
setProgress(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
PlaylistRepository repository = new PlaylistRepository(activity.getApplication());
|
||||
repository.insertAll((ArrayList<Playlist>) media);
|
||||
setProgress(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void syncSongs() {
|
||||
SyncUtil.getSongs(requireContext(), new MediaCallback() {
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
Log.e(TAG, "onError: " + exception.getMessage());
|
||||
setProgress(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
SongRepository repository = new SongRepository(activity.getApplication());
|
||||
repository.insertAll((ArrayList<Song>) media);
|
||||
setProgress(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setProgress(boolean step) {
|
||||
if (step) {
|
||||
progressing.add(25);
|
||||
bind.loadingProgressBar.setProgress(bind.loadingProgressBar.getProgress() + 25, true);
|
||||
} else {
|
||||
progressing.add(0);
|
||||
}
|
||||
|
||||
countProgress();
|
||||
}
|
||||
|
||||
private void countProgress() {
|
||||
if (progressing.size() == 5) {
|
||||
if (bind.loadingProgressBar.getProgress() == 100)
|
||||
terminate();
|
||||
else
|
||||
Toast.makeText(requireContext(), "Sync error", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void terminate() {
|
||||
PreferenceUtil.getInstance(requireContext()).setSync(true);
|
||||
activity.goToHome();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.cappielloantonio.play.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.cappielloantonio.play.helper.ThemeHelper;
|
||||
|
||||
public class PreferenceUtil {
|
||||
public static final String SERVER = "server";
|
||||
public static final String USER = "user";
|
||||
public static final String TOKEN = "token";
|
||||
|
||||
public static final String SYNC = "sync";
|
||||
|
||||
public static final String HOST_URL = "host";
|
||||
public static final String IMAGE_CACHE_SIZE = "image_cache_size";
|
||||
|
||||
private static PreferenceUtil sInstance;
|
||||
|
||||
private final SharedPreferences mPreferences;
|
||||
|
||||
private PreferenceUtil(final Context context) {
|
||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
}
|
||||
|
||||
public static PreferenceUtil getInstance(final Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new PreferenceUtil(context.getApplicationContext());
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public String getTheme() { return mPreferences.getString("themePref", ThemeHelper.DEFAULT_MODE ); }
|
||||
|
||||
public String getServer() {
|
||||
return mPreferences.getString(SERVER, "https://jellyfin.org");
|
||||
}
|
||||
|
||||
public void setServer(String server) {
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putString(SERVER, server);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return mPreferences.getString(USER, "");
|
||||
}
|
||||
|
||||
public void setUser(String user) {
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putString(USER, user);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return mPreferences.getString(TOKEN, "");
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putString(TOKEN, token);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public Boolean getSync() {
|
||||
return mPreferences.getBoolean(SYNC, false);
|
||||
}
|
||||
|
||||
public void setSync(Boolean sync) {
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putBoolean(SYNC, sync);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public final String getHostUrl() {
|
||||
return mPreferences.getString(HOST_URL, "undefined");
|
||||
}
|
||||
|
||||
public final int getImageCacheSize() {
|
||||
return Integer.parseInt(mPreferences.getString(IMAGE_CACHE_SIZE, "400000000"));
|
||||
}
|
||||
}
|
||||
177
app/src/main/java/com/cappielloantonio/play/util/SyncUtil.java
Normal file
177
app/src/main/java/com/cappielloantonio/play/util/SyncUtil.java
Normal file
@@ -0,0 +1,177 @@
|
||||
package com.cappielloantonio.play.util;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.cappielloantonio.play.App;
|
||||
import com.cappielloantonio.play.interfaces.MediaCallback;
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.Response;
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.querying.ArtistsQuery;
|
||||
import org.jellyfin.apiclient.model.querying.ItemFields;
|
||||
import org.jellyfin.apiclient.model.querying.ItemQuery;
|
||||
import org.jellyfin.apiclient.model.querying.ItemsByNameQuery;
|
||||
import org.jellyfin.apiclient.model.querying.ItemsResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class SyncUtil {
|
||||
public static BaseItemDto musicLibrary;
|
||||
|
||||
public static void getLibraries(Context context, MediaCallback callback) {
|
||||
String id = App.getApiClientInstance(context).getCurrentUserId();
|
||||
|
||||
App.getApiClientInstance(context).GetUserViews(id, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
List<BaseItemDto> libraries = new ArrayList<>();
|
||||
libraries.addAll(Arrays.asList(result.getItems()));
|
||||
|
||||
callback.onLoadMedia(libraries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void getSongs(Context context, MediaCallback callback) {
|
||||
ItemQuery query = new ItemQuery();
|
||||
|
||||
query.setIncludeItemTypes(new String[]{"Audio"});
|
||||
query.setFields(new ItemFields[]{ItemFields.MediaSources});
|
||||
query.setUserId(App.getApiClientInstance(context).getCurrentUserId());
|
||||
query.setRecursive(true);
|
||||
query.setParentId(musicLibrary.getId());
|
||||
|
||||
App.getApiClientInstance(context).GetItemsAsync(query, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
ArrayList<Song> songs = new ArrayList<>();
|
||||
|
||||
for (BaseItemDto itemDto : result.getItems()) {
|
||||
songs.add(new Song(itemDto));
|
||||
}
|
||||
|
||||
callback.onLoadMedia(songs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
callback.onError(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void getAlbums(Context context, MediaCallback callback) {
|
||||
ItemQuery query = new ItemQuery();
|
||||
|
||||
query.setIncludeItemTypes(new String[]{"MusicAlbum"});
|
||||
query.setUserId(App.getApiClientInstance(context).getCurrentUserId());
|
||||
query.setRecursive(true);
|
||||
query.setParentId(musicLibrary.getId());
|
||||
|
||||
App.getApiClientInstance(context).GetItemsAsync(query, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
List<Album> albums = new ArrayList<>();
|
||||
for (BaseItemDto itemDto : result.getItems()) {
|
||||
albums.add(new Album(itemDto));
|
||||
}
|
||||
|
||||
callback.onLoadMedia(albums);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void getArtists(Context context, MediaCallback callback) {
|
||||
ArtistsQuery query = new ArtistsQuery();
|
||||
|
||||
query.setFields(new ItemFields[]{ItemFields.Genres});
|
||||
query.setUserId(App.getApiClientInstance(context).getCurrentUserId());
|
||||
query.setRecursive(true);
|
||||
query.setParentId(musicLibrary.getId());
|
||||
|
||||
App.getApiClientInstance(context).GetAlbumArtistsAsync(query, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
List<Artist> artists = new ArrayList<>();
|
||||
for (BaseItemDto itemDto : result.getItems()) {
|
||||
artists.add(new Artist(itemDto));
|
||||
}
|
||||
|
||||
callback.onLoadMedia(artists);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void getPlaylists(Context context, MediaCallback callback) {
|
||||
ItemQuery query = new ItemQuery();
|
||||
|
||||
query.setIncludeItemTypes(new String[]{"Playlist"});
|
||||
query.setUserId(App.getApiClientInstance(context).getCurrentUserId());
|
||||
query.setRecursive(true);
|
||||
query.setParentId(musicLibrary.getId());
|
||||
|
||||
App.getApiClientInstance(context).GetItemsAsync(query, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
List<Playlist> playlists = new ArrayList<>();
|
||||
for (BaseItemDto itemDto : result.getItems()) {
|
||||
playlists.add(new Playlist(itemDto));
|
||||
}
|
||||
|
||||
callback.onLoadMedia(playlists);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void getGenres(Context context, MediaCallback callback) {
|
||||
ItemsByNameQuery query = new ItemsByNameQuery();
|
||||
|
||||
query.setUserId(App.getApiClientInstance(context).getCurrentUserId());
|
||||
query.setRecursive(true);
|
||||
query.setParentId(musicLibrary.getId());
|
||||
|
||||
App.getApiClientInstance(context).GetGenresAsync(query, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
List<Genre> genres = new ArrayList<>();
|
||||
for (BaseItemDto itemDto : result.getItems()) {
|
||||
genres.add(new Genre(itemDto));
|
||||
}
|
||||
|
||||
callback.onLoadMedia(genres);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.cappielloantonio.play.viewmodel;
|
||||
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HomeViewModel extends ViewModel {
|
||||
|
||||
public List<Song> getDiscoverSongList() {
|
||||
List<Song> discover_songs = new ArrayList<>();
|
||||
discover_songs.add(new Song("Holiday", "American Idiot"));
|
||||
discover_songs.add(new Song("Brioschi", "Stanza Singola"));
|
||||
discover_songs.add(new Song("HappySad", "Ceri Singles"));
|
||||
discover_songs.add(new Song("Falling back to Earth", "Haken"));
|
||||
|
||||
return discover_songs;
|
||||
}
|
||||
|
||||
public List<Song> getRecentSongList() {
|
||||
List<Song> recent_songs = new ArrayList<>();
|
||||
recent_songs.add(new Song("Holiday", "American Idiot"));
|
||||
recent_songs.add(new Song("Brioschi", "Stanza Singola"));
|
||||
recent_songs.add(new Song("HappySad", "Ceri Singles"));
|
||||
recent_songs.add(new Song("Falling back to Earth", "Haken"));
|
||||
|
||||
return recent_songs;
|
||||
}
|
||||
|
||||
public List<Song> getMostPlayedSongList() {
|
||||
List<Song> most_played_songs = new ArrayList<>();
|
||||
most_played_songs.add(new Song("Holiday", "American Idiot"));
|
||||
most_played_songs.add(new Song("Brioschi", "Stanza Singola"));
|
||||
most_played_songs.add(new Song("HappySad", "Ceri Singles"));
|
||||
most_played_songs.add(new Song("Falling back to Earth", "Haken"));
|
||||
|
||||
return most_played_songs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.cappielloantonio.play.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.repository.GenreRepository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LibraryViewModel extends AndroidViewModel {
|
||||
private GenreRepository genreRepository;
|
||||
private LiveData<List<Genre>> allGenres;
|
||||
|
||||
public LibraryViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
||||
genreRepository = new GenreRepository(application);
|
||||
allGenres = genreRepository.getListLiveGenres();
|
||||
}
|
||||
|
||||
public LiveData<List<Genre>> getGenreList() {
|
||||
return allGenres;
|
||||
}
|
||||
|
||||
public ArrayList<Album> getAlbumSample() {
|
||||
ArrayList<Album> albums = new ArrayList<>();
|
||||
albums.add(new Album("1", "aaaa", 1, "1", "qqqq", "", ""));
|
||||
albums.add(new Album("2", "ssss", 1, "2", "wwww", "", ""));
|
||||
albums.add(new Album("3", "dddd", 1, "3", "eeee", "", ""));
|
||||
albums.add(new Album("4", "ffff", 1, "4", "rrrr", "", ""));
|
||||
albums.add(new Album("5", "gggg", 1, "5", "tttt", "", ""));
|
||||
albums.add(new Album("6", "hhhh", 1, "6", "yyyy", "", ""));
|
||||
albums.add(new Album("7", "jjjj", 1, "7", "uuuu", "", ""));
|
||||
albums.add(new Album("8", "kkkk", 1, "8", "iiii", "", ""));
|
||||
albums.add(new Album("9", "llll", 1, "9", "oooo", "", ""));
|
||||
|
||||
return albums;
|
||||
}
|
||||
|
||||
public ArrayList<Artist> getArtistSample() {
|
||||
ArrayList<Artist> artists = new ArrayList<>();
|
||||
artists.add(new Artist("1", "dhgr", "", ""));
|
||||
artists.add(new Artist("2", "kdnu", "", ""));
|
||||
artists.add(new Artist("3", "wfty", "", ""));
|
||||
artists.add(new Artist("4", "hfds", "", ""));
|
||||
artists.add(new Artist("5", "jgab", "", ""));
|
||||
artists.add(new Artist("6", "iudg", "", ""));
|
||||
artists.add(new Artist("7", "istr", "", ""));
|
||||
artists.add(new Artist("8", "dger", "", ""));
|
||||
artists.add(new Artist("9", "jhjk", "", ""));
|
||||
|
||||
return artists;
|
||||
}
|
||||
|
||||
public ArrayList<Playlist> getPlaylist() {
|
||||
ArrayList<Playlist> playlists = new ArrayList<>();
|
||||
playlists.add(new Playlist("1", "sdad", "", ""));
|
||||
playlists.add(new Playlist("2", "rwef", "", ""));
|
||||
playlists.add(new Playlist("3", "khjf", "", ""));
|
||||
playlists.add(new Playlist("4", "thfd", "", ""));
|
||||
playlists.add(new Playlist("5", "jhku", "", ""));
|
||||
playlists.add(new Playlist("6", "tuid", "", ""));
|
||||
playlists.add(new Playlist("7", "hfrt", "", ""));
|
||||
playlists.add(new Playlist("8", "qedg", "", ""));
|
||||
playlists.add(new Playlist("9", "tugh", "", ""));
|
||||
|
||||
return playlists;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.cappielloantonio.play.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
import com.cappielloantonio.play.repository.SongRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SongViewModel extends AndroidViewModel {
|
||||
private SongRepository repository;
|
||||
private LiveData<List<Song>> allSongs;
|
||||
|
||||
public SongViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
||||
repository = new SongRepository(application);
|
||||
allSongs = repository.getListLiveSongs();
|
||||
}
|
||||
|
||||
public boolean exist(Song song) {
|
||||
return repository.exist(song);
|
||||
}
|
||||
|
||||
public void insert(Song song) {
|
||||
repository.insert(song);
|
||||
}
|
||||
|
||||
public void delete(Song song) {
|
||||
repository.delete(song);
|
||||
}
|
||||
|
||||
public LiveData<List<Song>> getAllSongs() {
|
||||
return allSongs;
|
||||
}
|
||||
}
|
||||
6
app/src/main/res/drawable/bottom_nav_selector.xml
Normal file
6
app/src/main/res/drawable/bottom_nav_selector.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/bottomNavIconPressedColor" android:state_pressed="true" />
|
||||
<item android:color="@color/bottomNavIconSelectedColor" android:state_checked="true" />
|
||||
<item android:color="@color/bottomNavIconColor" />
|
||||
</selector>
|
||||
5
app/src/main/res/drawable/bottom_nav_shape.xml
Normal file
5
app/src/main/res/drawable/bottom_nav_shape.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/cardColor" />
|
||||
<corners android:radius="4dp" />
|
||||
</shape>
|
||||
10
app/src/main/res/drawable/ic_close.xml
Normal file
10
app/src/main/res/drawable/ic_close.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_favorites.xml
Normal file
9
app/src/main/res/drawable/ic_favorites.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
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_filter.xml
Normal file
9
app/src/main/res/drawable/ic_filter.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_graphic_eq.xml
Normal file
9
app/src/main/res/drawable/ic_graphic_eq.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M8,18c0.55,0 1,-0.45 1,-1L9,7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v10c0,0.55 0.45,1 1,1zM12,22c0.55,0 1,-0.45 1,-1L13,3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v18c0,0.55 0.45,1 1,1zM4,14c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v2c0,0.55 0.45,1 1,1zM16,18c0.55,0 1,-0.45 1,-1L17,7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v10c0,0.55 0.45,1 1,1zM19,11v2c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_home.xml
Normal file
9
app/src/main/res/drawable/ic_home.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,5.69l5,4.5V18h-2v-6H9v6H7v-7.81l5,-4.5M12,3L2,12h3v8h6v-6h2v6h6v-8h3L12,3z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_qr_code.xml
Normal file
9
app/src/main/res/drawable/ic_qr_code.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15,21h-2v-2h2V21zM13,14h-2v5h2V14zM21,12h-2v4h2V12zM19,10h-2v2h2V10zM7,12H5v2h2V12zM5,10H3v2h2V10zM12,5h2V3h-2V5zM4.5,4.5v3h3v-3H4.5zM9,9H3V3h6V9zM4.5,16.5v3h3v-3H4.5zM9,21H3v-6h6V21zM16.5,4.5v3h3v-3H16.5zM21,9h-6V3h6V9zM19,19v-3l-4,0v2h2v3h4v-2H19zM17,12l-4,0v2h4V12zM13,10H7v2h2v2h2v-2h2V10zM14,9V7h-2V5h-2v4L14,9zM6.75,5.25h-1.5v1.5h1.5V5.25zM6.75,17.25h-1.5v1.5h1.5V17.25zM18.75,5.25h-1.5v1.5h1.5V5.25z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_search.xml
Normal file
9
app/src/main/res/drawable/ic_search.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_settings.xml
Normal file
9
app/src/main/res/drawable/ic_settings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
|
||||
</vector>
|
||||
BIN
app/src/main/res/font/bold.ttf
Normal file
BIN
app/src/main/res/font/bold.ttf
Normal file
Binary file not shown.
6
app/src/main/res/font/open_sans_font_family.xml
Normal file
6
app/src/main/res/font/open_sans_font_family.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<font-family
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<font app:font="@font/regular" app:fontStyle="normal" app:fontWeight="400" />
|
||||
<font app:font="@font/bold" app:fontStyle="normal" app:fontWeight="700" />
|
||||
</font-family>
|
||||
BIN
app/src/main/res/font/regular.ttf
Normal file
BIN
app/src/main/res/font/regular.ttf
Normal file
Binary file not shown.
31
app/src/main/res/layout/activity_main.xml
Normal file
31
app/src/main/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:imeOptions="actionDone">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/nav_host_fragment"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/nav_graph" />
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/bottom_navigation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@drawable/bottom_nav_shape"
|
||||
android:elevation="2dp"
|
||||
android:visibility="gone"
|
||||
app:itemIconTint="@drawable/bottom_nav_selector"
|
||||
app:labelVisibilityMode="unlabeled"
|
||||
app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap"
|
||||
app:menu="@menu/bottom_nav_menu" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
194
app/src/main/res/layout/fragment_home.xml
Normal file
194
app/src/main/res/layout/fragment_home.xml
Normal file
@@ -0,0 +1,194 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView 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="match_parent"
|
||||
app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<!-- Discover music -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="Discover Music"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="See all"
|
||||
android:textColor="@color/subtitleTextColor"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- slideview -->
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/discover_song_view_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="152dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Recently played tracks -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="Recently played tracks"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="See all"
|
||||
android:textColor="@color/subtitleTextColor"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recently_played_tracks_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" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Most played tracks -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="Most played tracks"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="See all"
|
||||
android:textColor="@color/subtitleTextColor"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/most_played_tracks_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" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/resync_button"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="Resync"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/normalTextColor"
|
||||
app:cornerRadius="24dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
7
app/src/main/res/layout/fragment_landing.xml
Normal file
7
app/src/main/res/layout/fragment_landing.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.fragment.LandingFragment">
|
||||
</FrameLayout>
|
||||
262
app/src/main/res/layout/fragment_library.xml
Normal file
262
app/src/main/res/layout/fragment_library.xml
Normal file
@@ -0,0 +1,262 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
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="match_parent"
|
||||
app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior">
|
||||
|
||||
<LinearLayout
|
||||
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="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<!-- Album -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="My Albums"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="See all"
|
||||
android:textColor="@color/subtitleTextColor"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/album_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" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<!-- Artist -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="My Artists"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="See all"
|
||||
android:textColor="@color/subtitleTextColor"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/artist_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" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<!-- Genre -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="My Genres"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="See all"
|
||||
android:textColor="@color/subtitleTextColor"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/genre_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" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<!-- Playlist -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Label and button -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="My Playlists"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:text="See all"
|
||||
android:textColor="@color/subtitleTextColor"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/playlist_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="10dp"
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
101
app/src/main/res/layout/fragment_login.xml
Normal file
101
app/src/main/res/layout/fragment_login.xml
Normal file
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/login_screen"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:boxCornerRadiusBottomEnd="24dp"
|
||||
app:boxCornerRadiusBottomStart="24dp"
|
||||
app:boxCornerRadiusTopEnd="24dp"
|
||||
app:boxCornerRadiusTopStart="24dp"
|
||||
app:boxStrokeColor="?android:textColorSecondary"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true"
|
||||
app:hintTextColor="?android:textColorSecondary">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/username_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Username"
|
||||
android:inputType="textShortMessage"
|
||||
android:text="Antonio" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:boxCornerRadiusBottomEnd="24dp"
|
||||
app:boxCornerRadiusBottomStart="24dp"
|
||||
app:boxCornerRadiusTopEnd="24dp"
|
||||
app:boxCornerRadiusTopStart="24dp"
|
||||
app:boxStrokeColor="?android:textColorSecondary"
|
||||
app:endIconMode="password_toggle"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true"
|
||||
app:hintTextColor="?android:textColorSecondary">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/password_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Password"
|
||||
android:inputType="textPassword"
|
||||
android:text="D5S%TXefMwHg4!i%ucNHJ#57" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:textColorHint="?android:textColorHint"
|
||||
app:boxCornerRadiusBottomEnd="24dp"
|
||||
app:boxCornerRadiusBottomStart="24dp"
|
||||
app:boxCornerRadiusTopEnd="24dp"
|
||||
app:boxCornerRadiusTopStart="24dp"
|
||||
app:boxStrokeColor="?android:textColorSecondary"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?android:textColorSecondary"
|
||||
app:errorEnabled="true"
|
||||
app:hintTextColor="?android:textColorSecondary">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/server_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Server"
|
||||
android:inputType="textNoSuggestions"
|
||||
android:text="http://192.168.1.81:8096" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:layout_margin="32dp"
|
||||
android:backgroundTint="@color/colorAccent"
|
||||
android:text="Login"
|
||||
android:textAllCaps="false"
|
||||
app:cornerRadius="24dp" />
|
||||
</LinearLayout>
|
||||
48
app/src/main/res/layout/fragment_search.xml
Normal file
48
app/src/main/res/layout/fragment_search.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout 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="match_parent">
|
||||
|
||||
<com.paulrybitskyi.persistentsearchview.PersistentSearchView
|
||||
android:id="@+id/persistentSearchView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingRight="4dp"
|
||||
app:areSuggestionsDisabled="true"
|
||||
app:cardBackgroundColor="@color/cardColor"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardElevation="2dp"
|
||||
app:clearInputButtonDrawable="@drawable/ic_close"
|
||||
app:dividerColor="@color/dividerColor"
|
||||
app:isClearInputButtonEnabled="true"
|
||||
app:isDismissableOnTouchOutside="true"
|
||||
app:isProgressBarEnabled="true"
|
||||
app:isVoiceInputButtonEnabled="true"
|
||||
app:leftButtonDrawable="@drawable/ic_search"
|
||||
app:progressBarColor="@color/colorAccent"
|
||||
app:queryInputBarIconColor="@color/darkIconColor"
|
||||
app:queryInputCursorColor="@color/colorAccent"
|
||||
app:queryInputHint="@string/search_hint"
|
||||
app:queryInputHintColor="@color/hintTextColor"
|
||||
app:queryInputTextColor="@color/hintTextColor"
|
||||
app:rightButtonDrawable="@drawable/ic_filter"
|
||||
app:shouldDimBehind="true" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="never"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingTop="60dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:paddingRight="2dp"
|
||||
android:paddingBottom="4dp" />
|
||||
</RelativeLayout>
|
||||
6
app/src/main/res/layout/fragment_settings.xml
Normal file
6
app/src/main/res/layout/fragment_settings.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
</RelativeLayout>
|
||||
20
app/src/main/res/layout/fragment_sync.xml
Normal file
20
app/src/main/res/layout/fragment_sync.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?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="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_progress_bar"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="false"
|
||||
android:minWidth="128dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:visibility="gone"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
39
app/src/main/res/layout/item_discover_song.xml
Normal file
39
app/src/main/res/layout/item_discover_song.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
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:backgroundTint="@color/cardColor"
|
||||
app:cardCornerRadius="4dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="136dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_discover_song_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginTop="18dp"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/artist_discover_song_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/title_discover_song_label"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:drawablePadding="10dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="3"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textColor="@color/subtitleTextColor"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
40
app/src/main/res/layout/item_library_album.xml
Normal file
40
app/src/main/res/layout/item_library_album.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<androidx.cardview.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="172dp"
|
||||
android:layout_gravity="center"
|
||||
android:backgroundTint="@color/cardColor"
|
||||
card_view:cardCornerRadius="4dp"
|
||||
card_view:cardElevation="2dp"
|
||||
card_view:cardPreventCornerOverlap="false"
|
||||
card_view:cardUseCompatPadding="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/album_name_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingTop="8dp"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/artist_name_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="2dp"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
31
app/src/main/res/layout/item_library_artist.xml
Normal file
31
app/src/main/res/layout/item_library_artist.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<androidx.cardview.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="172dp"
|
||||
android:layout_gravity="center"
|
||||
android:backgroundTint="@color/cardColor"
|
||||
card_view:cardCornerRadius="4dp"
|
||||
card_view:cardElevation="2dp"
|
||||
card_view:cardPreventCornerOverlap="false"
|
||||
card_view:cardUseCompatPadding="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/artist_name_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingTop="8dp"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
45
app/src/main/res/layout/item_library_genre.xml
Normal file
45
app/src/main/res/layout/item_library_genre.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<androidx.cardview.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:backgroundTint="@color/cardColor"
|
||||
card_view:cardCornerRadius="4dp"
|
||||
card_view:cardElevation="2dp"
|
||||
card_view:cardPreventCornerOverlap="false"
|
||||
card_view:cardUseCompatPadding="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<View
|
||||
android:layout_width="6dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/colorAccent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/genre_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="8dp"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:textAlignment="gravity"/>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
37
app/src/main/res/layout/item_library_playlist.xml
Normal file
37
app/src/main/res/layout/item_library_playlist.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="96dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingEnd="4dp">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:backgroundTint="@color/cardColor"
|
||||
card_view:cardCornerRadius="4dp"
|
||||
card_view:cardElevation="2dp"
|
||||
card_view:cardPreventCornerOverlap="false"
|
||||
card_view:cardUseCompatPadding="true">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/playlist_name_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:padding="18dp"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:textAlignment="center"/>
|
||||
</RelativeLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</RelativeLayout>
|
||||
40
app/src/main/res/layout/item_recent_track.xml
Normal file
40
app/src/main/res/layout/item_recent_track.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<androidx.cardview.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="156dp"
|
||||
android:layout_height="156dp"
|
||||
android:layout_gravity="center"
|
||||
android:backgroundTint="@color/cardColor"
|
||||
card_view:cardCornerRadius="4dp"
|
||||
card_view:cardElevation="2dp"
|
||||
card_view:cardPreventCornerOverlap="false"
|
||||
card_view:cardUseCompatPadding="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_track_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingTop="8dp"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/artist_track_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/open_sans_font_family"
|
||||
android:paddingStart="2dp"
|
||||
android:text="@string/label_placeholder"
|
||||
android:textColor="@color/titleTextColor"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
19
app/src/main/res/menu/bottom_nav_menu.xml
Normal file
19
app/src/main/res/menu/bottom_nav_menu.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/homeFragment"
|
||||
android:icon="@drawable/ic_home"
|
||||
android:title="@string/home_menu_label" />
|
||||
<item
|
||||
android:id="@+id/libraryFragment"
|
||||
android:icon="@drawable/ic_graphic_eq"
|
||||
android:title="@string/library_menu_label" />
|
||||
<item
|
||||
android:id="@+id/searchFragment"
|
||||
android:icon="@drawable/ic_search"
|
||||
android:title="@string/search_menu_label" />
|
||||
<item
|
||||
android:id="@+id/settingsFragment"
|
||||
android:icon="@drawable/ic_settings"
|
||||
android:title="@string/settings_menu_label" />
|
||||
</menu>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
85
app/src/main/res/navigation/nav_graph.xml
Normal file
85
app/src/main/res/navigation/nav_graph.xml
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation 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/nav_graph"
|
||||
app:startDestination="@id/landingFragment">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/landingFragment"
|
||||
android:name="com.cappielloantonio.play.ui.fragment.LandingFragment"
|
||||
android:label="fragment_landing"
|
||||
tools:layout="@layout/fragment_landing" >
|
||||
<action
|
||||
android:id="@+id/action_landingFragment_to_loginFragment"
|
||||
app:destination="@id/loginFragment"
|
||||
app:popUpTo="@id/landingFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
<action
|
||||
android:id="@+id/action_landingFragment_to_homeFragment"
|
||||
app:destination="@id/homeFragment"
|
||||
app:popUpTo="@id/landingFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
<action
|
||||
android:id="@+id/action_landingFragment_to_syncFragment"
|
||||
app:destination="@id/syncFragment"
|
||||
app:popUpTo="@id/landingFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/loginFragment"
|
||||
android:name="com.cappielloantonio.play.ui.fragment.LoginFragment"
|
||||
android:label="LoginFragment"
|
||||
tools:layout="@layout/fragment_login">
|
||||
<action
|
||||
android:id="@+id/action_loginFragment_to_syncFragment"
|
||||
app:destination="@id/syncFragment"
|
||||
app:popUpTo="@id/loginFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
<action
|
||||
android:id="@+id/action_loginFragment_to_homeFragment"
|
||||
app:destination="@id/homeFragment"
|
||||
app:popUpTo="@id/landingFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/syncFragment"
|
||||
android:name="com.cappielloantonio.play.ui.fragment.SyncFragment"
|
||||
android:label="SyncFragment"
|
||||
tools:layout="@layout/fragment_sync">
|
||||
<action
|
||||
android:id="@+id/action_syncFragment_to_homeFragment"
|
||||
app:destination="@id/homeFragment"
|
||||
app:popUpTo="@id/landingFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/homeFragment"
|
||||
android:name="com.cappielloantonio.play.ui.fragment.HomeFragment"
|
||||
android:label="HomeFragment"
|
||||
tools:layout="@layout/fragment_home">
|
||||
<action
|
||||
android:id="@+id/action_homeFragment_to_syncFragment"
|
||||
app:destination="@id/syncFragment"
|
||||
app:popUpTo="@id/homeFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/libraryFragment"
|
||||
android:name="com.cappielloantonio.play.ui.fragment.LibraryFragment"
|
||||
android:label="LibraryFragment"
|
||||
tools:layout="@layout/fragment_library"/>
|
||||
<fragment
|
||||
android:id="@+id/searchFragment"
|
||||
android:name="com.cappielloantonio.play.ui.fragment.SearchFragment"
|
||||
android:label="SearchFragment"
|
||||
tools:layout="@layout/fragment_search"/>
|
||||
<fragment
|
||||
android:id="@+id/settingsFragment"
|
||||
android:name="com.cappielloantonio.play.ui.fragment.SettingsFragment"
|
||||
android:label="SettingsFragment"
|
||||
tools:layout="@layout/fragment_settings"/>
|
||||
</navigation>
|
||||
28
app/src/main/res/values-night-v27/styles.xml
Normal file
28
app/src/main/res/values-night-v27/styles.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
|
||||
<item name="colorControlNormal">@color/colorPrimary</item>
|
||||
<item name="android:statusBarColor">@color/colorPrimary</item>
|
||||
<item name="android:navigationBarColor">@color/colorPrimary</item>
|
||||
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:windowLightNavigationBar">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:windowTranslucentNavigation">false</item>
|
||||
|
||||
<item name="dialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Dialog" parent="Theme.MaterialComponents.DayNight.Dialog">
|
||||
<item name="android:background">@color/colorPrimary</item>
|
||||
<item name="colorPrimary">@color/colorAccent</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:windowMinWidthMajor">82%</item>
|
||||
<item name="android:windowMinWidthMinor">82%</item>
|
||||
</style>
|
||||
</resources>
|
||||
37
app/src/main/res/values-night/colors.xml
Normal file
37
app/src/main/res/values-night/colors.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#121212</color>
|
||||
<color name="colorPrimaryDark">#121212</color>
|
||||
<color name="colorAccent">#733ae6</color>
|
||||
<color name="colorAccentLight">#aa6aff</color>
|
||||
|
||||
<!-- Ui color -->
|
||||
<color name="statusBarColor">#121212</color>
|
||||
<color name="navigationBarColor">#121212</color>
|
||||
<color name="navigationDrawerColor">#121211</color>
|
||||
|
||||
<color name="cardColor">#1D1D1D</color>
|
||||
|
||||
<color name="titleTextColor">#DADADA</color>
|
||||
<color name="subtitleTextColor">#9B9B9B</color>
|
||||
<color name="normalTextColor">#808080</color>
|
||||
<color name="normalIconColor">#808080</color>
|
||||
|
||||
<color name="suggestionTextColor">#DADADA</color>
|
||||
<color name="suggestionIconColor">#DADADA</color>
|
||||
<color name="darkTextColor">#CFCFCF</color>
|
||||
<color name="darkIconColor">#CFCFCF</color>
|
||||
<color name="suggestionSelectedTextColor">#CCCCCC</color>
|
||||
<color name="dividerColor">#707070</color>
|
||||
<color name="hintTextColor">#CFCFCF</color>
|
||||
<color name="iconSearchBarColor">#CFCFCF</color>
|
||||
<color name="contentContainerColor">#121212</color>
|
||||
|
||||
<color name="navigationDrawerTextColor">#F3F3F3</color>
|
||||
<color name="navigationDrawerIconColor">#A0A0A0</color>
|
||||
|
||||
<color name="bottomNavIconPressedColor">#FFFFFF</color>
|
||||
<color name="bottomNavIconSelectedColor">#EEEEEE</color>
|
||||
<color name="bottomNavIconColor">#707070</color>
|
||||
</resources>
|
||||
|
||||
25
app/src/main/res/values-night/styles.xml
Normal file
25
app/src/main/res/values-night/styles.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
|
||||
<item name="android:statusBarColor">@color/colorPrimary</item>
|
||||
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:windowTranslucentNavigation">false</item>
|
||||
|
||||
<item name="dialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Dialog" parent="Theme.MaterialComponents.DayNight.Dialog">
|
||||
<item name="android:background">@color/colorPrimary</item>
|
||||
<item name="colorPrimary">@color/colorAccent</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:windowMinWidthMajor">82%</item>
|
||||
<item name="android:windowMinWidthMinor">82%</item>
|
||||
</style>
|
||||
</resources>
|
||||
28
app/src/main/res/values-v27/styles.xml
Normal file
28
app/src/main/res/values-v27/styles.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
|
||||
<item name="colorControlNormal">@color/colorPrimary</item>
|
||||
<item name="android:statusBarColor">@color/colorPrimary</item>
|
||||
<item name="android:navigationBarColor">@color/colorPrimary</item>
|
||||
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:windowLightNavigationBar">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:windowTranslucentNavigation">false</item>
|
||||
|
||||
<item name="dialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Dialog" parent="Theme.MaterialComponents.DayNight.Dialog">
|
||||
<item name="android:background">@color/colorPrimary</item>
|
||||
<item name="colorPrimary">@color/colorAccent</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:windowMinWidthMajor">82%</item>
|
||||
<item name="android:windowMinWidthMinor">82%</item>
|
||||
</style>
|
||||
</resources>
|
||||
134
app/src/main/res/values/arrays.xml
Normal file
134
app/src/main/res/values/arrays.xml
Normal file
@@ -0,0 +1,134 @@
|
||||
<resources>
|
||||
<!-- Reply Preference -->
|
||||
<string-array name="reply_entries">
|
||||
<item>Reply</item>
|
||||
<item>Reply to all</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="reply_values">
|
||||
<item>reply</item>
|
||||
<item>reply_all</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="themeListArray">
|
||||
<item>Light</item>
|
||||
<item>Dark</item>
|
||||
<item>System default</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="themeEntryArray">
|
||||
<item>light</item>
|
||||
<item>dark</item>
|
||||
<item>default</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="searchByListArray">
|
||||
<item>Title</item>
|
||||
<item>Author(s)</item>
|
||||
<item>Series</item>
|
||||
<item>Publisher</item>
|
||||
<item>Year</item>
|
||||
<item>ISBN</item>
|
||||
<item>Language</item>
|
||||
<item>Tags</item>
|
||||
<item>Extension</item>
|
||||
<item>All</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="searchByEntryArray">
|
||||
<item>title</item>
|
||||
<item>author</item>
|
||||
<item>series</item>
|
||||
<item>publisher</item>
|
||||
<item>year</item>
|
||||
<item>isbn</item>
|
||||
<item>language</item>
|
||||
<item>tags</item>
|
||||
<item>extension</item>
|
||||
<item>all</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="searchMaskListArray">
|
||||
<item>Yes</item>
|
||||
<item>No</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="searchMaskEntryArray">
|
||||
<item>yes</item>
|
||||
<item>no</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="resultNumberListArray">
|
||||
<item>25</item>
|
||||
<item>50</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="resultNumberEntryArray">
|
||||
<item>25</item>
|
||||
<item>50</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_cache_size_titles">
|
||||
<item>Unlimited</item>
|
||||
<item>2GB</item>
|
||||
<item>1GB</item>
|
||||
<item>400MB</item>
|
||||
<item>200MB</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_cache_size_values">
|
||||
<item>4000000000</item>
|
||||
<item>2000000000</item>
|
||||
<item>1000000000</item>
|
||||
<item>400000000</item>
|
||||
<item>200000000</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="sortModeListArray">
|
||||
<item>Ascending</item>
|
||||
<item>Descending</item>
|
||||
<item>Default</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="sortModeEntryArray">
|
||||
<item>ASC</item>
|
||||
<item>DESC</item>
|
||||
<item>def</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="orderByListArray">
|
||||
<item>ID</item>
|
||||
<item>Author(s)</item>
|
||||
<item>Author(s)</item>
|
||||
<item>Publisher</item>
|
||||
<item>Year</item>
|
||||
<item>Pages</item>
|
||||
<item>Language</item>
|
||||
<item>Size</item>
|
||||
<item>Extension</item>
|
||||
<item>None</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="orderByEntryArray">
|
||||
<item>id</item>
|
||||
<item>author</item>
|
||||
<item>title</item>
|
||||
<item>publisher</item>
|
||||
<item>year</item>
|
||||
<item>pages</item>
|
||||
<item>language</item>
|
||||
<item>filesize</item>
|
||||
<item>extension</item>
|
||||
<item>none</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="saveFilterListArray">
|
||||
<item>Yes</item>
|
||||
<item>No</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="saveFilterEntryArray">
|
||||
<item>yes</item>
|
||||
<item>no</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
37
app/src/main/res/values/colors.xml
Normal file
37
app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#FFFFFF</color>
|
||||
<color name="colorPrimaryDark">#FFFFFF</color>
|
||||
<color name="colorAccent">#3700B3</color>
|
||||
<color name="colorAccentLight">#733ae6</color>
|
||||
|
||||
<!-- Ui color -->
|
||||
<color name="statusBarColor">#FFFFFF</color>
|
||||
<color name="navigationBarColor">#FFFFFF</color>
|
||||
<color name="navigationDrawerColor">#FFFFFF</color>
|
||||
|
||||
|
||||
<color name="cardColor">#FFFFFF</color>
|
||||
|
||||
<color name="titleTextColor">#252525</color>
|
||||
<color name="subtitleTextColor">#646464</color>
|
||||
<color name="normalTextColor">#7f7f7f</color>
|
||||
<color name="normalIconColor">#7f7f7f</color>
|
||||
|
||||
<color name="suggestionTextColor">#252525</color>
|
||||
<color name="suggestionIconColor">#252525</color>
|
||||
<color name="darkTextColor">#303030</color>
|
||||
<color name="darkIconColor">#303030</color>
|
||||
<color name="suggestionSelectedTextColor">#333333</color>
|
||||
<color name="dividerColor">#AFAFAF</color>
|
||||
<color name="hintTextColor">#303030</color>
|
||||
<color name="iconSearchBarColor">#303030</color>
|
||||
<color name="contentContainerColor">#EEEEEE</color>
|
||||
|
||||
<color name="navigationDrawerTextColor">#383838</color>
|
||||
<color name="navigationDrawerIconColor">#757575</color>
|
||||
|
||||
<color name="bottomNavIconPressedColor">#252525</color>
|
||||
<color name="bottomNavIconSelectedColor">#303030</color>
|
||||
<color name="bottomNavIconColor">#AFAFAF</color>
|
||||
</resources>
|
||||
8
app/src/main/res/values/dimens.xml
Normal file
8
app/src/main/res/values/dimens.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
<dimen name="nav_header_vertical_spacing">8dp</dimen>
|
||||
<dimen name="nav_header_height">176dp</dimen>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
</resources>
|
||||
35
app/src/main/res/values/strings.xml
Normal file
35
app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<resources>
|
||||
<string name="app_name">Play</string>
|
||||
<string name="storage_permission_rationale">We need permissions because this and that</string>
|
||||
<string name="title_activity_settings">Settings</string>
|
||||
<string name="title_activity_filters">Filters</string>
|
||||
<string name="title_activity_details">Details</string>
|
||||
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="general_header">General</string>
|
||||
<string name="search_hint">Search title, artists or albums</string>
|
||||
<string name="menu_home">Home</string>
|
||||
<string name="settings_menu_label">Settings</string>
|
||||
<string name="download_label">Download</string>
|
||||
<string name="shelf_label">Shelf</string>
|
||||
<string name="theme_header">Theme</string>
|
||||
<string name="theme_selection">Choose theme</string>
|
||||
<string name="covers_cache">Covers cache</string>
|
||||
<string name="search_label">Search</string>
|
||||
<string name="favorites_label">Favorites</string>
|
||||
<string name="categories_label">Categories</string>
|
||||
<string name="library_menu_label">Library</string>
|
||||
<string name="home_menu_label">Home</string>
|
||||
<string name="search_menu_label">Search</string>
|
||||
<string name="label_placeholder">--</string>
|
||||
<string name="save_filters">Save filters between sessions</string>
|
||||
|
||||
<string name="battery_optimizations_title">Battery Optimizations</string>
|
||||
<string name="battery_optimizations_message">Please disable battery optimizations for media playback while the screen is off.</string>
|
||||
|
||||
<string name="disable">Disable</string>
|
||||
<string name="ignore">Ignore</string>
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
|
||||
</resources>
|
||||
27
app/src/main/res/values/styles.xml
Normal file
27
app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
|
||||
<item name="android:statusBarColor">@color/colorPrimary</item>
|
||||
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:windowTranslucentNavigation">false</item>
|
||||
|
||||
<!-- <item name="android:dialogTheme">@style/AppTheme.Dialog</item>-->
|
||||
<!-- <item name="android:alertDialogTheme">@style/AppTheme.Dialog</item>-->
|
||||
<item name="dialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Dialog" parent="Theme.MaterialComponents.DayNight.Dialog">
|
||||
<item name="android:background">@color/colorPrimary</item>
|
||||
<item name="colorPrimary">@color/colorAccent</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:windowMinWidthMajor">82%</item>
|
||||
<item name="android:windowMinWidthMinor">82%</item>
|
||||
</style>
|
||||
</resources>
|
||||
30
app/src/main/res/xml/global_preferences.xml
Normal file
30
app/src/main/res/xml/global_preferences.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceCategory app:title="@string/general_header">
|
||||
<ListPreference
|
||||
app:defaultValue="400000000"
|
||||
app:dialogTitle="@string/covers_cache"
|
||||
app:entries="@array/pref_cache_size_titles"
|
||||
app:entryValues="@array/pref_cache_size_values"
|
||||
app:key="image_cache_size"
|
||||
app:title="@string/covers_cache"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<ListPreference
|
||||
app:defaultValue="default"
|
||||
app:dialogTitle="@string/theme_selection"
|
||||
app:entries="@array/themeListArray"
|
||||
app:entryValues="@array/themeEntryArray"
|
||||
app:key="themePref"
|
||||
app:title="@string/theme_selection"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<ListPreference
|
||||
app:defaultValue="no"
|
||||
app:dialogTitle="@string/save_filters"
|
||||
app:entries="@array/saveFilterListArray"
|
||||
app:entryValues="@array/saveFilterEntryArray"
|
||||
app:key="filtersPref"
|
||||
app:title="@string/save_filters"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.cappielloantonio.play;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
27
build.gradle
Normal file
27
build.gradle
Normal file
@@ -0,0 +1,27 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
19
gradle.properties
Normal file
19
gradle.properties
Normal file
@@ -0,0 +1,19 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app"s APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user