Files
999/lib/models/tradition_model.dart

178 lines
5.0 KiB
Dart

class StationWord {
final int id;
final String word;
final String emoji;
final String pos;
final String category;
final String desc;
const StationWord({
required this.id,
required this.word,
this.emoji = '',
this.pos = '',
this.category = '',
this.desc = '',
});
factory StationWord.fromMap(Map<String, dynamic> map) {
return StationWord(
id: (map['id'] as num?)?.toInt() ?? 0,
word: map['word'] as String? ?? '',
emoji: map['emoji'] as String? ?? '',
pos: map['pos'] as String? ?? '',
category: map['category'] as String? ?? '',
desc: map['desc'] as String? ?? '',
);
}
}
class TraditionStation {
final String id;
final String name;
final String symbol;
final String group;
final String lore;
final String? hebrew;
final String? hanzi;
final String? arabic;
final String? arcanum;
final StationWord? primary;
final List<StationWord> cluster;
final List<Map<String, String>> parallels;
final List<int> dots;
const TraditionStation({
required this.id,
required this.name,
required this.symbol,
required this.group,
required this.lore,
this.hebrew,
this.hanzi,
this.arabic,
this.arcanum,
this.primary,
this.cluster = const [],
this.parallels = const [],
this.dots = const [],
});
/// Four geomantic rows (1 or 2 dots each), head → feet. Empty if not a figure.
List<int> get geomancyRows {
if (dots.length == 4 && dots.every((n) => n == 1 || n == 2)) return dots;
final lines = symbol
.split('\n')
.map((s) => s.trim())
.where((s) => s.isNotEmpty)
.toList();
if (lines.length != 4) return const [];
final rows = <int>[];
for (final line in lines) {
final n = '·'.allMatches(line).length;
if (n != 1 && n != 2) return const [];
rows.add(n);
}
return rows;
}
String get groupKey {
final sep = group.indexOf(' · ');
if (sep <= 0) return group;
return group.substring(0, sep);
}
String get groupSub {
final sep = group.indexOf(' · ');
if (sep < 0) return '';
return group.substring(sep + 3);
}
factory TraditionStation.fromMap(Map<String, dynamic> map) {
final primaryMap = map['primary'];
final clusterRaw = map['cluster'];
return TraditionStation(
id: map['id'] as String? ?? '',
name: map['name'] as String? ?? '',
symbol: map['symbol'] as String? ?? '',
group: map['group'] as String? ?? '',
lore: map['lore'] as String? ?? '',
hebrew: map['hebrew'] as String?,
hanzi: map['hanzi'] as String?,
arabic: map['arabic'] as String?,
arcanum: map['arcanum'] as String?,
primary: primaryMap is Map<String, dynamic>
? StationWord.fromMap(primaryMap)
: null,
cluster: clusterRaw is List
? clusterRaw
.whereType<Map<String, dynamic>>()
.map(StationWord.fromMap)
.toList()
: const [],
dots: (map['dots'] as List? ?? const [])
.whereType<num>()
.map((n) => n.toInt())
.toList(),
parallels: (map['parallels'] as List? ?? const [])
.whereType<Map>()
.map((p) => {
'system': '${p['system'] ?? ''}',
'system_name': '${p['system_name'] ?? ''}',
'id': '${p['id'] ?? ''}',
'name': '${p['name'] ?? ''}',
'symbol': '${p['symbol'] ?? ''}',
})
.toList(),
);
}
bool matchesQuery(String query) {
if (query.isEmpty) return true;
final q = query.toLowerCase();
if (name.toLowerCase().contains(q)) return true;
if (lore.toLowerCase().contains(q)) return true;
if (symbol.contains(query)) return true;
if (hebrew != null && hebrew!.contains(query)) return true;
if (hanzi != null && hanzi!.contains(query)) return true;
if (arabic != null && arabic!.contains(query)) return true;
if (primary != null && primary!.word.toLowerCase().contains(q)) return true;
return cluster.any((c) => c.word.toLowerCase().contains(q));
}
}
class TraditionCanon {
final String id;
final String name;
final String icon;
final int count;
final String description;
final List<TraditionStation> stations;
const TraditionCanon({
required this.id,
required this.name,
required this.icon,
required this.count,
required this.description,
required this.stations,
});
factory TraditionCanon.fromMap(Map<String, dynamic> map) {
final raw = map['stations'];
return TraditionCanon(
id: map['id'] as String? ?? '',
name: map['name'] as String? ?? '',
icon: map['icon'] as String? ?? '',
count: (map['count'] as num?)?.toInt() ?? 0,
description: map['description'] as String? ?? '',
stations: raw is List
? raw
.whereType<Map<String, dynamic>>()
.map(TraditionStation.fromMap)
.toList()
: const [],
);
}
}