Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions lib/widgets/map_svg_color_mapper.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart' show mapEquals;
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:icarus/providers/user_preferences_provider.dart';
Expand All @@ -12,24 +13,26 @@ class MapSvgSourceColors {
}

class MapSvgColorMapper extends ColorMapper {
const MapSvgColorMapper(this.replacements);
MapSvgColorMapper(Map<int, Color> replacements)
: replacements = Map.unmodifiable(replacements);

MapSvgColorMapper.forPalette(MapThemePalette palette)
: replacements = {
: replacements = Map.unmodifiable({
MapSvgSourceColors.base.toARGB32(): palette.baseColor,
MapSvgSourceColors.detail.toARGB32(): palette.detailColor,
MapSvgSourceColors.highlight.toARGB32(): palette.highlightColor,
};
});

/// The map in [palette] as cones reveal it: the same art with its floor
/// in [revealedFloorColor] (see `lib/view_cone/cone_coverage.dart`).
MapSvgColorMapper.revealed(MapThemePalette palette)
: replacements = {
: replacements = Map.unmodifiable({
MapSvgSourceColors.base.toARGB32(): revealedFloorColor(palette),
MapSvgSourceColors.detail.toARGB32(): palette.detailColor,
MapSvgSourceColors.highlight.toARGB32(): palette.highlightColor,
};
});

/// Unmodifiable: mappers are compared by these, so they never change.
final Map<int, Color> replacements;

@override
Expand All @@ -48,4 +51,18 @@ class MapSvgColorMapper extends ColorMapper {
final alpha = (color.a * 255.0).round().clamp(0, 255);
return replacement.withAlpha(alpha);
}

// The SVG loader and its picture cache compare mappers, so a mapper made
// again with the same colours, as views do on every build (a replay builds
// every frame), must equal the last one. If it didn't, the map would be
// loaded and drawn again from scratch.
@override
bool operator ==(Object other) =>
other is MapSvgColorMapper && mapEquals(other.replacements, replacements);

@override
int get hashCode => Object.hashAllUnordered([
for (final MapEntry(:key, :value) in replacements.entries)
Object.hash(key, value),
]);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
47 changes: 47 additions & 0 deletions test/map_svg_color_mapper_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import 'package:flutter/painting.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:icarus/providers/user_preferences_provider.dart';
import 'package:icarus/widgets/map_svg_color_mapper.dart';

void main() {
final palette = MapThemePalette(
baseColorValue: 0xFF271406,
detailColorValue: 0xFFB27C40,
highlightColorValue: 0xFFF08234,
);

// A map widget rebuilt with a mapper made again from the same palette must
// keep its loaded picture: flutter_svg reloads whenever the loader changes,
// and the loader compares mappers.
test('a mapper made again from the same palette gives an equal loader', () {
SvgAssetLoader loader(MapSvgColorMapper mapper) =>
SvgAssetLoader('assets/maps/ascent_map.svg', colorMapper: mapper);

for (final make in [
MapSvgColorMapper.forPalette,
MapSvgColorMapper.revealed,
]) {
final again = make(palette.copyWith());
expect(again, make(palette));
expect(again.hashCode, make(palette).hashCode);
expect(loader(again), loader(make(palette)));
}
});

test('the order colours were listed in does not matter', () {
const red = Color(0xFFFF0000), blue = Color(0xFF0000FF);
final one = MapSvgColorMapper(const {1: red, 2: blue});
final other = MapSvgColorMapper(const {2: blue, 1: red});
expect(other, one);
expect(other.hashCode, one.hashCode);
});

test('mappers for different colours differ', () {
final other = palette.copyWith(baseColorValue: 0xFF102030);
expect(MapSvgColorMapper.forPalette(other),
isNot(MapSvgColorMapper.forPalette(palette)));
expect(MapSvgColorMapper.revealed(palette),
isNot(MapSvgColorMapper.forPalette(palette)));
});
}
Loading