commit 36f5d1ce52b89bea89aee4e978dde215eff03f7a Author: ari melody Date: Thu Sep 12 12:01:16 2024 +0100 first commit! 🎉 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.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 +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..c65dcc3 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +AriDroid \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..0897082 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..2850f35 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..8978d23 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..ab29f6f --- /dev/null +++ b/.project @@ -0,0 +1,28 @@ + + + AriDroid + ari's firt android app :3 + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + + + 1726097811826 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..d9268cb --- /dev/null +++ b/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments=--init-script /Users/ari/.cache/jdtls/config/org.eclipse.osgi/330/0/.cp/gradle/init/init.gradle +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/app/.classpath b/app/.classpath new file mode 100644 index 0000000..0a3280e --- /dev/null +++ b/app/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/.project b/app/.project new file mode 100644 index 0000000..38e97e4 --- /dev/null +++ b/app/.project @@ -0,0 +1,34 @@ + + + AriDroid + ari's firt android app :3 + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + + + 1726097811845 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/app/.settings/org.eclipse.buildship.core.prefs b/app/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..b1886ad --- /dev/null +++ b/app/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..382bb67 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,43 @@ +plugins { + alias(libs.plugins.android.application) +} + +android { + namespace = "me.arimelody.aridroid" + compileSdk = 34 + + defaultConfig { + applicationId = "me.arimelody.aridroid" + minSdk = 33 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} + +dependencies { + + implementation(libs.appcompat) + implementation(libs.material) + implementation(libs.activity) + implementation(libs.constraintlayout) + testImplementation(libs.junit) + androidTestImplementation(libs.ext.junit) + androidTestImplementation(libs.espresso.core) +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -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 \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6b889d5 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/me/arimelody/aridroid/MainActivity.java b/app/src/main/java/me/arimelody/aridroid/MainActivity.java new file mode 100644 index 0000000..95400a2 --- /dev/null +++ b/app/src/main/java/me/arimelody/aridroid/MainActivity.java @@ -0,0 +1,139 @@ +package me.arimelody.aridroid; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.util.JsonReader; + +import androidx.activity.EdgeToEdge; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.channels.ClosedByInterruptException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Locale; + +public class MainActivity extends AppCompatActivity { + + public static String BASE_URL; + + RecyclerView musicList; + MusicListAdapter musicListAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_main); + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { + Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); + return insets; + }); + + BASE_URL = getResources().getString(R.string.base_url); + + musicList = findViewById(R.id.musicList); + + ArrayList items = new ArrayList<>(); + fetchMusicData(items); + + musicListAdapter = new MusicListAdapter(this, items); + + musicList.setAdapter(musicListAdapter); + musicList.setLayoutManager(new LinearLayoutManager(this)); + } + + void fetchMusicData(ArrayList items) { + Thread thread = new Thread(() -> { + try { + URL url = URI.create(BASE_URL + "/api/v1/music").toURL(); + System.out.printf("Attempting to fetch %s...\n", url); + HttpURLConnection http = (HttpURLConnection) url.openConnection(); + http.setRequestMethod("GET"); + http.setRequestProperty("User-Agent", "aridroid"); + http.setRequestProperty("Accept", "application/json"); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length = 0; + while ((length = http.getInputStream().read(buffer)) != -1) { + stream.write(buffer, 0, length); + } + updateReleaseList(stream.toString(), items); + } catch (Exception e) { + System.err.printf("FATAL: Failed to fetch music data: %s\n", e.toString()); + } + }); + thread.start(); + } + + void updateReleaseList(String res, ArrayList items) { + System.out.println(res); + try { + JSONArray json = new JSONArray(res); + items.clear(); + musicList.post(() -> { + musicListAdapter.notifyItemRangeRemoved(0, items.size()); + }); + + for (int i = 0; i < json.length(); i++) { + JSONObject obj = json.getJSONObject(i); + + String id = obj.getString("id"); + ArrayList credits = new ArrayList<>(); + + JSONArray jsonArtists = obj.getJSONArray("artists"); + for (int ci = 0; ci < jsonArtists.length(); ci++) + credits.add(new MusicCreditModel("", jsonArtists.getString(ci), "", true)); + String buylink = obj.getString("buylink"); + + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.GERMANY); + Date date; + try { + date = df.parse(obj.getString("releaseDate")); + } catch (ParseException e) { + System.err.printf("FATAL: Failed to parse date for release %s: %s\n", id, e.toString()); + continue; + } + + MusicItemModel item = new MusicItemModel( + id, + obj.getString("title"), + "", + obj.getString("type"), + date, + obj.getString("artwork"), + "Buy", + buylink, + obj.getString("copyright"), + null, + credits); + + items.add(item); + musicList.post(() -> { + musicListAdapter.notifyItemInserted(items.size()); + }); + } + } catch (JSONException e) { + System.err.printf("FATAL: Failed to parse JSON response: %s\n", e.toString()); + } + } +} diff --git a/app/src/main/java/me/arimelody/aridroid/MusicCreditModel.java b/app/src/main/java/me/arimelody/aridroid/MusicCreditModel.java new file mode 100644 index 0000000..4bb4bba --- /dev/null +++ b/app/src/main/java/me/arimelody/aridroid/MusicCreditModel.java @@ -0,0 +1,31 @@ +package me.arimelody.aridroid; + +public class MusicCreditModel { + private final String id; + private final String name; + private final String role; + private final boolean primary; + + public MusicCreditModel(String id, String name, String role, boolean primary) { + this.id = id; + this.name = name; + this.role = role; + this.primary = primary; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public String getRole() { + return role; + } + + public boolean isPrimary() { + return primary; + } +} diff --git a/app/src/main/java/me/arimelody/aridroid/MusicItemModel.java b/app/src/main/java/me/arimelody/aridroid/MusicItemModel.java new file mode 100644 index 0000000..77866fd --- /dev/null +++ b/app/src/main/java/me/arimelody/aridroid/MusicItemModel.java @@ -0,0 +1,77 @@ +package me.arimelody.aridroid; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; + +public class MusicItemModel { + private final String id; + private final String title; + private final String description; + private final String type; + private final Date releaseDate; + private final String artwork; + private final String buyname; + private final String buylink; + private final String copyright; + private final URL copyrightURL; + private final ArrayList credits; + + public MusicItemModel(String id, String title, String description, String type, Date releaseDate, String artwork, String buyname, String buylink, String copyright, URL copyrightURL, ArrayList credits) { + this.id = id; + this.title = title; + this.description = description; + this.type = type; + this.releaseDate = releaseDate; + this.artwork = artwork; + this.buyname = buyname; + this.buylink = buylink; + this.copyright = copyright; + this.copyrightURL = copyrightURL; + this.credits = credits; + } + + public String getId() { + return id; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public String getType() { + return type; + } + + public Date getReleaseDate() { + return releaseDate; + } + + public String getArtwork() { + return artwork; + } + + public String getBuyname() { + return buyname; + } + + public String getBuylink() { + return buylink; + } + + public String getCopyright() { + return copyright; + } + + public URL getCopyrightURL() { + return copyrightURL; + } + + public ArrayList getCredits() { + return credits; + } +} diff --git a/app/src/main/java/me/arimelody/aridroid/MusicListAdapter.java b/app/src/main/java/me/arimelody/aridroid/MusicListAdapter.java new file mode 100644 index 0000000..b496184 --- /dev/null +++ b/app/src/main/java/me/arimelody/aridroid/MusicListAdapter.java @@ -0,0 +1,114 @@ +package me.arimelody.aridroid; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Locale; + +public class MusicListAdapter extends RecyclerView.Adapter { + Context context; + ArrayList data; + + public MusicListAdapter(Context context, ArrayList data) { + this.context = context; + this.data = data; + } + + @NonNull + @Override + public MusicListAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(context); + View view = inflater.inflate(R.layout.music_item, parent, false); + return new MusicListAdapter.MyViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull MusicListAdapter.MyViewHolder holder, int position) { + MusicItemModel release = data.get(position); + + holder.fetchReleaseArtwork(release.getArtwork()); + holder.artwork.setContentDescription(release.getTitle() + " artwork"); + + holder.title.setText(release.getTitle()); + + Calendar calendar = Calendar.getInstance(); + calendar.setTime(release.getReleaseDate()); + holder.year.setText(calendar.getDisplayName(Calendar.YEAR, Calendar.LONG_FORMAT, Locale.ENGLISH)); + + StringBuilder artist = new StringBuilder(); + ArrayList primaryCredits = new ArrayList<>(); + for (int i = 0; i < release.getCredits().size(); i++) { + if (!release.getCredits().get(i).isPrimary()) continue; + primaryCredits.add(release.getCredits().get(i)); + } + for (int i = 0; i < primaryCredits.size(); i++) { + if (i == 0) { + artist.append(primaryCredits.get(i).getName()); + continue; + } + if (i == primaryCredits.size() - 1) { + artist.append(" & ").append(primaryCredits.get(i).getName()); + break; + } + artist.append(primaryCredits.get(i).getName()).append(", "); + } + holder.artist.setText(artist.toString()); + } + + @Override + public int getItemCount() { + return data.size(); + } + + public static class MyViewHolder extends RecyclerView.ViewHolder { + ImageView artwork; + TextView title; + TextView year; + TextView artist; + + public MyViewHolder(@NonNull View itemView) { + super(itemView); + + artwork = itemView.findViewById(R.id.musicArtwork); + title = itemView.findViewById(R.id.musicTitle); + year = itemView.findViewById(R.id.musicYear); + artist = itemView.findViewById(R.id.musicArtist); + } + + void fetchReleaseArtwork(String artworkURL) { + Thread thread = new Thread(() -> { + try { + URL url = new URL(MainActivity.BASE_URL + artworkURL); + System.out.printf("Attempting to fetch %s...\n", url); + HttpURLConnection http = (HttpURLConnection) url.openConnection(); + http.setRequestMethod("GET"); + http.setRequestProperty("User-Agent", "aridroid"); + http.setRequestProperty("Accept", "image/*"); + + InputStream stream = http.getInputStream(); + Bitmap img = BitmapFactory.decodeStream(stream); + // TODO: image caching + // https://developer.android.com/topic/performance/graphics/cache-bitmap#java + artwork.setImageBitmap(img); + } catch (Exception e) { + System.err.printf("FATAL: Failed to fetch music data: %s\n", e.toString()); + } + }); + thread.start(); + } + } +} diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..ce14471 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/music_item.xml b/app/src/main/res/layout/music_item.xml new file mode 100644 index 0000000..464d45e --- /dev/null +++ b/app/src/main/res/layout/music_item.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..ce53919 --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,7 @@ + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..c8524cd --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,5 @@ + + + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..8320cfc --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,8 @@ + + https://arimelody.me + AriDroid + Untitled Track + Unknown Artist + 2002 + Music artwork + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..9895922 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,9 @@ + + + + +