Skip to content

Commit a0c1c3b

Browse files
committed
fix: show imported buddies in review step and fix profile temperature
1 parent b2cb456 commit a0c1c3b

3 files changed

Lines changed: 71 additions & 25 deletions

File tree

lib/features/dive_import/data/services/uddf_entity_importer.dart

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1289,7 +1289,7 @@ class UddfEntityImporter {
12891289
Map<String, String> buddyIdMapping,
12901290
BuddyRepository repository,
12911291
) async {
1292-
// Link referenced buddies
1292+
// Link referenced buddies (from pre-imported buddy entities)
12931293
final buddyRefsValue = diveData['buddyRefs'];
12941294
final buddyRefs = buddyRefsValue is List
12951295
? buddyRefsValue.whereType<String>().toList()
@@ -1301,6 +1301,22 @@ class UddfEntityImporter {
13011301
}
13021302
}
13031303

1304+
// Link referenced dive guides (same buddy entities, different role)
1305+
final guideRefsValue = diveData['diveGuideRefs'];
1306+
final guideRefs = guideRefsValue is List
1307+
? guideRefsValue.whereType<String>().toList()
1308+
: <String>[];
1309+
for (final guideRef in guideRefs) {
1310+
final newGuideId = buddyIdMapping[guideRef];
1311+
if (newGuideId != null) {
1312+
await repository.addBuddyToDive(
1313+
diveId,
1314+
newGuideId,
1315+
BuddyRole.diveGuide,
1316+
);
1317+
}
1318+
}
1319+
13041320
// Handle inline buddy names not in the diver section
13051321
final inlineIds = <String>{};
13061322
final unmatchedNamesValue = diveData['unmatchedBuddyNames'];

