HUGE ui rewrite waow. very nice
This commit is contained in:
parent
f5e50cf481
commit
dc64cb65b1
|
@ -4,6 +4,14 @@
|
||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
|
<DropdownSelection timestamp="2024-09-13T01:49:05.448371200Z">
|
||||||
|
<Target type="DEFAULT_BOOT">
|
||||||
|
<handle>
|
||||||
|
<DeviceId pluginId="PhysicalDevice" identifier="serial=3374c0d40804" />
|
||||||
|
</handle>
|
||||||
|
</Target>
|
||||||
|
</DropdownSelection>
|
||||||
|
<DialogSelection />
|
||||||
</SelectionState>
|
</SelectionState>
|
||||||
</selectionStates>
|
</selectionStates>
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -4,16 +4,18 @@ plugins {
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "me.arimelody.aridroid"
|
namespace = "me.arimelody.aridroid"
|
||||||
compileSdk = 34
|
compileSdk = 35
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "me.arimelody.aridroid"
|
applicationId = "me.arimelody.aridroid"
|
||||||
minSdk = 28
|
minSdk = 28
|
||||||
targetSdk = 34
|
targetSdk = 35
|
||||||
versionCode = 1
|
versionCode = 2
|
||||||
versionName = "1.0"
|
versionName = "1.1"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
resourceConfigurations += setOf()
|
||||||
|
setProperty("archivesBaseName", applicationId + "-v" + versionCode + "(" + versionName + ")")
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|
Binary file not shown.
Binary file not shown.
BIN
app/release/me.arimelody.aridroid-v2(1.1)-release.apk
Normal file
BIN
app/release/me.arimelody.aridroid-v2(1.1)-release.apk
Normal file
Binary file not shown.
37
app/release/output-metadata.json
Normal file
37
app/release/output-metadata.json
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"artifactType": {
|
||||||
|
"type": "APK",
|
||||||
|
"kind": "Directory"
|
||||||
|
},
|
||||||
|
"applicationId": "me.arimelody.aridroid",
|
||||||
|
"variantName": "release",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"type": "SINGLE",
|
||||||
|
"filters": [],
|
||||||
|
"attributes": [],
|
||||||
|
"versionCode": 2,
|
||||||
|
"versionName": "1.1",
|
||||||
|
"outputFile": "me.arimelody.aridroid-v2(1.1)-release.apk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"elementType": "File",
|
||||||
|
"baselineProfiles": [
|
||||||
|
{
|
||||||
|
"minApi": 28,
|
||||||
|
"maxApi": 30,
|
||||||
|
"baselineProfiles": [
|
||||||
|
"baselineProfiles/1/me.arimelody.aridroid-v2(1.1)-release.dm"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minApi": 31,
|
||||||
|
"maxApi": 2147483647,
|
||||||
|
"baselineProfiles": [
|
||||||
|
"baselineProfiles/0/me.arimelody.aridroid-v2(1.1)-release.dm"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"minSdkVersionForDexing": 28
|
||||||
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.AriDroid">
|
android:theme="@style/AriDroid.Base">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
@ -21,6 +21,9 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<meta-data
|
||||||
|
android:name="preloaded_fonts"
|
||||||
|
android:resource="@array/preloaded_fonts" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
127
app/src/main/java/me/arimelody/aridroid/ArtistListAdapter.java
Normal file
127
app/src/main/java/me/arimelody/aridroid/ArtistListAdapter.java
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
package me.arimelody.aridroid;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.LruCache;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class ArtistListAdapter extends RecyclerView.Adapter<ArtistListAdapter.ArtistViewHolder> {
|
||||||
|
Context context;
|
||||||
|
Handler handler;
|
||||||
|
ArrayList<ArtistModel> artists;
|
||||||
|
LruCache<URL, Bitmap> avatarCache;
|
||||||
|
|
||||||
|
public ArtistListAdapter(@NonNull Context context) {
|
||||||
|
this.context = context;
|
||||||
|
handler = new Handler(Looper.getMainLooper());
|
||||||
|
artists = new ArrayList<>();
|
||||||
|
|
||||||
|
avatarCache = new LruCache<>(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addArtist(ArtistModel artist) {
|
||||||
|
artists.add(artist);
|
||||||
|
handler.post(() -> notifyItemInserted(artists.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeArtist(int position) {
|
||||||
|
artists.remove(position);
|
||||||
|
handler.post(() -> notifyItemRemoved(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearArtists() {
|
||||||
|
int size = artists.size();
|
||||||
|
artists.clear();
|
||||||
|
handler.post(() -> notifyItemRangeRemoved(0, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public ArtistViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(context);
|
||||||
|
View view = inflater.inflate(R.layout.artist_list_item, parent, false);
|
||||||
|
return new ArtistViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull ArtistViewHolder holder, int position) {
|
||||||
|
ArtistModel artist = artists.get(position);
|
||||||
|
|
||||||
|
holder.website.setOnClickListener(new View.OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(artist.getWebsite()));
|
||||||
|
context.startActivity(browserIntent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
holder.name.setText(artist.getName());
|
||||||
|
if (!artist.getAvatarURL().isEmpty())
|
||||||
|
holder.fetchAvatar(artist.getAvatarURL(), avatarCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return artists.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ArtistViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
ImageView avatar;
|
||||||
|
TextView name;
|
||||||
|
Button website;
|
||||||
|
|
||||||
|
public ArtistViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
|
||||||
|
avatar = itemView.findViewById(R.id.artistAvatar);
|
||||||
|
name = itemView.findViewById(R.id.artistName);
|
||||||
|
website = itemView.findViewById(R.id.artistWebsite);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchAvatar(String avatarURL, LruCache<URL, Bitmap> avatarCache) {
|
||||||
|
Thread thread = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
URL url = new URL(MainActivity.BASE_URL + avatarURL);
|
||||||
|
|
||||||
|
// check cache
|
||||||
|
Bitmap cachedImage = avatarCache.get(url);
|
||||||
|
if (cachedImage != null) {
|
||||||
|
avatar.post(() -> avatar.setImageBitmap(cachedImage));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.printf("Fetching %s...\n", url);
|
||||||
|
HttpURLConnection http = (HttpURLConnection) url.openConnection();
|
||||||
|
http.setRequestMethod("GET");
|
||||||
|
http.setRequestProperty("User-Agent", "aridroid/" + MainActivity.VERSION);
|
||||||
|
http.setRequestProperty("Accept", "image/*");
|
||||||
|
|
||||||
|
InputStream stream = http.getInputStream();
|
||||||
|
Bitmap img = BitmapFactory.decodeStream(stream);
|
||||||
|
// store image in memory cache
|
||||||
|
avatarCache.put(url, img);
|
||||||
|
avatar.post(() -> avatar.setImageBitmap(img));
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.printf("FATAL: Failed to fetch release artwork: %s\n", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
app/src/main/java/me/arimelody/aridroid/ArtistModel.java
Normal file
31
app/src/main/java/me/arimelody/aridroid/ArtistModel.java
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package me.arimelody.aridroid;
|
||||||
|
|
||||||
|
public class ArtistModel {
|
||||||
|
private final String id;
|
||||||
|
private final String name;
|
||||||
|
private final String website;
|
||||||
|
private final String avatarURL;
|
||||||
|
|
||||||
|
public ArtistModel(String id, String name, String website, String avatarURL) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.website = website;
|
||||||
|
this.avatarURL = avatarURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWebsite() {
|
||||||
|
return website;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAvatarURL() {
|
||||||
|
return avatarURL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
package me.arimelody.aridroid;
|
package me.arimelody.aridroid;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.content.pm.PackageInfo;
|
||||||
import android.graphics.BitmapFactory;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.JsonReader;
|
|
||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
import androidx.activity.EdgeToEdge;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
@ -18,12 +17,9 @@ import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.channels.ClosedByInterruptException;
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -31,11 +27,8 @@ import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
public static String BASE_URL;
|
public static String BASE_URL;
|
||||||
|
public static String VERSION;
|
||||||
RecyclerView musicList;
|
|
||||||
MusicListAdapter musicListAdapter;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
@ -48,55 +41,61 @@ public class MainActivity extends AppCompatActivity {
|
||||||
return insets;
|
return insets;
|
||||||
});
|
});
|
||||||
|
|
||||||
BASE_URL = getResources().getString(R.string.base_url);
|
try {
|
||||||
|
PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
|
||||||
musicList = findViewById(R.id.musicList);
|
VERSION = pInfo.versionName;
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
ArrayList<MusicItemModel> items = new ArrayList<>();
|
throw new RuntimeException(e);
|
||||||
fetchMusicData(items);
|
|
||||||
|
|
||||||
musicListAdapter = new MusicListAdapter(this, items);
|
|
||||||
|
|
||||||
musicList.setAdapter(musicListAdapter);
|
|
||||||
musicList.setLayoutManager(new LinearLayoutManager(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchMusicData(ArrayList<MusicItemModel> items) {
|
BASE_URL = getResources().getString(R.string.base_url);
|
||||||
|
|
||||||
|
ReleaseListAdapter releaseListAdapter = new ReleaseListAdapter(this);
|
||||||
|
fetchReleaseData(releaseListAdapter);
|
||||||
|
ArtistListAdapter artistListAdapter = new ArtistListAdapter(this);
|
||||||
|
fetchArtistData(artistListAdapter);
|
||||||
|
|
||||||
|
RecyclerView releaseList = findViewById(R.id.musicList);
|
||||||
|
releaseList.setAdapter(releaseListAdapter);
|
||||||
|
releaseList.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
|
||||||
|
RecyclerView artistList = findViewById(R.id.artistList);
|
||||||
|
artistList.setAdapter(artistListAdapter);
|
||||||
|
artistList.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchReleaseData(ReleaseListAdapter releaseListAdapter) {
|
||||||
Thread thread = new Thread(() -> {
|
Thread thread = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
URL url = URI.create(BASE_URL + "/api/v1/music").toURL();
|
URL url = URI.create(BASE_URL + "/api/v1/music").toURL();
|
||||||
System.out.printf("Fetching %s...\n", url);
|
System.out.printf("Fetching %s...\n", url);
|
||||||
HttpURLConnection http = (HttpURLConnection) url.openConnection();
|
HttpURLConnection http = (HttpURLConnection) url.openConnection();
|
||||||
http.setRequestMethod("GET");
|
http.setRequestMethod("GET");
|
||||||
http.setRequestProperty("User-Agent", "aridroid");
|
http.setRequestProperty("User-Agent", "aridroid/" + MainActivity.VERSION);
|
||||||
http.setRequestProperty("Accept", "application/json");
|
http.setRequestProperty("Accept", "application/json");
|
||||||
|
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
int length = 0;
|
int length;
|
||||||
while ((length = http.getInputStream().read(buffer)) != -1) {
|
while ((length = http.getInputStream().read(buffer)) != -1) {
|
||||||
stream.write(buffer, 0, length);
|
stream.write(buffer, 0, length);
|
||||||
}
|
}
|
||||||
updateReleaseList(stream.toString(), items);
|
updateReleaseList(stream.toString(), releaseListAdapter);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.printf("Failed to fetch music data: %s\n", e.toString());
|
System.err.printf("Failed to fetch music data: %s\n", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateReleaseList(String res, ArrayList<MusicItemModel> items) {
|
void updateReleaseList(String res, ReleaseListAdapter releaseListAdapter) {
|
||||||
try {
|
try {
|
||||||
JSONArray json = new JSONArray(res);
|
JSONArray json = new JSONArray(res);
|
||||||
items.clear();
|
releaseListAdapter.clearReleases();
|
||||||
musicList.post(() -> {
|
|
||||||
musicListAdapter.notifyItemRangeRemoved(0, items.size());
|
|
||||||
});
|
|
||||||
|
|
||||||
for (int i = 0; i < json.length(); i++) {
|
for (int i = 0; i < json.length(); i++) {
|
||||||
JSONObject obj = json.getJSONObject(i);
|
JSONObject obj = json.getJSONObject(i);
|
||||||
|
|
||||||
String id = obj.getString("id");
|
|
||||||
ArrayList<MusicCreditModel> credits = new ArrayList<>();
|
ArrayList<MusicCreditModel> credits = new ArrayList<>();
|
||||||
|
|
||||||
JSONArray jsonArtists = obj.getJSONArray("artists");
|
JSONArray jsonArtists = obj.getJSONArray("artists");
|
||||||
|
@ -109,12 +108,12 @@ public class MainActivity extends AppCompatActivity {
|
||||||
try {
|
try {
|
||||||
date = df.parse(obj.getString("releaseDate"));
|
date = df.parse(obj.getString("releaseDate"));
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
System.err.printf("Failed to parse date for release %s: %s\n", id, e.toString());
|
System.err.printf("Failed to parse date for release %s: %s\n", obj.getString("id"), e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicItemModel item = new MusicItemModel(
|
releaseListAdapter.addRelease(new ReleaseModel(
|
||||||
id,
|
obj.getString("id"),
|
||||||
obj.getString("title"),
|
obj.getString("title"),
|
||||||
"",
|
"",
|
||||||
obj.getString("type"),
|
obj.getString("type"),
|
||||||
|
@ -124,15 +123,53 @@ public class MainActivity extends AppCompatActivity {
|
||||||
buylink,
|
buylink,
|
||||||
obj.getString("copyright"),
|
obj.getString("copyright"),
|
||||||
null,
|
null,
|
||||||
credits);
|
credits));
|
||||||
|
|
||||||
items.add(item);
|
|
||||||
musicList.post(() -> {
|
|
||||||
musicListAdapter.notifyItemInserted(items.size());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
System.err.printf("Failed to parse JSON response: %s\n", e.toString());
|
System.err.printf("Failed to parse JSON response: %s\n", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchArtistData(ArtistListAdapter artistListAdapter) {
|
||||||
|
Thread thread = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
URL url = URI.create(BASE_URL + "/api/v1/artist").toURL();
|
||||||
|
System.out.printf("Fetching %s...\n", url);
|
||||||
|
HttpURLConnection http = (HttpURLConnection) url.openConnection();
|
||||||
|
http.setRequestMethod("GET");
|
||||||
|
http.setRequestProperty("User-Agent", "aridroid/" + MainActivity.VERSION);
|
||||||
|
http.setRequestProperty("Accept", "application/json");
|
||||||
|
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int length;
|
||||||
|
while ((length = http.getInputStream().read(buffer)) != -1) {
|
||||||
|
stream.write(buffer, 0, length);
|
||||||
|
}
|
||||||
|
updateArtistList(stream.toString(), artistListAdapter);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.printf("Failed to fetch artist data: %s\n", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateArtistList(String res, ArtistListAdapter artistListAdapter) {
|
||||||
|
try {
|
||||||
|
JSONArray json = new JSONArray(res);
|
||||||
|
artistListAdapter.clearArtists();
|
||||||
|
|
||||||
|
for (int i = 0; i < json.length(); i++) {
|
||||||
|
JSONObject obj = json.getJSONObject(i);
|
||||||
|
|
||||||
|
artistListAdapter.addArtist(new ArtistModel(
|
||||||
|
obj.getString("id"),
|
||||||
|
obj.getString("name"),
|
||||||
|
obj.getString("website"),
|
||||||
|
obj.getString("avatar")));
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
System.err.printf("Failed to parse JSON response: %s\n", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@ package me.arimelody.aridroid;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.LruCache;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -10,7 +13,6 @@ import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -20,17 +22,19 @@ import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class MusicListAdapter extends RecyclerView.Adapter<MusicListAdapter.MyViewHolder> {
|
public class ReleaseListAdapter extends RecyclerView.Adapter<ReleaseListAdapter.ReleaseViewHolder> {
|
||||||
Context context;
|
Context context;
|
||||||
ArrayList<MusicItemModel> data;
|
Handler handler;
|
||||||
|
ArrayList<ReleaseModel> releases;
|
||||||
|
LruCache<URL, Bitmap> artworkCache;
|
||||||
|
|
||||||
public HashMap<String, Integer> ReleaseTypes = new HashMap();
|
public static HashMap<String, Integer> ReleaseTypes = new HashMap<>();
|
||||||
|
|
||||||
public MusicListAdapter(Context context, ArrayList<MusicItemModel> data) {
|
public ReleaseListAdapter(@NonNull Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.data = data;
|
handler = new Handler(Looper.getMainLooper());
|
||||||
|
releases = new ArrayList<>();
|
||||||
|
|
||||||
ReleaseTypes.put("single", R.string.release_type_single);
|
ReleaseTypes.put("single", R.string.release_type_single);
|
||||||
ReleaseTypes.put("album", R.string.release_type_album);
|
ReleaseTypes.put("album", R.string.release_type_album);
|
||||||
|
@ -38,21 +42,40 @@ public class MusicListAdapter extends RecyclerView.Adapter<MusicListAdapter.MyVi
|
||||||
ReleaseTypes.put("lp", R.string.release_type_lp);
|
ReleaseTypes.put("lp", R.string.release_type_lp);
|
||||||
ReleaseTypes.put("compilation", R.string.release_type_compilation);
|
ReleaseTypes.put("compilation", R.string.release_type_compilation);
|
||||||
ReleaseTypes.put("upcoming", R.string.release_type_upcoming);
|
ReleaseTypes.put("upcoming", R.string.release_type_upcoming);
|
||||||
|
|
||||||
|
artworkCache = new LruCache<>(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRelease(ReleaseModel release) {
|
||||||
|
releases.add(release);
|
||||||
|
handler.post(() -> notifyItemInserted(releases.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeRelease(int position) {
|
||||||
|
releases.remove(position);
|
||||||
|
handler.post(() -> notifyItemRemoved(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearReleases() {
|
||||||
|
int size = releases.size();
|
||||||
|
releases.clear();
|
||||||
|
handler.post(() -> notifyItemRangeRemoved(0, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public MusicListAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public ReleaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
LayoutInflater inflater = LayoutInflater.from(context);
|
LayoutInflater inflater = LayoutInflater.from(context);
|
||||||
View view = inflater.inflate(R.layout.music_item, parent, false);
|
View view = inflater.inflate(R.layout.release_list_item, parent, false);
|
||||||
return new MusicListAdapter.MyViewHolder(view);
|
return new ReleaseViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull MusicListAdapter.MyViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ReleaseViewHolder holder, int position) {
|
||||||
MusicItemModel release = data.get(position);
|
ReleaseModel release = releases.get(position);
|
||||||
|
|
||||||
holder.fetchReleaseArtwork(release.getArtwork());
|
if (!release.getArtworkURL().isEmpty())
|
||||||
|
holder.fetchReleaseArtwork(release.getArtworkURL(), artworkCache);
|
||||||
holder.artwork.setContentDescription(release.getTitle() + " artwork");
|
holder.artwork.setContentDescription(release.getTitle() + " artwork");
|
||||||
|
|
||||||
holder.title.setText(release.getTitle());
|
holder.title.setText(release.getTitle());
|
||||||
|
@ -86,43 +109,51 @@ public class MusicListAdapter extends RecyclerView.Adapter<MusicListAdapter.MyVi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return data.size();
|
return releases.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MyViewHolder extends RecyclerView.ViewHolder {
|
public static class ReleaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
ImageView artwork;
|
ImageView artwork;
|
||||||
TextView title;
|
TextView title;
|
||||||
TextView year;
|
TextView year;
|
||||||
TextView artist;
|
TextView artist;
|
||||||
TextView type;
|
TextView type;
|
||||||
|
|
||||||
public MyViewHolder(@NonNull View itemView) {
|
public ReleaseViewHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
artwork = itemView.findViewById(R.id.musicArtwork);
|
artwork = itemView.findViewById(R.id.artistAvatar);
|
||||||
title = itemView.findViewById(R.id.musicTitle);
|
title = itemView.findViewById(R.id.musicTitle);
|
||||||
year = itemView.findViewById(R.id.musicYear);
|
year = itemView.findViewById(R.id.musicYear);
|
||||||
artist = itemView.findViewById(R.id.musicArtist);
|
artist = itemView.findViewById(R.id.musicArtist);
|
||||||
type = itemView.findViewById(R.id.musicType);
|
type = itemView.findViewById(R.id.musicType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchReleaseArtwork(String artworkURL) {
|
void fetchReleaseArtwork(String artworkURL, LruCache<URL, Bitmap> artworkCache) {
|
||||||
Thread thread = new Thread(() -> {
|
Thread thread = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
URL url = new URL(MainActivity.BASE_URL + artworkURL);
|
URL url = new URL(MainActivity.BASE_URL + artworkURL);
|
||||||
|
|
||||||
|
// check cache
|
||||||
|
Bitmap cachedImage = artworkCache.get(url);
|
||||||
|
if (cachedImage != null) {
|
||||||
|
artwork.post(() -> artwork.setImageBitmap(cachedImage));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
System.out.printf("Fetching %s...\n", url);
|
System.out.printf("Fetching %s...\n", url);
|
||||||
HttpURLConnection http = (HttpURLConnection) url.openConnection();
|
HttpURLConnection http = (HttpURLConnection) url.openConnection();
|
||||||
http.setRequestMethod("GET");
|
http.setRequestMethod("GET");
|
||||||
http.setRequestProperty("User-Agent", "aridroid");
|
http.setRequestProperty("User-Agent", "aridroid/" + MainActivity.VERSION);
|
||||||
http.setRequestProperty("Accept", "image/*");
|
http.setRequestProperty("Accept", "image/*");
|
||||||
|
|
||||||
InputStream stream = http.getInputStream();
|
InputStream stream = http.getInputStream();
|
||||||
Bitmap img = BitmapFactory.decodeStream(stream);
|
Bitmap img = BitmapFactory.decodeStream(stream);
|
||||||
// TODO: image caching
|
// store image in memory cache
|
||||||
// https://developer.android.com/topic/performance/graphics/cache-bitmap#java
|
artworkCache.put(url, img);
|
||||||
artwork.post(() -> artwork.setImageBitmap(img));
|
artwork.post(() -> artwork.setImageBitmap(img));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.printf("FATAL: Failed to fetch release artwork: %s\n", e.toString());
|
System.err.printf("FATAL: Failed to fetch release artwork: %s\n", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
thread.start();
|
thread.start();
|
|
@ -4,26 +4,26 @@ import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class MusicItemModel {
|
public class ReleaseModel {
|
||||||
private final String id;
|
private final String id;
|
||||||
private final String title;
|
private final String title;
|
||||||
private final String description;
|
private final String description;
|
||||||
private final String type;
|
private final String type;
|
||||||
private final Date releaseDate;
|
private final Date releaseDate;
|
||||||
private final String artwork;
|
private final String artworkURL;
|
||||||
private final String buyname;
|
private final String buyname;
|
||||||
private final String buylink;
|
private final String buylink;
|
||||||
private final String copyright;
|
private final String copyright;
|
||||||
private final URL copyrightURL;
|
private final URL copyrightURL;
|
||||||
private final ArrayList<MusicCreditModel> credits;
|
private final ArrayList<MusicCreditModel> credits;
|
||||||
|
|
||||||
public MusicItemModel(String id, String title, String description, String type, Date releaseDate, String artwork, String buyname, String buylink, String copyright, URL copyrightURL, ArrayList<MusicCreditModel> credits) {
|
public ReleaseModel(String id, String title, String description, String type, Date releaseDate, String artwork, String buyname, String buylink, String copyright, URL copyrightURL, ArrayList<MusicCreditModel> credits) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.releaseDate = releaseDate;
|
this.releaseDate = releaseDate;
|
||||||
this.artwork = artwork;
|
this.artworkURL = artwork;
|
||||||
this.buyname = buyname;
|
this.buyname = buyname;
|
||||||
this.buylink = buylink;
|
this.buylink = buylink;
|
||||||
this.copyright = copyright;
|
this.copyright = copyright;
|
||||||
|
@ -51,8 +51,8 @@ public class MusicItemModel {
|
||||||
return releaseDate;
|
return releaseDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getArtwork() {
|
public String getArtworkURL() {
|
||||||
return artwork;
|
return artworkURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBuyname() {
|
public String getBuyname() {
|
6
app/src/main/res/color/on_surface_dim.xml
Normal file
6
app/src/main/res/color/on_surface_dim.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:alpha="0.6"
|
||||||
|
android:color="?attr/colorOnSurface" />
|
||||||
|
</selector>
|
7
app/src/main/res/font/inter.xml
Normal file
7
app/src/main/res/font/inter.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
app:fontProviderAuthority="com.google.android.gms.fonts"
|
||||||
|
app:fontProviderPackage="com.google.android.gms"
|
||||||
|
app:fontProviderQuery="Inter"
|
||||||
|
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
||||||
|
</font-family>
|
7
app/src/main/res/font/inter_black.xml
Normal file
7
app/src/main/res/font/inter_black.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
app:fontProviderAuthority="com.google.android.gms.fonts"
|
||||||
|
app:fontProviderPackage="com.google.android.gms"
|
||||||
|
app:fontProviderQuery="name=Inter&weight=900"
|
||||||
|
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
||||||
|
</font-family>
|
7
app/src/main/res/font/inter_bold.xml
Normal file
7
app/src/main/res/font/inter_bold.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
app:fontProviderAuthority="com.google.android.gms.fonts"
|
||||||
|
app:fontProviderPackage="com.google.android.gms"
|
||||||
|
app:fontProviderQuery="name=Inter&weight=700"
|
||||||
|
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
||||||
|
</font-family>
|
11
app/src/main/res/font/monaspace.xml
Normal file
11
app/src/main/res/font/monaspace.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<font
|
||||||
|
android:fontStyle="normal"
|
||||||
|
android:fontWeight="400"
|
||||||
|
android:font="@font/monaspace_regular" />
|
||||||
|
<font
|
||||||
|
android:fontStyle="normal"
|
||||||
|
android:fontWeight="800"
|
||||||
|
android:font="@font/monaspace_bold" />
|
||||||
|
</font-family>
|
BIN
app/src/main/res/font/monaspace_bold.otf
Normal file
BIN
app/src/main/res/font/monaspace_bold.otf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/monaspace_regular.otf
Normal file
BIN
app/src/main/res/font/monaspace_regular.otf
Normal file
Binary file not shown.
|
@ -1,19 +1,60 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/main"
|
android:id="@+id/main"
|
||||||
|
android:theme="@style/AriDroid.Theme"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".MainActivity">
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent">
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/musicListHeader"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:layout_marginVertical="10dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:fontFamily="@font/inter_black"
|
||||||
|
android:text="@string/releases_list_title"
|
||||||
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:textSize="32sp" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/musicList"
|
android:id="@+id/musicList"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
android:layout_marginVertical="5dp"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintTop_toBottomOf="@id/musicListHeader"/>
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent">
|
<TextView
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
android:id="@+id/artistListHeader"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:layout_marginVertical="10dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/musicList"
|
||||||
|
android:textSize="32sp"
|
||||||
|
android:fontFamily="@font/inter_black"
|
||||||
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:text="@string/artists_list_title" />
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/artistList"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/artistListHeader"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
83
app/src/main/res/layout/artist_list_item.xml
Normal file
83
app/src/main/res/layout/artist_list_item.xml
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<?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"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/musicItem"
|
||||||
|
android:theme="@style/AriDroid.Card"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
app:cardBackgroundColor="?attr/colorSurface"
|
||||||
|
app:cardCornerRadius="?attr/cornerRadius">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="10dp">
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/musicArtworkContainer"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:cardCornerRadius="24dp">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/artistAvatar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:contentDescription="@string/music_artwork_description"
|
||||||
|
android:src="@mipmap/ic_launcher"/>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/musicArtworkContainer"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/musicArtworkContainer"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/musicArtworkContainer">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/artistName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
android:fontFamily="@font/inter_bold"
|
||||||
|
android:textSize="16dp"
|
||||||
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:text="@string/default_artist_name" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/artistWebsite"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="0dp"
|
||||||
|
android:paddingVertical="0dp"
|
||||||
|
android:text="@string/artist_website"
|
||||||
|
android:textColor="?attr/colorSurface"
|
||||||
|
android:textColorLink="#77B7CE"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<!-- <TextView-->
|
||||||
|
<!-- android:id="@+id/artistID"-->
|
||||||
|
<!-- android:layout_width="wrap_content"-->
|
||||||
|
<!-- android:layout_height="wrap_content"-->
|
||||||
|
<!-- android:layout_marginStart="5dp"-->
|
||||||
|
<!-- app:layout_constraintRight_toRightOf="parent"-->
|
||||||
|
<!-- app:layout_constraintTop_toTopOf="@id/artistName"-->
|
||||||
|
<!-- android:fontFamily="@font/monaspace"-->
|
||||||
|
<!-- android:textColor="@color/on_surface_dim"-->
|
||||||
|
<!-- android:text="@string/default_artist_id" />-->
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
|
@ -1,72 +1,82 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
android:theme="@style/AriDroid.Card"
|
||||||
android:id="@+id/musicItem"
|
android:id="@+id/musicItem"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dp"
|
android:layout_marginHorizontal="10dp"
|
||||||
app:cardBackgroundColor="@color/material_dynamic_neutral100"
|
android:layout_marginVertical="5dp"
|
||||||
android:padding="10dp">
|
app:cardBackgroundColor="?attr/colorSurface"
|
||||||
|
app:cardCornerRadius="?attr/cornerRadius">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_margin="10dp">
|
android:layout_margin="10dp">
|
||||||
|
|
||||||
<ImageView
|
<androidx.cardview.widget.CardView
|
||||||
android:id="@+id/musicArtwork"
|
android:id="@+id/musicArtworkContainer"
|
||||||
android:layout_width="64dp"
|
android:layout_width="64dp"
|
||||||
android:layout_height="64dp"
|
android:layout_height="64dp"
|
||||||
android:contentDescription="@string/music_artwork_description"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:srcCompat="@tools:sample/avatars" />
|
app:cardCornerRadius="5dp">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/artistAvatar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:contentDescription="@string/music_artwork_description"
|
||||||
|
android:src="@mipmap/default_music_art"/>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/musicArtwork"
|
app:layout_constraintBottom_toBottomOf="@id/musicArtworkContainer"
|
||||||
app:layout_constraintLeft_toRightOf="@id/musicArtwork"
|
app:layout_constraintLeft_toRightOf="@id/musicArtworkContainer"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@id/musicArtwork">
|
app:layout_constraintTop_toTopOf="@id/musicArtworkContainer">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/musicTitle"
|
android:id="@+id/musicTitle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/default_release_title"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:fontFamily="@font/inter_bold"
|
||||||
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:text="@string/default_release_title" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/musicYear"
|
android:id="@+id/musicYear"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="5dp"
|
android:layout_marginStart="5dp"
|
||||||
android:alpha=".6"
|
|
||||||
android:text="@string/default_year"
|
|
||||||
android:textStyle="bold|italic"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/musicTitle"
|
app:layout_constraintLeft_toRightOf="@id/musicTitle"
|
||||||
app:layout_constraintTop_toTopOf="@id/musicTitle" />
|
app:layout_constraintTop_toTopOf="@id/musicTitle"
|
||||||
|
android:fontFamily="@font/inter_bold"
|
||||||
|
android:textColor="@color/on_surface_dim"
|
||||||
|
android:text="@string/default_year" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/musicArtist"
|
android:id="@+id/musicArtist"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/default_artist"
|
|
||||||
app:layout_constraintLeft_toLeftOf="@id/musicTitle"
|
app:layout_constraintLeft_toLeftOf="@id/musicTitle"
|
||||||
app:layout_constraintTop_toBottomOf="@id/musicTitle" />
|
app:layout_constraintTop_toBottomOf="@id/musicTitle"
|
||||||
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:text="@string/default_artist" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/musicType"
|
android:id="@+id/musicType"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/default_release_type"
|
|
||||||
app:layout_constraintLeft_toLeftOf="@id/musicArtist"
|
app:layout_constraintLeft_toLeftOf="@id/musicArtist"
|
||||||
app:layout_constraintTop_toBottomOf="@id/musicArtist" />
|
app:layout_constraintTop_toBottomOf="@id/musicArtist"
|
||||||
|
android:textColor="@color/on_surface_dim"
|
||||||
|
android:text="@string/default_release_type" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
BIN
app/src/main/res/mipmap-hdpi/default_music_art.png
Normal file
BIN
app/src/main/res/mipmap-hdpi/default_music_art.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 139 KiB |
|
@ -1,7 +1,14 @@
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources>
|
||||||
<!-- Base application theme. -->
|
<style name="AriDroid.Theme" parent="AriDroid.Base">
|
||||||
<style name="Base.Theme.AriDroid" parent="Theme.Material3.DayNight.NoActionBar">
|
<item name="colorPrimary">@color/brand_green</item>
|
||||||
<!-- Customize your dark theme here. -->
|
<item name="colorSecondary">@color/brand_pink</item>
|
||||||
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
|
<item name="colorSurface">@color/dark100</item>
|
||||||
|
<item name="colorOnSurface">@color/white90</item>
|
||||||
|
<item name="android:fontFamily">@font/inter</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AriDroid.Card" parent="AriDroid.Theme">
|
||||||
|
<item name="colorSurface">@color/dark90</item>
|
||||||
|
<item name="colorOnSurface">@color/white100</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="black">#FF000000</color>
|
|
||||||
<color name="white">#FFFFFFFF</color>
|
|
||||||
</resources>
|
|
19
app/src/main/res/values/colours.xml
Normal file
19
app/src/main/res/values/colours.xml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="brand_green">#FFB7FD49</color>
|
||||||
|
<color name="brand_green_dark">#FF465E1F</color>
|
||||||
|
<color name="brand_yellow">#FFF8E05B</color>
|
||||||
|
<color name="brand_yellow_dark">#FFC6A80F</color>
|
||||||
|
<color name="brand_pink">#FFF788FE</color>
|
||||||
|
<color name="brand_pink_dark">#FFDC62E5</color>
|
||||||
|
|
||||||
|
<color name="dark100">#FF000000</color>
|
||||||
|
<color name="dark90">#FF101010</color>
|
||||||
|
<color name="dark80">#FF202020</color>
|
||||||
|
<color name="dark50">#FF404040</color>
|
||||||
|
|
||||||
|
<color name="white100">#FFFFFFFF</color>
|
||||||
|
<color name="white90">#FFF0F0F0</color>
|
||||||
|
<color name="white80">#FFD0D0D0</color>
|
||||||
|
<color name="white50">#FFB0B0B0</color>
|
||||||
|
</resources>
|
17
app/src/main/res/values/font_certs.xml
Normal file
17
app/src/main/res/values/font_certs.xml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<array name="com_google_android_gms_fonts_certs">
|
||||||
|
<item>@array/com_google_android_gms_fonts_certs_dev</item>
|
||||||
|
<item>@array/com_google_android_gms_fonts_certs_prod</item>
|
||||||
|
</array>
|
||||||
|
<string-array name="com_google_android_gms_fonts_certs_dev">
|
||||||
|
<item>
|
||||||
|
MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
|
||||||
|
</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="com_google_android_gms_fonts_certs_prod">
|
||||||
|
<item>
|
||||||
|
MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
|
||||||
|
</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
8
app/src/main/res/values/preloaded_fonts.xml
Normal file
8
app/src/main/res/values/preloaded_fonts.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<array name="preloaded_fonts" translatable="false">
|
||||||
|
<item>@font/inter</item>
|
||||||
|
<item>@font/inter_black</item>
|
||||||
|
<item>@font/inter_bold</item>
|
||||||
|
</array>
|
||||||
|
</resources>
|
|
@ -2,6 +2,7 @@
|
||||||
<string name="base_url">https://arimelody.me</string>
|
<string name="base_url">https://arimelody.me</string>
|
||||||
<string name="app_name">AriDroid</string>
|
<string name="app_name">AriDroid</string>
|
||||||
|
|
||||||
|
<string name="releases_list_title">Releases</string>
|
||||||
<string name="music_artwork_description">%s artwork</string>
|
<string name="music_artwork_description">%s artwork</string>
|
||||||
<string name="default_release_title">Untitled Release</string>
|
<string name="default_release_title">Untitled Release</string>
|
||||||
<string name="default_track_title">Untitled Track</string>
|
<string name="default_track_title">Untitled Track</string>
|
||||||
|
@ -9,7 +10,6 @@
|
||||||
<string name="default_year">2002</string>
|
<string name="default_year">2002</string>
|
||||||
<string name="default_release_type">Release</string>
|
<string name="default_release_type">Release</string>
|
||||||
<string name="default_release_track_count">0 tracks</string>
|
<string name="default_release_track_count">0 tracks</string>
|
||||||
|
|
||||||
<string name="release_type_unknown">Unknown</string>
|
<string name="release_type_unknown">Unknown</string>
|
||||||
<string name="release_type_single">Single</string>
|
<string name="release_type_single">Single</string>
|
||||||
<string name="release_type_album">Album</string>
|
<string name="release_type_album">Album</string>
|
||||||
|
@ -17,9 +17,13 @@
|
||||||
<string name="release_type_lp">LP</string>
|
<string name="release_type_lp">LP</string>
|
||||||
<string name="release_type_compilation">Compilation</string>
|
<string name="release_type_compilation">Compilation</string>
|
||||||
<string name="release_type_upcoming">Upcoming</string>
|
<string name="release_type_upcoming">Upcoming</string>
|
||||||
|
|
||||||
<plurals name="release_track_count">
|
<plurals name="release_track_count">
|
||||||
<item quantity="one">(%d track)</item>
|
<item quantity="one">(%d track)</item>
|
||||||
<item quantity="other">(%d tracks)</item>
|
<item quantity="other">(%d tracks)</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
|
<string name="artists_list_title">Artists</string>
|
||||||
|
<string name="default_artist_name">Unknown Artist</string>
|
||||||
|
<string name="default_artist_id">artist001</string>
|
||||||
|
<string name="artist_website">Website</string>
|
||||||
</resources>
|
</resources>
|
|
@ -1,9 +1,19 @@
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources>
|
||||||
<!-- Base application theme. -->
|
<style name="AriDroid.Base" parent="Theme.Material3.DayNight.NoActionBar">
|
||||||
<style name="Base.Theme.AriDroid" parent="Theme.Material3.DayNight.NoActionBar">
|
<item name="android:fontFamily">@font/inter</item>
|
||||||
<!-- Customize your light theme here. -->
|
|
||||||
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.AriDroid" parent="Base.Theme.AriDroid" />
|
<style name="AriDroid.Theme" parent="AriDroid.Base">
|
||||||
|
<item name="colorPrimary">@color/brand_green_dark</item>
|
||||||
|
<item name="colorSecondary">@color/brand_pink_dark</item>
|
||||||
|
<item name="colorSurface">@color/white90</item>
|
||||||
|
<item name="colorOnSurfaceVariant">@color/white50</item>
|
||||||
|
<item name="colorOnSurface">@color/dark90</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AriDroid.Card" parent="AriDroid.Theme">
|
||||||
|
<item name="colorSurface">@color/white100</item>
|
||||||
|
<item name="colorOnSurface">@color/dark90</item>
|
||||||
|
<item name="cornerRadius">10dp</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue