Private
Public Access
- Interface in Galician by default regardless of the phone's language, with English selectable under Axustes -> Idioma; switching rebuilds the screens - All text in tools/strings.py (key -> English, Galician), generating res/values/strings.xml (gl) and res/values-en/strings.xml; layouts now use string resources - util/Tr.java: translations for the network and Plex layers, which can't read Android resources (falls back to English in desktop tests) - net/RefusedException: distinguish "server answered but refused" from connection failures - The connection log stays in English for troubleshooting Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
231 lines
10 KiB
Java
231 lines
10 KiB
Java
package com.minamp;
|
|
|
|
import android.app.AlertDialog;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.drawable.GradientDrawable;
|
|
import android.os.Bundle;
|
|
import android.view.View;
|
|
import android.widget.ImageButton;
|
|
import android.widget.ImageView;
|
|
import android.widget.SeekBar;
|
|
import android.widget.TextView;
|
|
|
|
import com.minamp.plex.Item;
|
|
|
|
public class NowPlayingActivity extends BaseActivity {
|
|
|
|
private ImageView art;
|
|
private TextView title, sub, from, elapsed, remaining, status, sleepText, albumLink;
|
|
private SeekBar seek;
|
|
private ImageButton playBtn, shuffleBtn, repeatBtn, loveBtn;
|
|
private Glyph playGlyph, shuffleGlyph, repeatGlyph, loveGlyph;
|
|
private View root;
|
|
private boolean dragging;
|
|
private String shownThumb;
|
|
private int white, dim, accent;
|
|
|
|
@Override
|
|
protected void onCreate(Bundle b) {
|
|
super.onCreate(b);
|
|
setContentView(R.layout.activity_now_playing);
|
|
white = getResources().getColor(R.color.text);
|
|
dim = 0x99FFFFFF;
|
|
accent = getResources().getColor(R.color.accent);
|
|
|
|
root = findViewById(R.id.np_root);
|
|
art = (ImageView) findViewById(R.id.np_art);
|
|
title = (TextView) findViewById(R.id.np_title);
|
|
sub = (TextView) findViewById(R.id.np_sub);
|
|
from = (TextView) findViewById(R.id.np_from);
|
|
elapsed = (TextView) findViewById(R.id.np_elapsed);
|
|
remaining = (TextView) findViewById(R.id.np_remaining);
|
|
status = (TextView) findViewById(R.id.np_status);
|
|
sleepText = (TextView) findViewById(R.id.np_sleep_text);
|
|
albumLink = (TextView) findViewById(R.id.np_artist_link);
|
|
seek = (SeekBar) findViewById(R.id.np_seek);
|
|
playBtn = (ImageButton) findViewById(R.id.np_play);
|
|
shuffleBtn = (ImageButton) findViewById(R.id.np_shuffle);
|
|
repeatBtn = (ImageButton) findViewById(R.id.np_repeat);
|
|
loveBtn = (ImageButton) findViewById(R.id.np_love);
|
|
|
|
ImageButton down = (ImageButton) findViewById(R.id.np_down);
|
|
Ui.icon(down, Glyph.BACK, white);
|
|
down.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { finish(); } });
|
|
ImageButton queue = (ImageButton) findViewById(R.id.np_queue);
|
|
Ui.icon(queue, Glyph.QUEUE, white);
|
|
queue.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) { startActivity(new Intent(NowPlayingActivity.this, QueueActivity.class)); }
|
|
});
|
|
|
|
playGlyph = Ui.glyph(this, Glyph.PLAY, getResources().getColor(R.color.on_accent), 24);
|
|
playGlyph.scale(1f);
|
|
playBtn.setImageDrawable(playGlyph);
|
|
playBtn.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) { PlayerService.send(NowPlayingActivity.this, PlayerService.ACTION_TOGGLE); }
|
|
});
|
|
ImageButton prev = (ImageButton) findViewById(R.id.np_prev);
|
|
ImageButton next = (ImageButton) findViewById(R.id.np_next);
|
|
Ui.icon(prev, Glyph.PREV, white, 22);
|
|
Ui.icon(next, Glyph.NEXT, white, 22);
|
|
prev.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) { PlayerService.send(NowPlayingActivity.this, PlayerService.ACTION_PREV); }
|
|
});
|
|
next.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) { PlayerService.send(NowPlayingActivity.this, PlayerService.ACTION_NEXT); }
|
|
});
|
|
|
|
shuffleGlyph = Ui.glyph(this, Glyph.SHUFFLE, dim, 20); shuffleGlyph.scale(1f);
|
|
shuffleBtn.setImageDrawable(shuffleGlyph);
|
|
shuffleBtn.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) { PlayQueue.get().setShuffle(!PlayQueue.get().shuffle()); }
|
|
});
|
|
repeatGlyph = Ui.glyph(this, Glyph.REPEAT, dim, 20); repeatGlyph.scale(1f);
|
|
repeatBtn.setImageDrawable(repeatGlyph);
|
|
repeatBtn.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) {
|
|
PlayQueue.get().cycleRepeat();
|
|
int r = PlayQueue.get().repeat();
|
|
toast(str(r == PlayQueue.REPEAT_ALL ? R.string.repeat_queue : r == PlayQueue.REPEAT_ONE ? R.string.repeat_track : R.string.repeat_off));
|
|
}
|
|
});
|
|
loveGlyph = Ui.glyph(this, Glyph.HEART_OUTLINE, white, 20); loveGlyph.scale(1f);
|
|
loveBtn.setImageDrawable(loveGlyph);
|
|
loveBtn.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) {
|
|
Item it = PlayQueue.get().current();
|
|
if (it != null) toggleLove(it, new Runnable() { public void run() { update(); } });
|
|
}
|
|
});
|
|
|
|
Ui.icon((ImageView) findViewById(R.id.np_sleep_icon), Glyph.MOON, 0xB3FFFFFF, 16);
|
|
findViewById(R.id.np_sleep).setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) { sleepDialog(); }
|
|
});
|
|
albumLink.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) {
|
|
Item it = PlayQueue.get().current();
|
|
if (it != null && it.albumKey.length() > 0) openKey(it.albumKey, Item.ALBUM, it.album);
|
|
}
|
|
});
|
|
art.setOnLongClickListener(new View.OnLongClickListener() {
|
|
public boolean onLongClick(View v) {
|
|
Item it = PlayQueue.get().current();
|
|
if (it != null) itemMenu(it);
|
|
return true;
|
|
}
|
|
});
|
|
|
|
seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
|
public void onProgressChanged(SeekBar s, int p, boolean user) {
|
|
if (user) {
|
|
long d = PlayerService.duration();
|
|
elapsed.setText(Ui.time(d * p / 1000));
|
|
}
|
|
}
|
|
public void onStartTrackingTouch(SeekBar s) { dragging = true; }
|
|
public void onStopTrackingTouch(SeekBar s) {
|
|
dragging = false;
|
|
long d = PlayerService.duration();
|
|
if (d > 0) PlayerService.seekTo(NowPlayingActivity.this, d * s.getProgress() / 1000);
|
|
}
|
|
});
|
|
setBackdrop(0xFF1D1D22);
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
super.onResume();
|
|
update();
|
|
}
|
|
|
|
@Override
|
|
public void onPlayerChanged() { super.onPlayerChanged(); update(); }
|
|
|
|
@Override
|
|
public void onQueueChanged() { super.onQueueChanged(); update(); }
|
|
|
|
@Override
|
|
protected void onTick() { super.onTick(); updateTime(); }
|
|
|
|
private void update() {
|
|
Item it = PlayQueue.get().current();
|
|
PlayQueue q = PlayQueue.get();
|
|
if (it == null) {
|
|
title.setText(R.string.nothing_playing);
|
|
sub.setText(R.string.pick_something);
|
|
from.setText("");
|
|
art.setImageResource(R.drawable.art_placeholder);
|
|
shownThumb = null;
|
|
return;
|
|
}
|
|
title.setText(it.title);
|
|
sub.setText(it.artist + (it.album.length() > 0 ? " — " + it.album : ""));
|
|
from.setText(q.title().length() > 0 ? q.title() : it.album);
|
|
playGlyph.setType(PlayerService.isPlaying() ? Glyph.PAUSE : Glyph.PLAY);
|
|
shuffleGlyph.setColor(q.shuffle() ? accent : dim);
|
|
repeatGlyph.setType(q.repeat() == PlayQueue.REPEAT_ONE ? Glyph.REPEAT_ONE : Glyph.REPEAT);
|
|
repeatGlyph.setColor(q.repeat() != PlayQueue.REPEAT_OFF ? accent : dim);
|
|
loveGlyph.setType(it.loved() ? Glyph.HEART : Glyph.HEART_OUTLINE);
|
|
loveGlyph.setColor(it.loved() ? accent : white);
|
|
albumLink.setVisibility(it.albumKey.length() > 0 ? View.VISIBLE : View.INVISIBLE);
|
|
albumLink.setText(R.string.album_link);
|
|
|
|
if (!it.thumb.equals(shownThumb)) {
|
|
shownThumb = it.thumb;
|
|
final String want = it.thumb;
|
|
int size = Math.min(getResources().getDisplayMetrics().widthPixels, 480);
|
|
art.setImageResource(R.drawable.art_placeholder);
|
|
app.images.load(it.thumb, size, new ImageLoader.Callback() {
|
|
public void onBitmap(Bitmap bm) {
|
|
if (destroyed || !want.equals(shownThumb)) return;
|
|
if (bm != null) { art.setImageBitmap(bm); setBackdrop(Ui.backdropColor(bm)); }
|
|
}
|
|
});
|
|
}
|
|
updateSleep();
|
|
updateTime();
|
|
}
|
|
|
|
private void updateTime() {
|
|
long d = PlayerService.duration();
|
|
long p = PlayerService.position();
|
|
if (!dragging) {
|
|
seek.setProgress(d > 0 ? (int) (p * 1000 / d) : 0);
|
|
elapsed.setText(Ui.time(p));
|
|
}
|
|
remaining.setText("-" + Ui.time(Math.max(0, d - p)));
|
|
String st = PlayerService.status();
|
|
status.setText(st.length() > 0 ? st : PlayerService.sourceLabel());
|
|
if (PlayerService.sleepAt() > 0) updateSleep();
|
|
}
|
|
|
|
private void updateSleep() {
|
|
long at = PlayerService.sleepAt();
|
|
if (PlayerService.sleepEndOfTrack()) sleepText.setText(R.string.end_of_track);
|
|
else if (at > 0) sleepText.setText(Ui.time(at - System.currentTimeMillis()));
|
|
else sleepText.setText(R.string.sleep);
|
|
}
|
|
|
|
private void setBackdrop(int color) {
|
|
GradientDrawable g = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,
|
|
new int[] { color, getResources().getColor(R.color.bg) });
|
|
root.setBackgroundDrawable(g);
|
|
}
|
|
|
|
private void sleepDialog() {
|
|
final int[] mins = {0, 15, 30, 45, 60, 90, -1};
|
|
String[] labels = {str(R.string.sleep_off), str(R.string.sleep_15), str(R.string.sleep_30), str(R.string.sleep_45),
|
|
str(R.string.sleep_60), str(R.string.sleep_90), str(R.string.sleep_eot)};
|
|
new AlertDialog.Builder(this).setTitle(R.string.sleep_timer)
|
|
.setItems(labels, new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface d, int which) {
|
|
startService(new Intent(NowPlayingActivity.this, PlayerService.class)
|
|
.setAction(PlayerService.ACTION_SLEEP).putExtra(PlayerService.EXTRA_MINUTES, mins[which]));
|
|
app.handler.postDelayed(new Runnable() { public void run() { if (!destroyed) updateSleep(); } }, 300);
|
|
}
|
|
}).show();
|
|
}
|
|
}
|