Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c23ec9131 |
No files matched your search
@@ -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="5"
|
||||
android:versionName="1.4"
|
||||
android:versionCode="6"
|
||||
android:versionName="1.5"
|
||||
android:installLocation="auto">
|
||||
|
||||
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10" />
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 224 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 312 B After Width: | Height: | Size: 272 B |
|
Before Width: | Height: | Size: 510 B After Width: | Height: | Size: 533 B |
|
Before Width: | Height: | Size: 760 B After Width: | Height: | Size: 588 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 690 B After Width: | Height: | Size: 977 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 238 B |
|
Before Width: | Height: | Size: 413 B After Width: | Height: | Size: 434 B |
|
Before Width: | Height: | Size: 467 B After Width: | Height: | Size: 393 B |
|
Before Width: | Height: | Size: 656 B After Width: | Height: | Size: 647 B |
|
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 434 B |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 355 B After Width: | Height: | Size: 301 B |
|
Before Width: | Height: | Size: 486 B After Width: | Height: | Size: 494 B |
|
Before Width: | Height: | Size: 561 B After Width: | Height: | Size: 376 B |
|
Before Width: | Height: | Size: 834 B After Width: | Height: | Size: 806 B |
|
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 567 B |
|
After Width: | Height: | Size: 12 KiB |
@@ -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>
|
||||
@@ -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">
|
||||
|
||||
@@ -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><solid android:color="#FFC766" /><corners android:radius="23dp" /></shape>
|
||||
<shape><gradient android:startColor="#AA5CFF" android:endColor="#7022E6" android:angle="270" /><corners android:radius="23dp" /></shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape><solid android:color="@color/accent" /><corners android:radius="23dp" /></shape>
|
||||
<shape><gradient android:startColor="@color/accent_top" android:endColor="@color/accent_bottom" android:angle="270" /><corners android:radius="23dp" /></shape>
|
||||
</item>
|
||||
</selector>
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
android:gravity="center"
|
||||
android:textSize="@dimen/text_more"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/accent" />
|
||||
android:textColor="@color/accent_light" />
|
||||
@@ -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>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<PreferenceCategory android:title="Acerca de">
|
||||
<Preference
|
||||
android:key="about"
|
||||
android:title="MiniABS 1.4"
|
||||
android:title="MiniABS 1.5"
|
||||
android:summary="Un pequeno cliente de podcasts de Audiobookshelf para Android 2.2+" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
@@ -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.4";
|
||||
static final String VERSION = "1.5";
|
||||
|
||||
static class ApiException extends IOException {
|
||||
final int code;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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(32 * k), folder, "ic_play", DARK)
|
||||
pause(round(32 * 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")
|
||||