140 lines
3.8 KiB
Dart
140 lines
3.8 KiB
Dart
class IgnisScene {
|
||
final String id;
|
||
final String displayName;
|
||
|
||
const IgnisScene({required this.id, required this.displayName});
|
||
|
||
static IgnisScene fromApi(Object? value, {String? fallbackId}) {
|
||
if (value is Map) {
|
||
final map = Map<String, dynamic>.from(value);
|
||
final id =
|
||
_stringValue(map, const ['id', 'scene', 'scene_id', 'value']) ??
|
||
fallbackId;
|
||
if (id == null || id.isEmpty) {
|
||
throw const FormatException('scene не содержит id');
|
||
}
|
||
|
||
final explicitName = _stringValue(map, const [
|
||
'name',
|
||
'label',
|
||
'display_name',
|
||
'title',
|
||
]);
|
||
return IgnisScene(
|
||
id: id,
|
||
displayName: explicitName ?? displayNameFor(id),
|
||
);
|
||
}
|
||
|
||
final id = value?.toString() ?? fallbackId;
|
||
if (id == null || id.isEmpty) {
|
||
throw const FormatException('scene должен быть объектом или id');
|
||
}
|
||
return IgnisScene(id: id, displayName: displayNameFor(id));
|
||
}
|
||
|
||
static List<IgnisScene> listFromApi(Object? data) {
|
||
final values = _collectionValues(data, const ['data', 'scenes']);
|
||
return values.map((value) {
|
||
if (value.entryKey == null) {
|
||
return IgnisScene.fromApi(value.value);
|
||
}
|
||
|
||
if (value.value is String || value.value is num) {
|
||
final name = value.value.toString();
|
||
return IgnisScene(
|
||
id: value.entryKey!,
|
||
displayName: _looksLikeTechnicalId(name)
|
||
? displayNameFor(name)
|
||
: name,
|
||
);
|
||
}
|
||
|
||
return IgnisScene.fromApi(value.value, fallbackId: value.entryKey);
|
||
}).toList();
|
||
}
|
||
|
||
static String displayNameFor(String id) {
|
||
final normalized = id.trim();
|
||
final knownName = _wizSceneNames[normalized];
|
||
if (knownName != null) return knownName;
|
||
return 'Сцена $normalized';
|
||
}
|
||
}
|
||
|
||
const Map<String, String> _wizSceneNames = {
|
||
'1': 'Океан',
|
||
'2': 'Романтика',
|
||
'3': 'Закат',
|
||
'4': 'Вечеринка',
|
||
'5': 'Камин',
|
||
'6': 'Уют',
|
||
'7': 'Лес',
|
||
'8': 'Пастель',
|
||
'9': 'Пробуждение',
|
||
'10': 'Сон',
|
||
'11': 'Тёплый белый',
|
||
'12': 'Дневной свет',
|
||
'13': 'Холодный белый',
|
||
'14': 'Ночник',
|
||
'15': 'Фокус',
|
||
'16': 'Расслабление',
|
||
'17': 'Настоящие цвета',
|
||
'18': 'ТВ',
|
||
'19': 'Рост растений',
|
||
'20': 'Весна',
|
||
'21': 'Лето',
|
||
'22': 'Осень',
|
||
'23': 'Погружение',
|
||
'24': 'Джунгли',
|
||
'25': 'Мохито',
|
||
'26': 'Клуб',
|
||
'27': 'Рождество',
|
||
'28': 'Хэллоуин',
|
||
'29': 'Свеча',
|
||
'30': 'Золотистый белый',
|
||
'31': 'Пульс',
|
||
'32': 'Стимпанк',
|
||
};
|
||
|
||
String? _stringValue(Map<String, dynamic> map, List<String> keys) {
|
||
for (final key in keys) {
|
||
final value = map[key];
|
||
if (value != null && value.toString().isNotEmpty) {
|
||
return value.toString();
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
bool _looksLikeTechnicalId(String value) => int.tryParse(value.trim()) != null;
|
||
|
||
List<_CollectionValue> _collectionValues(Object? data, List<String> wrappers) {
|
||
if (data is List) {
|
||
return data.map((value) => _CollectionValue(value)).toList();
|
||
}
|
||
|
||
if (data is Map) {
|
||
final map = Map<String, dynamic>.from(data);
|
||
for (final wrapper in wrappers) {
|
||
final value = map[wrapper];
|
||
if (value is List) {
|
||
return value.map((item) => _CollectionValue(item)).toList();
|
||
}
|
||
}
|
||
|
||
return map.entries
|
||
.map((entry) => _CollectionValue(entry.value, entryKey: entry.key))
|
||
.toList();
|
||
}
|
||
|
||
throw const FormatException('ожидался список или объект');
|
||
}
|
||
|
||
class _CollectionValue {
|
||
final Object? value;
|
||
final String? entryKey;
|
||
|
||
const _CollectionValue(this.value, {this.entryKey});
|
||
}
|