2026-04-09 21:32:23 +08:00

320 lines
11 KiB
Dart

import 'package:tancent_vap/utils/anim_configs.dart';
/// Defines how video content should be scaled within its container.
///
/// These scale types determine how the VAP animation is displayed when the
/// animation dimensions don't exactly match the widget size.
///
/// Example usage:
/// ```dart
/// VapView(
/// scaleType: ScaleType.fitCenter, // Maintain aspect ratio, fit within bounds
/// )
/// ```
enum ScaleType {
/// Scales the video to fit within the container while maintaining aspect ratio.
/// The entire video will be visible, but there may be empty space if the
/// aspect ratios don't match.
fitCenter("fitCenter"),
/// Scales the video to fill the container while maintaining aspect ratio.
/// The video may be cropped if aspect ratios don't match, but no empty space
/// will be visible.
centerCrop("centerCrop"),
/// Scales the video to exactly fill the container bounds.
/// This may distort the video if aspect ratios don't match, but ensures
/// the entire container is filled.
fitXY("fitXY");
/// The string key used for native platform communication.
final String key;
const ScaleType(this.key);
}
/// Defines the orientation of video content.
///
/// This enum represents the orientation metadata of the VAP animation,
/// which can be used to determine how the content should be displayed
/// or processed.
enum VideoOrientation {
/// No specific orientation or orientation is unknown.
none(0),
/// Video content is in portrait orientation (height > width).
portrait(1),
/// Video content is in landscape orientation (width > height).
landscape(2);
/// The integer value used for native platform communication.
final int value;
const VideoOrientation(this.value);
/// Creates a VideoOrientation from an integer value.
///
/// This method is used when parsing orientation data from native platforms.
/// If the provided [value] doesn't match any known orientation, returns [none].
///
/// Parameters:
/// - [value]: Integer value representing the orientation (0=none, 1=portrait, 2=landscape)
static VideoOrientation fromValue(int value) {
return VideoOrientation.values
.firstWhere((e) => e.value == value, orElse: () => none);
}
}
/// Callback function for animation failure events.
///
/// Called when an animation fails to load or play.
///
/// Parameters:
/// - [code]: Error code indicating the type of failure
/// - [type]: String description of the error type
/// - [message]: Optional detailed error message
typedef OnFailed = void Function(int code, String type, String? message);
/// Callback function for animation completion events.
///
/// Called when an animation finishes playing completely.
typedef OnVideoComplete = void Function();
/// Callback function for animation destruction events.
///
/// Called when an animation is destroyed and resources are cleaned up.
typedef OnVideoDestroy = void Function();
/// Callback function for frame rendering events.
///
/// Called for each frame that is rendered during animation playback.
/// This callback is only available on Android.
///
/// Parameters:
/// - [frameInfo]: Index of the current frame being rendered
/// - [configs]: Animation configuration data (may be null)
typedef OnVideoRender = void Function(int frameInfo, VAPConfigs? configs);
/// Callback function for animation configuration ready events.
///
/// Called when the animation file has been loaded and configuration
/// data is available.
///
/// Parameters:
/// - [configs]: Complete animation configuration data
typedef OnVideoConfigReady = void Function(VAPConfigs configs);
/// Callback function for animation start events.
///
/// Called when an animation begins playing.
typedef OnVideoStart = void Function();
/// Abstract base class for dynamic content that can be injected into VAP animations.
///
/// VAPContent represents different types of content (text, images) that can be
/// dynamically inserted into VAP animations at runtime. This allows for
/// personalized animations with user-specific data.
///
/// Subclasses include:
/// - [TextContent]: For dynamic text content
/// - [ImageBase64Content]: For base64-encoded images
/// - [ImageFileContent]: For local file images
/// - [ImageAssetContent]: For Flutter asset images
/// - [ImageURLContent]: For remote images
///
/// Example usage:
/// ```dart
/// Map<String, VAPContent> contents = {
/// 'username': TextContent('John Doe'),
/// 'avatar': ImageURLContent('https://example.com/avatar.jpg'),
/// 'logo': ImageAssetContent('assets/images/logo.png'),
/// };
/// ```
abstract class VAPContent {
/// The type of content (e.g., 'text', 'image_url', 'image_file').
String get contentType;
/// The actual content value (text string, file path, URL, etc.).
String get contentValue;
/// Converts this content to a map for native platform communication.
///
/// Returns a map containing the content type and value that can be
/// serialized and sent to native platforms.
Map<String, dynamic> get toMap {
return {'contentType': contentType, 'contentValue': contentValue};
}
/// Creates a VAPContent instance from a map received from native platforms.
///
/// This factory method automatically determines the appropriate subclass
/// based on the content type and value in the map.
///
/// Parameters:
/// - [value]: Map containing 'contentType' and 'contentValue' keys
///
/// Returns the appropriate VAPContent subclass instance.
/// Throws [ArgumentError] if the content type is unknown.
static VAPContent fromMap(Map<String, dynamic> value) {
final contentType = value['contentType'] as String;
final contentValue = value['contentValue'] as String;
switch (contentType) {
case 'text':
return TextContent(contentValue);
case 'image':
if (contentValue.startsWith('http://') ||
contentValue.startsWith('https://')) {
return ImageURLContent(contentValue);
} else if (contentValue.startsWith('data:image/')) {
return ImageBase64Content(contentValue);
} else if (contentValue.startsWith('assets/')) {
return ImageAssetContent(contentValue);
} else {
return ImageFileContent(contentValue);
}
default:
throw ArgumentError('Unknown content type: $contentType');
}
}
}
/// Content type for dynamic text injection into VAP animations.
///
/// TextContent allows you to inject dynamic text into VAP animations at runtime.
/// The text will be rendered using the styling defined in the VAP file.
///
/// Example usage:
/// ```dart
/// TextContent username = TextContent('John Doe');
/// await controller.setVapTagContent('username', username);
/// ```
class TextContent extends VAPContent {
/// The text content to display in the animation.
final String text;
/// Creates a TextContent with the specified text.
///
/// Parameters:
/// - [text]: The text string to inject into the animation
TextContent(this.text);
@override
String get contentType => 'text';
@override
String get contentValue => text;
}
/// Content type for base64-encoded image injection into VAP animations.
///
/// ImageBase64Content allows you to inject images that are encoded as base64
/// strings directly into VAP animations. This is useful when you have image
/// data in memory or received from an API.
///
/// Example usage:
/// ```dart
/// String base64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';
/// ImageBase64Content image = ImageBase64Content(base64Data);
/// await controller.setVapTagContent('avatar', image);
/// ```
class ImageBase64Content extends VAPContent {
/// The base64-encoded image data.
final String base64;
/// Creates an ImageBase64Content with the specified base64 data.
///
/// Parameters:
/// - [base64]: Base64-encoded image string
ImageBase64Content(this.base64);
@override
String get contentType => 'image_base64';
@override
String get contentValue => base64;
}
/// Content type for local file image injection into VAP animations.
///
/// ImageFileContent allows you to inject images from the device's file system
/// into VAP animations. The file path should point to a valid image file
/// accessible to the app.
///
/// Example usage:
/// ```dart
/// ImageFileContent image = ImageFileContent('/storage/emulated/0/Download/avatar.jpg');
/// await controller.setVapTagContent('avatar', image);
/// ```
class ImageFileContent extends VAPContent {
/// The file system path to the image file.
final String filePath;
/// Creates an ImageFileContent with the specified file path.
///
/// Parameters:
/// - [filePath]: Absolute path to the image file on the device
ImageFileContent(this.filePath);
@override
String get contentType => 'image_file';
@override
String get contentValue => filePath;
}
/// Content type for Flutter asset image injection into VAP animations.
///
/// ImageAssetContent allows you to inject images from your app's assets
/// into VAP animations. The asset must be declared in your pubspec.yaml file.
///
/// Example usage:
/// ```dart
/// ImageAssetContent logo = ImageAssetContent('assets/images/logo.png');
/// await controller.setVapTagContent('logo', logo);
/// ```
class ImageAssetContent extends VAPContent {
/// The asset path as declared in pubspec.yaml.
final String assetPath;
/// Creates an ImageAssetContent with the specified asset path.
///
/// Parameters:
/// - [assetPath]: Path to the asset image (e.g., 'assets/images/logo.png')
ImageAssetContent(this.assetPath);
@override
String get contentType => 'image_asset';
@override
String get contentValue => assetPath;
}
/// Content type for remote URL image injection into VAP animations.
///
/// ImageURLContent allows you to inject images from remote URLs into VAP
/// animations. The image will be downloaded and cached automatically.
///
/// Example usage:
/// ```dart
/// ImageURLContent avatar = ImageURLContent('https://example.com/avatar.jpg');
/// await controller.setVapTagContent('avatar', avatar);
/// ```
class ImageURLContent extends VAPContent {
/// The URL of the remote image.
final String url;
/// Creates an ImageURLContent with the specified URL.
///
/// Parameters:
/// - [url]: HTTP/HTTPS URL pointing to an image file
ImageURLContent(this.url);
@override
String get contentType => 'image_url';
@override
String get contentValue => url;
}