1 Commits

Author SHA1 Message Date
417a012c93 feat: add disabled state to ImageRotatorCard and handle paused state in ImageRotatorWidget
All checks were successful
Build App / build (push) Successful in 7m14s
2026-03-01 19:06:34 +01:00
3 changed files with 31 additions and 2 deletions

View File

@@ -68,6 +68,7 @@ interface ClockCard {
interface ImageRotatorCard {
id: string; type: "image_rotator"; name: string;
config: { images: string[]; interval: number; fit: "cover" | "contain" };
disabled?: boolean;
layout?: CardLayout;
}
@@ -85,6 +86,7 @@ export type DataCard = CustomJsonCard | StaticTextCard | ClockCard | ImageRotato
interface FormState {
type: CardType;
name: string;
disabled: boolean;
// layout
grid_col: number; grid_row: number; col_span: number; row_span: number;
// display (custom_json / static_text / clock)
@@ -112,6 +114,7 @@ interface FormState {
const EMPTY_FORM: FormState = {
type: "custom_json",
name: "",
disabled: false,
grid_col: 1, grid_row: 1, col_span: 1, row_span: 1,
font_size: "16",
text_color: "#ffffff",
@@ -186,6 +189,7 @@ function cardToForm(card: DataCard): FormState {
image_urls: card.config.images ?? [],
image_interval: String(card.config.interval ?? 10),
image_fit: card.config.fit ?? "cover",
disabled: (card as ImageRotatorCard).disabled ?? false,
};
}
if (card.type === "spotify") {
@@ -246,6 +250,7 @@ function formToCard(form: FormState, id: string): DataCard {
fit: form.image_fit,
},
layout,
disabled: form.disabled,
};
}
if (form.type === "spotify") {
@@ -967,6 +972,17 @@ function FormView({ form, onChange, onBoolChange, onLayoutChange, onTypeChange,
<FieldLabel text="Name *" />
<TextInput style={styles.input} placeholder="My Widget" placeholderTextColor={colors.placeholderColor} value={form.name} onChangeText={(v) => onChange("name", v)} />
</View>
{form.type === "image_rotator" && (
<View style={[styles.field, styles.row, { alignItems: "center" }] }>
<Text style={[styles.label, { flex: 1 }]}>Paused</Text>
<Switch
value={form.disabled}
onValueChange={(v) => onBoolChange("disabled", v)}
trackColor={{ true: colors.accent, false: colors.border }}
thumbColor="#fff"
/>
</View>
)}
<SectionLabel text={form.type === "custom_json" ? "Data Source" : form.type === "static_text" ? "Content" : form.type === "clock" ? "Clock Settings" : form.type === "spotify" ? "Spotify Settings" : "Images"} />
{form.type === "custom_json" && <CustomJsonFields form={form} onChange={onChange} />}
@@ -1030,7 +1046,10 @@ function cardSubtitle(card: DataCard): string {
function cardMeta(card: DataCard): string {
if (card.type === "custom_json") return `Refresh: ${(card as CustomJsonCard).config.refresh_interval}s`;
if (card.type === "image_rotator") return `Fit: ${card.config.fit}`;
if (card.type === "image_rotator") {
const paused = (card as ImageRotatorCard).disabled ? "Paused · " : "";
return `${paused}Fit: ${card.config.fit}`;
}
if (card.type === "clock") return card.config.mode === "time" ? "Mode: live time" : "Mode: countdown";
if (card.type === "spotify") return `Refresh: ${(card as SpotifyCard).config.refresh_interval}s`;
return "";

View File

@@ -242,6 +242,7 @@ function ImageRotatorWidget({ card, isNightMode, nightMessage }: { card: ImageRo
useEffect(() => {
if (isNightMode) return;
if (card.disabled) return;
if (images.length <= 1) return;
const ms = Math.max(2000, (card.config.interval ?? 10) * 1000);
const timer = setInterval(() => {
@@ -252,7 +253,7 @@ function ImageRotatorWidget({ card, isNightMode, nightMessage }: { card: ImageRo
}, 400);
}, ms);
return () => clearInterval(timer);
}, [images.length, card.config.interval, isNightMode]);
}, [images.length, card.config.interval, isNightMode, card.disabled]);
// ── Night mode overlay ────────────────────────────────────────────────────
if (isNightMode) {
@@ -292,6 +293,13 @@ function ImageRotatorWidget({ card, isNightMode, nightMessage }: { card: ImageRo
display: "block",
}}
/>
{/* Paused overlay when disabled */}
{card.disabled && (
<div className="absolute inset-0 flex flex-col items-center justify-center bg-black/50">
<span className="text-5xl"></span>
<span className="text-white text-lg font-semibold mt-2">Paused</span>
</div>
)}
{/* Name overlay */}
<div className="absolute bottom-0 left-0 right-0 px-4 py-2 bg-gradient-to-t from-black/70 to-transparent">
<span className="text-white text-xs font-semibold truncate">{card.name}</span>

View File

@@ -115,6 +115,8 @@ export interface ImageRotatorCard {
name: string;
config: ImageRotatorConfig;
layout?: CardLayout;
/** When true the rotator is temporarily paused on the TV */
disabled?: boolean;
}
// ─── spotify ──────────────────────────────────────────────────────────────────