feat: complete academic symbol lexicon heal, 2-column Cooper extraction, and updated assets
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
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 [],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user