- BLE: 修复 BlueZ LocalName 与 Includes 冲突,串行注册与退避 - HTTP: 语音对话补 Live2D talking 标志与 session;Web 补 X-Session-Id - Flutter: 角色/对话/模型页 + API,Gradle/依赖升级,麦克风权限 - 文档: 新增 docs/STATUS.md,校准 CLAUDE/PROGRESS/README - 清理: 移除根目录截图与临时模型,运维脚本迁入 scripts/device
93 lines
2.4 KiB
Dart
93 lines
2.4 KiB
Dart
class CharacterPack {
|
|
const CharacterPack({
|
|
required this.filename,
|
|
required this.name,
|
|
required this.characterType,
|
|
required this.renderType,
|
|
this.live2dModel,
|
|
});
|
|
|
|
final String filename;
|
|
final String name;
|
|
final String characterType;
|
|
final String renderType;
|
|
final String? live2dModel;
|
|
|
|
bool get isLive2d => renderType.toLowerCase() == 'live2d';
|
|
|
|
String get typeLabel {
|
|
switch (characterType.toLowerCase()) {
|
|
case 'human':
|
|
return '数字人';
|
|
case 'singer':
|
|
return '歌姬';
|
|
case 'live2d':
|
|
return 'Live2D';
|
|
case 'pet':
|
|
default:
|
|
return '宠物';
|
|
}
|
|
}
|
|
|
|
IconDataLike get iconHint {
|
|
switch (characterType.toLowerCase()) {
|
|
case 'human':
|
|
return IconDataLike.person;
|
|
case 'singer':
|
|
return IconDataLike.mic;
|
|
case 'live2d':
|
|
return IconDataLike.sparkle;
|
|
default:
|
|
return IconDataLike.pets;
|
|
}
|
|
}
|
|
|
|
factory CharacterPack.fromJson(Map<String, dynamic> json) {
|
|
final character = json['character'];
|
|
final Map<String, dynamic> charMap = character is Map
|
|
? Map<String, dynamic>.from(character)
|
|
: const <String, dynamic>{};
|
|
final filename = json['filename']?.toString() ?? '';
|
|
return CharacterPack(
|
|
filename: filename,
|
|
name: charMap['name']?.toString().isNotEmpty == true
|
|
? charMap['name'].toString()
|
|
: filename,
|
|
characterType: charMap['character_type']?.toString() ?? 'pet',
|
|
renderType: charMap['render_type']?.toString() ?? 'video',
|
|
live2dModel: charMap['live2d_model']?.toString(),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Avoid importing Flutter material in pure model unit tests.
|
|
enum IconDataLike { pets, person, mic, sparkle }
|
|
|
|
class AvailableConfigs {
|
|
const AvailableConfigs({
|
|
required this.configs,
|
|
required this.active,
|
|
});
|
|
|
|
final List<CharacterPack> configs;
|
|
final String active;
|
|
|
|
factory AvailableConfigs.fromJson(Map<String, dynamic> json) {
|
|
final raw = json['configs'];
|
|
final list = <CharacterPack>[];
|
|
if (raw is List) {
|
|
for (final item in raw) {
|
|
if (item is Map<String, dynamic>) {
|
|
list.add(CharacterPack.fromJson(item));
|
|
} else if (item is Map) {
|
|
list.add(CharacterPack.fromJson(Map<String, dynamic>.from(item)));
|
|
}
|
|
}
|
|
}
|
|
return AvailableConfigs(
|
|
configs: list,
|
|
active: json['active']?.toString() ?? '',
|
|
);
|
|
}
|
|
}
|