2 Commits
Author SHA1 Message Date
xockoandClaude Opus 5.5 2c23ec9131 MiniABS 1.5: Audiobookshelf icon and purple theme
- Launcher icon from the Audiobookshelf icon pack (art/icon_master_512.png),
  including an xhdpi size
- Notification icon cut out of the same artwork; player icons redrawn in the
  icon's lilac (tools/make_icons.py)
- Purple colour scheme taken from the icon: gradient accent buttons, lilac
  text accents (accent_light), purple-tinted backgrounds
- README: where the icon and colours come from

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 10:07:49 +02:00
xockoandClaude Opus 5.5 0fea07f1b2 MiniABS 1.4: smaller player controls
- Play/pause becomes a rounded rectangle (58x46dp) instead of a 78dp circle,
  with 32dp icons and wider spacing (play_w/play_h/play_gap in dimens.xml)
- Skip buttons shrink from 82x56dp to 62x42dp, with 16sp text
- Version 1.4 (versionCode 5); there was no public 1.3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 08:02:53 +02:00
37 changed files with 80 additions and 73 deletions

No files matched your search

+2 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.miniabs"
android:versionCode="3"
android:versionName="1.2"
android:versionCode="6"
android:versionName="1.5"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10" />
+1 -1
View File
@@ -1,6 +1,6 @@
# MiniABS
A tiny Audiobookshelf **podcast** client for the Samsung Galaxy Mini (GT-S5570) and other Android 2.2+ phones. Native Java, no libraries, ~130 KB. The interface is in Galician, with large text and touch targets sized for the Mini's 240×320 screen.
A tiny Audiobookshelf **podcast** client for the Samsung Galaxy Mini (GT-S5570) and other Android 2.2+ phones. Native Java, no libraries, ~130 KB. The interface is in Galician, with large text and touch targets sized for the Mini's 240×320 screen. Its purple colour scheme and launcher icon come from the Audiobookshelf icon pack (`art/icon_master_512.png`); `tools/make_icons.py` derives the notification and player icons from it.
## Install
Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 B

After

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 B

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 690 B

