scriptable-testlab
Version:
A lightweight, efficient tool designed to manage and update scripts for Scriptable.
246 lines (211 loc) • 5.92 kB
text/typescript
import {AbsWidgetImage} from 'scriptable-abstract';
import {MockData} from '../../data';
import {MockImage} from '../../media/image';
import {MockColor} from '../color';
import {MockSize} from '../size';
/**
* Represents the content mode options for an image.
*/
type ContentMode = 'fitting' | 'filling';
/**
* Represents the alignment options for an image.
*/
type ImageAlignment = 'left' | 'center' | 'right';
/**
* Represents the state of a widget image element.
*/
interface WidgetImageMockState {
readonly image: Image;
readonly resizable: boolean;
readonly imageSize: Size;
readonly imageOpacity: number;
readonly cornerRadius: number;
readonly borderWidth: number;
readonly borderColor: Color;
readonly containerRelativeShape: boolean;
readonly tintColor: Color;
readonly url: string;
readonly contentMode: ContentMode;
readonly alignment: ImageAlignment;
}
/**
* Default state for a new widget image element.
*/
const DEFAULT_STATE: WidgetImageMockState = {
image: MockImage.fromData(MockData.fromString('')),
resizable: true,
imageSize: new MockSize(100, 100),
imageOpacity: 1.0,
cornerRadius: 0,
borderWidth: 0,
borderColor: new MockColor('#000000'),
containerRelativeShape: false,
tintColor: new MockColor('#000000'),
url: '',
contentMode: 'fitting',
alignment: 'center',
};
/**
* Mock implementation of Scriptable's WidgetImage.
* Represents an image that can be displayed in a widget.
*
* @example
* ```typescript
* const image = MockImage.fromFile('example.jpg');
* const widgetImage = new MockWidgetImage(image);
* widgetImage.imageSize = new MockSize(200, 100);
* widgetImage.cornerRadius = 10;
* widgetImage.centerAlignImage();
* ```
*/
export class MockWidgetImage extends AbsWidgetImage<WidgetImageMockState> {
/**
* Creates a new widget image element with the specified image.
*/
constructor(image?: Image) {
super({
...DEFAULT_STATE,
...(image ? {image} : {}),
});
}
/**
* Creates a new widget image instance.
* @param image - The image to display in the widget.
* @returns A new widget image instance.
*/
static create(image?: Image): WidgetImage {
return new MockWidgetImage(image);
}
// Property accessors
get image(): Image {
return this.state.image;
}
set image(value: Image) {
this.setState({image: value});
}
get resizable(): boolean {
return this.state.resizable;
}
set resizable(value: boolean) {
this.setState({resizable: value});
}
get imageSize(): Size {
return this.state.imageSize;
}
set imageSize(value: Size) {
this.setState({imageSize: value});
}
/**
* Gets or sets the opacity of the image.
* Value should be between 0 (fully transparent) and 1 (fully opaque).
*/
get imageOpacity(): number {
return this.state.imageOpacity;
}
set imageOpacity(value: number) {
const numValue = Number(value);
const clampedValue = isNaN(numValue) ? 0 : Math.max(0, Math.min(1, numValue));
this.setState({imageOpacity: clampedValue});
}
/**
* Gets or sets the corner radius of the image.
* Negative values will be converted to 0.
*/
get cornerRadius(): number {
return this.state.cornerRadius;
}
set cornerRadius(value: number) {
const numValue = Number(value);
const validValue = isNaN(numValue) || numValue < 0 ? 0 : numValue;
this.setState({cornerRadius: validValue});
}
/**
* Gets or sets the border width of the image.
* Negative values will be converted to 0.
*/
get borderWidth(): number {
return this.state.borderWidth;
}
set borderWidth(value: number) {
const numValue = isNaN(Number(value)) ? 0 : Number(value);
this.setState({borderWidth: Math.max(0, numValue)});
}
get borderColor(): Color {
return this.state.borderColor;
}
set borderColor(value: Color) {
this.setState({borderColor: value});
}
get containerRelativeShape(): boolean {
return this.state.containerRelativeShape;
}
set containerRelativeShape(value: boolean) {
this.setState({containerRelativeShape: value});
}
get tintColor(): Color {
return this.state.tintColor;
}
set tintColor(value: Color) {
this.setState({tintColor: value});
}
get url(): string {
return this.state.url;
}
set url(value: string) {
this.setState({url: value});
}
/**
* Aligns the image to the left of its container.
* @returns this for method chaining
*/
leftAlignImage(): this {
this.setState({alignment: 'left'});
return this;
}
/**
* Centers the image in its container.
* @returns this for method chaining
*/
centerAlignImage(): this {
this.setState({alignment: 'center'});
return this;
}
/**
* Aligns the image to the right of its container.
* @returns this for method chaining
*/
rightAlignImage(): this {
this.setState({alignment: 'right'});
return this;
}
/**
* Sets the content mode to fitting, which scales the image to fit within its container while maintaining aspect ratio.
* @returns this for method chaining
*/
applyFittingContentMode(): this {
this.setState({contentMode: 'fitting'});
return this;
}
/**
* Sets the content mode to filling, which scales the image to fill its container while maintaining aspect ratio.
* @returns this for method chaining
*/
applyFillingContentMode(): this {
this.setState({contentMode: 'filling'});
return this;
}
/**
* Gets the current alignment of the image.
* @returns The current alignment ('left', 'center', or 'right').
*/
getAlignment(): ImageAlignment {
return this.state.alignment;
}
/**
* Gets the current content mode of the image.
* @returns The current content mode ('fitting' or 'filling').
*/
getContentMode(): ContentMode {
return this.state.contentMode;
}
}