lib/features/universal_import/data/parsers/subsurface_xml_parser.dart

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class SubsurfaceXmlParser implements ImportParser {
8989
final dives = <Map<String, dynamic>>[];
9090
final trips = <Map<String, dynamic>>[];
9191
final allTags = <String, Map<String, dynamic>>{};
92+
final allBuddies = <String, Map<String, dynamic>>{};
9293

9394
// Process trip-wrapped dives
9495
for (final tripElement in divesElement.findElements('trip')) {
@@ -103,6 +104,7 @@ class SubsurfaceXmlParser implements ImportParser {
103104
if (diveData != null) {
104105
diveData['tripRef'] = tripId;
105106
_collectTags(diveElement, diveData, allTags);
107+
_collectBuddies(diveElement, diveData, allBuddies);
106108
dives.add(diveData);
107109
tripDives.add(diveData);
108110
}
@@ -135,6 +137,7 @@ class SubsurfaceXmlParser implements ImportParser {
135137
final diveData = _parseDive(diveElement, siteMap: siteMap);
136138
if (diveData != null) {
137139
_collectTags(diveElement, diveData, allTags);
140+
_collectBuddies(diveElement, diveData, allBuddies);
138141
dives.add(diveData);
139142
}
140143
} catch (e) {
@@ -153,6 +156,9 @@ class SubsurfaceXmlParser implements ImportParser {
153156
if (allTags.isNotEmpty) {
154157
entities[ImportEntityType.tags] = allTags.values.toList();
155158
}
159+
if (allBuddies.isNotEmpty) {
160+
entities[ImportEntityType.buddies] = allBuddies.values.toList();
161+
}
156162
}
157163

158164
return ImportPayload(
@@ -250,23 +256,8 @@ class SubsurfaceXmlParser implements ImportParser {
250256
: WaterType.fresh;
251257
}
252258

253-
// Buddy -> proper Buddy entities via unmatchedBuddyNames
254-
final buddyEl = dive.findElements('buddy').firstOrNull;
255-
if (buddyEl != null) {
256-
final buddyNames = _splitNames(buddyEl.innerText);
257-
if (buddyNames.isNotEmpty) {
258-
result['unmatchedBuddyNames'] = buddyNames;
259-
}
260-
}
261-
262-
// Divemaster -> proper Buddy entities with diveGuide role
263-
final divemasterEl = dive.findElements('divemaster').firstOrNull;
264-
if (divemasterEl != null) {
265-
final dmNames = _splitNames(divemasterEl.innerText);
266-
if (dmNames.isNotEmpty) {
267-
result['unmatchedDiveGuideNames'] = dmNames;
268-
}
269-
}
259+
// Buddy and divemaster names are collected separately via _collectBuddies
260+
// after _parseDive returns, so they appear in ImportEntityType.buddies
270261

271262
// Composite notes: <notes> + "Suit: <suit>" + "SAC: <sac attr>"
272263
final notesParts = <String>[];
@@ -368,6 +359,34 @@ class SubsurfaceXmlParser implements ImportParser {
368359
};
369360
}
370361

362+
void _collectBuddies(
363+
XmlElement diveElement,
364+
Map<String, dynamic> diveData,
365+
Map<String, Map<String, dynamic>> allBuddies,
366+
) {
367+
final buddyEl = diveElement.findElements('buddy').firstOrNull;
368+
if (buddyEl != null) {
369+
final names = _splitNames(buddyEl.innerText);
370+
if (names.isNotEmpty) {
371+
diveData['buddyRefs'] = names;
372+
for (final name in names) {
373+
allBuddies.putIfAbsent(name, () => {'name': name, 'uddfId': name});
374+
}
375+
}
376+
}
377+
378+
final dmEl = diveElement.findElements('divemaster').firstOrNull;
379+
if (dmEl != null) {
380+
final names = _splitNames(dmEl.innerText);
381+
if (names.isNotEmpty) {
382+
diveData['diveGuideRefs'] = names;
383+
for (final name in names) {
384+
allBuddies.putIfAbsent(name, () => {'name': name, 'uddfId': name});
385+
}
386+
}
387+
}
388+
}
389+
371390
void _collectTags(
372391
XmlElement diveElement,
373392
Map<String, dynamic> diveData,

test/features/universal_import/data/parsers/subsurface_xml_parser_test.dart

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ void main() {
8181
});
8282

8383
group('dive metadata', () {
84-
test('parses buddies and divemasters as unmatched name lists', () async {
84+
test('creates buddy entities and sets refs on dives', () async {
8585
final result = await parser.parse(
8686
xmlBytes('''
8787
<divelog program='subsurface' version='3'>
@@ -97,9 +97,16 @@ void main() {
9797
</divelog>
9898
'''),
9999
);
100+
// Buddy entities created for review step
101+
final buddies = result.entitiesOf(ImportEntityType.buddies);
102+
expect(buddies.length, 3);
103+
final buddyNames = buddies.map((b) => b['name']).toSet();
104+
expect(buddyNames, containsAll(['John Doe', 'Alice', 'Jane Smith']));
105+
106+
// Dive has refs, not inline text
100107
final dive = result.entitiesOf(ImportEntityType.dives).first;
101-
expect(dive['unmatchedBuddyNames'], ['John Doe', 'Alice']);
102-
expect(dive['unmatchedDiveGuideNames'], ['Jane Smith']);
108+
expect(dive['buddyRefs'], ['John Doe', 'Alice']);
109+
expect(dive['diveGuideRefs'], ['Jane Smith']);
103110
expect(dive.containsKey('buddy'), isFalse);
104111
expect(dive.containsKey('diveMaster'), isFalse);
105112
});
@@ -581,10 +588,14 @@ void main() {
581588
// Verify a specific dive has expected data
582589
final dive1 = dives.firstWhere((d) => d['diveNumber'] == 1);
583590
expect(dive1['dateTime'], DateTime(2025, 9, 20, 7, 44, 37));
584-
final buddyNames = dive1['unmatchedBuddyNames'] as List<String>;
585-
expect(buddyNames, isNotEmpty);
586-
final guideNames = dive1['unmatchedDiveGuideNames'] as List<String>;
587-
expect(guideNames, isNotEmpty);
591+
final buddyRefs = dive1['buddyRefs'] as List<String>;
592+
expect(buddyRefs, isNotEmpty);
593+
final guideRefs = dive1['diveGuideRefs'] as List<String>;
594+
expect(guideRefs, isNotEmpty);
595+
596+
// Buddy entities should be in the payload for the review step
597+
final buddies = result.entitiesOf(ImportEntityType.buddies);
598+
expect(buddies.length, greaterThanOrEqualTo(2));
588599
expect(dive1['visibility'], Visibility.poor);
589600
expect(dive1['currentStrength'], CurrentStrength.strong);
590601
expect(dive1['waterType'], WaterType.salt);

0 commit comments

Comments
 (0)