diff --git a/packages/go_router/lib/src/route_data.dart b/packages/go_router/lib/src/route_data.dart index 373efcb1d0cb..1d156afca729 100644 --- a/packages/go_router/lib/src/route_data.dart +++ b/packages/go_router/lib/src/route_data.dart @@ -620,11 +620,42 @@ class NoOpPage extends Page { throw UnsupportedError('Should never be called'); } +/// Signature of custom query parameter encoding. +/// +/// The function takes a parameter value of type `T` and returns a string +/// representation suitable for use in a URI. The returned string is escaped to +/// be URL-safe. +/// +/// For example, a parameter value of `'field with space'` will generate a query +/// parameter value of `'field+with+space'`. +typedef QueryParameterEncoder = String Function(T value); + +/// Signature for custom query parameter decoding functions. +/// +/// Converts an encoded string from the URI into a parameter value of type `T`. +/// +/// The [value] parameter contains the encoded string from the URI. if the +/// parameter is absent from the URI. +typedef QueryParameterDecoder = T Function(String value); + /// Annotation to override the URI name for a route parameter. +@optionalTypeArgs @Target({TargetKind.parameter}) -class TypedQueryParameter { +class TypedQueryParameter { /// Annotation to override the URI name for a route parameter. - const TypedQueryParameter({this.name}); + const TypedQueryParameter({ + this.name, + this.encoder, + this.decoder, + this.compare, + }) : assert( + (encoder == null) == (decoder == null), + 'encoder and decoder must both be provided together', + ), + assert( + compare == null || encoder != null, + 'compare function requires an encoder to be provided', + ); /// The name of the parameter in the URI. /// @@ -647,4 +678,26 @@ class TypedQueryParameter { /// It is escaped to be URL-safe. For example `'field with space'` will /// generate a query parameter named `'field+with+space'`. final String? name; + + /// A function that converts a parameter value to a string for use in the URI. + /// + /// See [QueryParameterEncoder] for details. + final QueryParameterEncoder? encoder; + + /// A function that converts a string from the URI to a parameter value. + /// + /// See [QueryParameterDecoder] for details. + final QueryParameterDecoder? decoder; + + /// A function that determines if two parameter values differ. + /// + /// Returns `true` when the values differ and `false` when they match. + /// + /// Used to decide whether to include a parameter in the URI when a default + /// value exists. If the parameter equals its default value, it is omitted + /// from the URI; otherwise, it is included. + /// + /// This should be provided if the parameter has a default value and is is not + /// a primitive type. + final bool Function(T, T)? compare; } diff --git a/packages/go_router/pending_changelogs/support_custom_types.yaml b/packages/go_router/pending_changelogs/support_custom_types.yaml new file mode 100644 index 000000000000..40240bfcae31 --- /dev/null +++ b/packages/go_router/pending_changelogs/support_custom_types.yaml @@ -0,0 +1,3 @@ +changelog: | + - Adds `encoder`, `decoder` and `compare` parameters to `TypedQueryParameter` annotation for custom encoding, decoding and comparison of query parameters in `TypedGoRoute` constructors. +version: minor diff --git a/packages/go_router/test/route_data_test.dart b/packages/go_router/test/route_data_test.dart index a6a81b385762..9a0089080e0f 100644 --- a/packages/go_router/test/route_data_test.dart +++ b/packages/go_router/test/route_data_test.dart @@ -259,6 +259,10 @@ final List _relativeRoutes = [ ), ]; +String _coder(String? value) => ''; + +bool _compare(String a, String b) => true; + void main() { group('GoRouteData', () { testWidgets('It should build the page from the overridden build method', ( @@ -796,8 +800,23 @@ void main() { }); test('TypedQueryParameter stores the name', () { - const parameter = TypedQueryParameter(name: 'customName'); + const TypedQueryParameter parameter = TypedQueryParameter( + name: 'customName', + ); expect(parameter.name, 'customName'); }); + + test('TypedQueryParameter stores the encoder, decoder and compare', () { + const TypedQueryParameter parameter = TypedQueryParameter( + name: 'customName', + encoder: _coder, + decoder: _coder, + compare: _compare, + ); + + expect(parameter.encoder, _coder); + expect(parameter.decoder, _coder); + expect(parameter.compare, _compare); + }); }