@@ -8,9 +8,11 @@ import 'dart:convert';
8
8
import 'package:collection/collection.dart' ;
9
9
import 'package:flutter/foundation.dart' ;
10
10
import 'package:flutter/widgets.dart' ;
11
+ import 'package:logging/logging.dart' ;
11
12
import 'package:meta/meta.dart' ;
12
13
13
14
import 'configuration.dart' ;
15
+ import 'logging.dart' ;
14
16
import 'misc/errors.dart' ;
15
17
import 'path_utils.dart' ;
16
18
import 'route.dart' ;
@@ -358,29 +360,35 @@ class RouteMatchList {
358
360
/// Handles encoding and decoding of [RouteMatchList] objects to a format
359
361
/// suitable for using with [StandardMessageCodec] .
360
362
///
361
- /// The primary use of this class is for state restoration.
363
+ /// The primary use of this class is for state restoration and browser history .
362
364
@internal
363
365
class RouteMatchListCodec extends Codec <RouteMatchList , Map <Object ?, Object ?>> {
364
366
/// Creates a new [RouteMatchListCodec] object.
365
367
RouteMatchListCodec (RouteConfiguration configuration)
366
- : decoder = _RouteMatchListDecoder (configuration);
368
+ : decoder = _RouteMatchListDecoder (configuration),
369
+ encoder = _RouteMatchListEncoder (configuration);
367
370
368
371
static const String _locationKey = 'location' ;
369
372
static const String _extraKey = 'state' ;
370
373
static const String _imperativeMatchesKey = 'imperativeMatches' ;
371
374
static const String _pageKey = 'pageKey' ;
375
+ static const String _codecKey = 'codec' ;
376
+ static const String _jsonCodecName = 'json' ;
377
+ static const String _customCodecName = 'custom' ;
378
+ static const String _encodedKey = 'encoded' ;
372
379
373
380
@override
374
- final Converter <RouteMatchList , Map <Object ?, Object ?>> encoder =
375
- const _RouteMatchListEncoder ();
381
+ final Converter <RouteMatchList , Map <Object ?, Object ?>> encoder;
376
382
377
383
@override
378
384
final Converter <Map <Object ?, Object ?>, RouteMatchList > decoder;
379
385
}
380
386
381
387
class _RouteMatchListEncoder
382
388
extends Converter <RouteMatchList , Map <Object ?, Object ?>> {
383
- const _RouteMatchListEncoder ();
389
+ const _RouteMatchListEncoder (this .configuration);
390
+
391
+ final RouteConfiguration configuration;
384
392
@override
385
393
Map <Object ?, Object ?> convert (RouteMatchList input) {
386
394
final List <Map <Object ?, Object ?>> imperativeMatches = input.matches
@@ -394,15 +402,36 @@ class _RouteMatchListEncoder
394
402
imperativeMatches: imperativeMatches);
395
403
}
396
404
397
- static Map <Object ?, Object ?> _toPrimitives (String location, Object ? extra,
405
+ Map <Object ?, Object ?> _toPrimitives (String location, Object ? extra,
398
406
{List <Map <Object ?, Object ?>>? imperativeMatches, String ? pageKey}) {
399
- String ? encodedExtra;
400
- try {
401
- encodedExtra = json.encoder.convert (extra);
402
- } on JsonUnsupportedObjectError {/* give up if not serializable */ }
407
+ Map <String , Object ?> encodedExtra;
408
+ if (configuration.extraCodec != null ) {
409
+ encodedExtra = < String , Object ? > {
410
+ RouteMatchListCodec ._codecKey: RouteMatchListCodec ._customCodecName,
411
+ RouteMatchListCodec ._encodedKey:
412
+ configuration.extraCodec? .encode (extra),
413
+ };
414
+ } else {
415
+ String jsonEncodedExtra;
416
+ try {
417
+ jsonEncodedExtra = json.encoder.convert (extra);
418
+ } on JsonUnsupportedObjectError {
419
+ jsonEncodedExtra = json.encoder.convert (null );
420
+ log (
421
+ 'An extra with complex data type ${extra .runtimeType } is provided '
422
+ 'without a codec. Consider provide a codec to GoRouter to '
423
+ 'prevent extra being dropped during serialization.' ,
424
+ level: Level .WARNING );
425
+ }
426
+ encodedExtra = < String , Object ? > {
427
+ RouteMatchListCodec ._codecKey: RouteMatchListCodec ._jsonCodecName,
428
+ RouteMatchListCodec ._encodedKey: jsonEncodedExtra,
429
+ };
430
+ }
431
+
403
432
return < Object ? , Object ? > {
404
433
RouteMatchListCodec ._locationKey: location,
405
- if (encodedExtra != null ) RouteMatchListCodec ._extraKey: encodedExtra,
434
+ RouteMatchListCodec ._extraKey: encodedExtra,
406
435
if (imperativeMatches != null )
407
436
RouteMatchListCodec ._imperativeMatchesKey: imperativeMatches,
408
437
if (pageKey != null ) RouteMatchListCodec ._pageKey: pageKey,
@@ -420,13 +449,17 @@ class _RouteMatchListDecoder
420
449
RouteMatchList convert (Map <Object ?, Object ?> input) {
421
450
final String rootLocation =
422
451
input[RouteMatchListCodec ._locationKey]! as String ;
423
- final String ? encodedExtra =
424
- input[RouteMatchListCodec ._extraKey] as String ? ;
452
+ final Map < Object ?, Object ?> encodedExtra =
453
+ input[RouteMatchListCodec ._extraKey]! as Map < Object ?, Object ?> ;
425
454
final Object ? extra;
426
- if (encodedExtra != null ) {
427
- extra = json.decoder.convert (encodedExtra);
455
+
456
+ if (encodedExtra[RouteMatchListCodec ._codecKey] ==
457
+ RouteMatchListCodec ._jsonCodecName) {
458
+ extra = json.decoder
459
+ .convert (encodedExtra[RouteMatchListCodec ._encodedKey]! as String );
428
460
} else {
429
- extra = null ;
461
+ extra = configuration.extraCodec
462
+ ? .decode (encodedExtra[RouteMatchListCodec ._encodedKey]);
430
463
}
431
464
RouteMatchList matchList =
432
465
configuration.findMatch (rootLocation, extra: extra);
0 commit comments