After

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 365 B

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 413 B

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 B

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 B

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 760 B

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 834 B

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+2 -2
View File
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape><solid android:color="#FFC766" /><corners android:radius="6dp" /></shape>
<shape><gradient android:startColor="#AA5CFF" android:endColor="#7022E6" android:angle="270" /><corners android:radius="6dp" /></shape>
</item>
<item android:state_enabled="false">
<shape><solid android:color="@color/dim" /><corners android:radius="6dp" /></shape>
</item>
<item>
<shape><solid android:color="@color/accent" /><corners android:radius="6dp" /></shape>
<shape><gradient android:startColor="@color/accent_top" android:endColor="@color/accent_bottom" android:angle="270" /><corners android:radius="6dp" /></shape>
</item>
</selector>
+1 -1
View File
@@ -4,7 +4,7 @@
<shape>
<solid android:color="@color/pressed" />
<corners android:radius="6dp" />
<stroke android:width="1dp" android:color="@color/accent" />
<stroke android:width="1dp" android:color="@color/accent_light" />
</shape>
</item>
<item android:state_enabled="false">
+2 -2
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="oval"><solid android:color="#FFC766" /></shape>
<shape><gradient android:startColor="#AA5CFF" android:endColor="#7022E6" android:angle="270" /><corners android:radius="23dp" /></shape>
</item>
<item>
<shape android:shape="oval"><solid android:color="@color/accent" /></shape>
<shape><gradient android:startColor="@color/accent_top" android:endColor="@color/accent_bottom" android:angle="270" /><corners android:radius="23dp" /></shape>
</item>
</selector>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="@color/accent" />
<solid android:color="@color/accent_light" />
<stroke android:width="2dp" android:color="@color/bg" />
<size android:width="@dimen/seek_thumb" android:height="@dimen/seek_thumb" />
</shape>
+1 -1
View File
@@ -12,7 +12,7 @@
android:text="MiniABS"
android:textSize="@dimen/header_text"
android:textStyle="bold"
android:textColor="@color/accent" />
android:textColor="@color/accent_light" />
<TextView
android:id="@+id/library"
+3 -3
View File
@@ -34,7 +34,7 @@
android:text="MiniABS"
android:textSize="@dimen/login_title"
android:textStyle="bold"
android:textColor="@color/accent" />
android:textColor="@color/accent_light" />
<TextView
android:layout_width="wrap_content"
@@ -82,7 +82,7 @@
android:text="Conectar"
android:textStyle="bold"
android:textSize="@dimen/login_btn_text"
android:textColor="#121519" />
android:textColor="#FFFFFF" />
<TextView
android:id="@+id/status"
@@ -90,7 +90,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textSize="@dimen/login_status"
android:textColor="@color/accent" />
android:textColor="@color/accent_light" />
<TextView
android:layout_width="fill_parent"
+5 -5
View File
@@ -14,7 +14,7 @@
android:paddingRight="10dp"
android:textSize="@dimen/header_sub"
android:textStyle="bold"
android:textColor="@color/accent"
android:textColor="@color/accent_light"
android:singleLine="true"
android:ellipsize="end"
android:background="@drawable/row_sel" />
@@ -129,10 +129,10 @@
<ImageButton
android:id="@+id/play"
android:layout_width="@dimen/play_size"
android:layout_height="@dimen/play_size"
android:layout_marginLeft="14dp"
android:layout_marginRight="14dp"
android:layout_width="@dimen/play_w"
android:layout_height="@dimen/play_h"
android:layout_marginLeft="@dimen/play_gap"
android:layout_marginRight="@dimen/play_gap"
android:background="@drawable/btn_round"
android:src="@drawable/ic_play" />
+1 -1
View File
@@ -27,7 +27,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/text_show"
android:textColor="@color/accent"
android:textColor="@color/accent_light"
android:singleLine="true"
android:ellipsize="end" />
+1 -1
View File
@@ -6,4 +6,4 @@
android:gravity="center"
android:textSize="@dimen/text_more"
android:textStyle="bold"
android:textColor="@color/accent" />
android:textColor="@color/accent_light" />
+6 -4
View File
@@ -41,10 +41,12 @@
<dimen name="player_meta">13sp</dimen>
<dimen name="player_time">15sp</dimen>
<dimen name="player_desc">15sp</dimen>
<dimen name="skip_w">82dp</dimen>
<dimen name="skip_h">56dp</dimen>
<dimen name="skip_text">20sp</dimen>
<dimen name="play_size">78dp</dimen>
<dimen name="skip_w">62dp</dimen>
<dimen name="skip_h">42dp</dimen>
<dimen name="skip_text">16sp</dimen>
<dimen name="play_w">58dp</dimen>
<dimen name="play_h">46dp</dimen>
<dimen name="play_gap">28dp</dimen>
<dimen name="seek_thumb">26dp</dimen>
<dimen name="seek_track">7dp</dimen>
+13 -9
View File
@@ -2,16 +2,20 @@
<resources>
<string name="app_name">MiniABS</string>
<color name="bg">#121519</color>
<color name="surface">#1C2127</color>
<color name="header">#0B0D10</color>
<color name="line">#2A3038</color>
<color name="text">#ECEFF2</color>
<color name="sub">#A9B2BC</color>
<color name="dim">#6E7882</color>
<color name="accent">#F5A623</color>
<!-- Colours taken from the Audiobookshelf icon: gradient #9437FC to #570DCF, waves #BC8AFC -->
<color name="bg">#13111A</color>
<color name="surface">#1D1928</color>
<color name="header">#0C0A12</color>
<color name="line">#2C2638</color>
<color name="text">#EEEBF3</color>
<color name="sub">#ADA6BC</color>
<color name="dim">#736C82</color>
<color name="accent">#7A25EC</color> <!-- fills: tabs, progress, seek bar -->
<color name="accent_light">#BC8AFC</color> <!-- text and small marks on dark backgrounds -->
<color name="accent_top">#9437FC</color> <!-- button gradient, as in the icon -->
<color name="accent_bottom">#5A11D3</color>
<color name="fresh">#6EC1E4</color>
<color name="pressed">#2C333C</color>
<color name="pressed">#2E2642</color>
<style name="MiniTheme" parent="@android:style/Theme.NoTitleBar">
<item name="android:windowBackground">@color/bg</item>
+1 -1
View File
@@ -50,7 +50,7 @@
<PreferenceCategory android:title="Acerca de">
<Preference
android:key="about"
android:title="MiniABS 1.2"
android:title="MiniABS 1.5"
android:summary="Un pequeno cliente de podcasts de Audiobookshelf para Android 2.2+" />
</PreferenceCategory>
</PreferenceScreen>
+1 -1
View File
@@ -26,7 +26,7 @@ import android.os.Build;
/** Audiobookshelf REST client (API as of server 2.x, including the 2.26+ token system). */
final class Api {
static final String VERSION = "1.2";
static final String VERSION = "1.5";
static class ApiException extends IOException {
final int code;
+1 -1
View File
@@ -201,7 +201,7 @@ final class Rows extends BaseAdapter {
} else {
bar.setVisibility(View.GONE);
}
int color = act.getResources().getColor(finished ? R.color.line : started ? R.color.accent : R.color.fresh);
int color = act.getResources().getColor(finished ? R.color.line : started ? R.color.accent_light : R.color.fresh);
dotView.setBackgroundDrawable(dot(color));
}
}
+38 -37
View File
@@ -1,6 +1,11 @@
"""Draws MiniABS's PNG icons for ldpi (Galaxy Mini), mdpi and hdpi.
Android 2.x has no vector drawables, so every icon is rendered here at 4x and
The launcher icon (res/drawable-*/ic_launcher.png) comes from the supplied
Audiobookshelf icon pack and is not generated here. The notification icon is
cut out of that same artwork (art/icon_master_512.png): the white headphones
and equalizer become a white silhouette, as Android 2.3's status bar expects.
Android 2.x has no vector drawables, so the player icons are rendered at 4x and
downsampled for smooth edges.
"""
import os
@@ -8,9 +13,9 @@ import sys
from PIL import Image, ImageDraw
RES = sys.argv[1]
ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
DENS = {"ldpi": 0.75, "mdpi": 1.0, "hdpi": 1.5}
AMBER = (245, 166, 35, 255)
DARK = (18, 21, 25, 255)
LILAC = (188, 138, 252, 255) # the icon's sound-wave colour (#BC8AFC)
WHITE = (255, 255, 255, 255)
SS = 4 # supersampling
@@ -27,36 +32,32 @@ def save(img, px, folder, name):
out.save(os.path.join(d, name + ".png"))
def broadcast(d, s, cx, cy, scale, color, bg):
"""Podcast mark: a dot with two arcs on each side."""
r = s * 0.075 * scale
d.ellipse([cx - r, cy - r, cx + r, cy + r], fill=color)
w = max(1, int(s * 0.07 * scale))
for k in (0.22, 0.37):
rr = s * k * scale
box = [cx - rr, cy - rr, cx + rr, cy + rr]
d.arc(box, 140, 220, fill=color, width=w)
d.arc(box, -40, 40, fill=color, width=w)
def status_silhouette():
"""White mask of the icon's light parts (headphones, bars, waves) on transparency."""
src = Image.open(os.path.join(ROOT, "art", "icon_master_512.png")).convert("RGBA")
out = Image.new("RGBA", src.size, (0, 0, 0, 0))
sp, op = src.load(), out.load()
for y in range(src.size[1]):
for x in range(src.size[0]):
r, g, b, a = sp[x, y]
# the purple background has a low green channel; the white/lilac artwork a high one
level = min(255, max(0, (g - 80) * 255 // 50))
op[x, y] = (255, 255, 255, level * a // 255)
box = out.getbbox()
out = out.crop(box)
side = max(out.size)
sq = Image.new("RGBA", (side, side), (0, 0, 0, 0))
sq.paste(out, ((side - out.size[0]) // 2, (side - out.size[1]) // 2))
return sq
def launcher(px, folder):
img, s = canvas(px)
d = ImageDraw.Draw(img)
m = s * 0.06
d.rounded_rectangle([m, m, s - m, s - m], radius=s * 0.2, fill=DARK, outline=AMBER, width=int(s * 0.04))
broadcast(d, s, s / 2, s * 0.44, 1.0, AMBER, DARK)
# little stand under the mark
w = s * 0.05
d.rectangle([s / 2 - w / 2, s * 0.5, s / 2 + w / 2, s * 0.74], fill=AMBER)
d.rounded_rectangle([s * 0.36, s * 0.72, s * 0.64, s * 0.78], radius=w / 2, fill=AMBER)
save(img, px, folder, "ic_launcher")
def status(px, folder):
img, s = canvas(px)
d = ImageDraw.Draw(img)
broadcast(d, s, s / 2, s / 2, 1.25, WHITE, None)
save(img, px, folder, "ic_stat")
def status(sil, px, folder):
pad = max(1, round(px * 0.06))
inner = sil.resize((px - 2 * pad, px - 2 * pad), Image.LANCZOS)
img = Image.new("RGBA", (px, px), (0, 0, 0, 0))
img.paste(inner, (pad, pad))
d = os.path.join(RES, "drawable-" + folder)
img.save(os.path.join(d, "ic_stat.png"))
def play(px, folder, name, color):
@@ -85,12 +86,12 @@ def refresh(px, folder):
save(img, px, folder, "ic_refresh")
sil = status_silhouette()
for folder, k in DENS.items():
launcher(round(48 * k), folder)
status(round(25 * k), folder)
play(round(48 * k), folder, "ic_play", DARK)
pause(round(48 * k), folder, "ic_pause", DARK)
play(round(38 * k), folder, "ic_play_small", AMBER)
pause(round(38 * k), folder, "ic_pause_small", AMBER)
status(sil, round(25 * k), folder)
play(round(32 * k), folder, "ic_play", WHITE) # on the purple play button
pause(round(32 * k), folder, "ic_pause", WHITE)
play(round(38 * k), folder, "ic_play_small", LILAC) # mini player bar, on dark
pause(round(38 * k), folder, "ic_pause_small", LILAC)
refresh(round(30 * k), folder)
print("icons ok")