Files
podlite/src/com/miniabs/BaseActivity.java
T
xockoandClaude Opus 5.5 275bee3c11 MiniABS 1.2: Galician interface, larger text and touch targets
- Translate the interface to Galician (tools/translate_gl.py), including
  Galician month abbreviations for dates, which Android 2.3 lacks
- Resize for the Galaxy Mini's 240x320 screen: larger text, rows, tabs and
  buttons; all sizes now live in res/values/dimens.xml
- Redraw play/pause/refresh icons for every density; slightly brighter
  secondary text colours

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 21:29:17 +02:00

249 lines
9.8 KiB
Java

package com.miniabs;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
/** Shared bits: the mini player bar, a 1-second UI tick, sign-in errors and episode actions. */
abstract class BaseActivity extends Activity {
protected final Handler handler = new Handler();
private boolean ticking;
private View mini;
private TextView miniTitle, miniSub;
private ImageButton miniPlay;
private ProgressBar miniProgress;
private final Runnable ticker = new Runnable() {
public void run() {
onTick();
if (ticking) handler.postDelayed(this, 1000);
}
};
@Override
protected void onResume() {
super.onResume();
ticking = true;
handler.post(ticker);
}
@Override
protected void onPause() {
ticking = false;
handler.removeCallbacks(ticker);
super.onPause();
}
protected void onTick() {
updateMiniBar();
}
protected void toast(String s) {
Toast.makeText(this, s, s.length() > 60 ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT).show();
}
/** Shows an error; sends the user to the login screen if their sign-in expired. */
protected void showError(Exception e) {
if (e instanceof Api.AuthException) {
Prefs.get(this).logout();
App.clear();
HomeActivity.clearCache();
startActivity(new Intent(this, LoginActivity.class)
.putExtra("message", e.getMessage())
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
finish();
return;
}
if (offerTrust(null)) return;
toast(Util.describe(e));
}
/** If a request just failed on an unrecognised certificate, ask about it. retry runs after trusting. */
protected boolean offerTrust(final Runnable retry) {
return TrustPrompt.offer(this, new Runnable() {
public void run() {
if (retry != null) retry.run();
else toast("Certificado aceptado. Téntao de novo.");
}
});
}
// ------------------------------------------------------------ mini player
protected void setupMiniBar() {
mini = findViewById(R.id.mini_bar);
if (mini == null) return;
miniTitle = (TextView) findViewById(R.id.mini_title);
miniSub = (TextView) findViewById(R.id.mini_sub);
miniPlay = (ImageButton) findViewById(R.id.mini_play);
miniProgress = (ProgressBar) findViewById(R.id.mini_progress);
findViewById(R.id.mini_info).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startActivity(new Intent(BaseActivity.this, PlayerActivity.class));
}
});
miniPlay.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
PlayerService ps = PlayerService.get();
if (ps != null && ps.episode() != null) {
PlayerService.send(BaseActivity.this, PlayerService.A_TOGGLE);
} else {
Episode last = Prefs.get(BaseActivity.this).lastEpisode();
if (last != null) PlayerService.play(BaseActivity.this, last);
}
handler.postDelayed(new Runnable() {
public void run() {
updateMiniBar();
}
}, 300);
}
});
}
protected void updateMiniBar() {
if (mini == null) return;
PlayerService ps = PlayerService.get();
Episode e = ps != null ? ps.episode() : null;
if (e == null) e = Prefs.get(this).lastEpisode();
if (e == null) {
mini.setVisibility(View.GONE);
return;
}
mini.setVisibility(View.VISIBLE);
miniTitle.setText(e.title);
boolean playing = ps != null && ps.episode() != null && ps.isPlaying();
miniPlay.setImageResource(playing ? R.drawable.ic_pause_small : R.drawable.ic_play_small);
int pos, dur;
String sub;
if (ps != null && ps.episode() != null) {
pos = ps.positionMs();
dur = ps.durationMs();
int st = ps.state();
if (st == PlayerService.LOADING || st == PlayerService.ERROR) sub = ps.status();
else sub = Util.join(e.show, dur > 0 ? "quedan " + Util.clock(dur - pos) : "");
} else {
double[] p = App.progress(e.id);
double cur = p != null ? p[0] : Math.max(0, App.localPosition(this, e.id));
pos = (int) (cur * 1000);
dur = (int) (e.duration * 1000);
sub = Util.join(e.show, "En pausa");
}
miniSub.setText(sub);
miniProgress.setProgress(dur > 0 ? (int) (1000L * pos / dur) : 0);
}
// ------------------------------------------------------------ episode actions
protected static final int M_PLAY = 1, M_DOWNLOAD = 2, M_DELETE = 3, M_PLAYED = 4, M_UNPLAYED = 5,
M_SHOW = 6, M_CANCEL = 7;
protected void episodeMenu(ContextMenu menu, Episode e, boolean offerShow) {
menu.setHeaderTitle(e.title);
menu.add(0, M_PLAY, 0, "Reproducir");
if (DownloadService.busyWith(e.id)) menu.add(0, M_CANCEL, 0, "Cancelar descarga");
else if (Downloads.has(this, e.id)) menu.add(0, M_DELETE, 0, "Eliminar descarga");
else menu.add(0, M_DOWNLOAD, 0, "Descargar");
double[] p = App.progress(e.id);
if (p != null && p[2] > 0) menu.add(0, M_UNPLAYED, 0, "Marcar como non escoitado");
else menu.add(0, M_PLAYED, 0, "Marcar como escoitado");
if (offerShow) menu.add(0, M_SHOW, 0, "Ir ao programa");
}
/** Returns true if handled. onChanged runs on the UI thread after the list should refresh. */
protected boolean episodeAction(int id, final Episode e, final Runnable onChanged) {
switch (id) {
case M_PLAY:
playEpisode(e);
return true;
case M_DOWNLOAD:
if (Prefs.get(this).wifiOnly() && !Util.onWifi(this)) {
new AlertDialog.Builder(this)
.setMessage("Non estás nunha wifi. Descargar con datos móbiles esta vez?")
.setPositiveButton("Descargar", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int w) {
Prefs.get(BaseActivity.this).sp.edit().putBoolean("wifi_only", false).commit();
DownloadService.enqueue(BaseActivity.this, e);
toast("Descargando. Desactivouse «só con wifi» (podes cambialo en Axustes).");
if (onChanged != null) onChanged.run();
}
})
.setNegativeButton("Cancelar", null)
.show();
} else {
DownloadService.enqueue(this, e);
toast("Descargando…");
}
if (onChanged != null) onChanged.run();
return true;
case M_CANCEL:
DownloadService.cancel(e.id);
toast("Descarga cancelada");
if (onChanged != null) onChanged.run();
return true;
case M_DELETE:
PlayerService ps = PlayerService.get();
if (ps != null && ps.episode() != null && ps.episode().id.equals(e.id) && ps.isLocal()) {
ps.stop();
}
Downloads.delete(this, e);
toast("Descarga eliminada");
if (onChanged != null) onChanged.run();
return true;
case M_PLAYED:
case M_UNPLAYED:
setPlayed(e, id == M_PLAYED, onChanged);
return true;
case M_SHOW:
startActivity(new Intent(this, PodcastActivity.class)
.putExtra("itemId", e.itemId).putExtra("title", e.show));
return true;
default:
return false;
}
}
protected void playEpisode(Episode e) {
PlayerService.play(this, e);
startActivity(new Intent(this, PlayerActivity.class).putExtra("ep", e.toJson().toString()));
}
private void setPlayed(final Episode e, final boolean played, final Runnable onChanged) {
final double dur = e.duration;
final double[] before = App.progress(e.id);
App.setProgress(e.id, played ? dur : 0, dur, played);
if (onChanged != null) onChanged.run();
new Job<Void>() {
Void work() throws Exception {
Api.setProgress(BaseActivity.this, e.itemId, e.id, played ? dur : 0, dur, Boolean.valueOf(played));
App.forgetLocal(BaseActivity.this, e.id);
return null;
}
void done(Void r) {
toast(played ? "Marcado como escoitado" : "Marcado como non escoitado");
}
void failed(Exception ex) {
if (before != null) App.setProgress(e.id, before[0], before[1], before[2] > 0);
else App.setProgress(e.id, 0, dur, false);
if (onChanged != null) onChanged.run();
showError(ex);
}
}.start();
}
protected boolean onEpisodeContextItem(MenuItem item, Episode e, Runnable onChanged) {
return e != null && episodeAction(item.getItemId(), e, onChanged);
}
}