Line data Source code
1 : import 'package:flutter/foundation.dart';
2 : import 'package:flutter/widgets.dart';
3 :
4 : import './utils.dart';
5 : import './beam_location.dart';
6 :
7 : /// A state for [BeamerDelegate] and [BeamLocation].
8 : ///
9 : /// Helps in building the pages and creates an URI.
10 : class BeamState {
11 9 : BeamState({
12 : this.pathBlueprintSegments = const <String>[],
13 : this.pathParameters = const <String, String>{},
14 : this.queryParameters = const <String, String>{},
15 : this.data = const <String, dynamic>{},
16 : }) {
17 9 : configure();
18 : }
19 :
20 : /// Creates a [BeamState] from given [uri] and optional [data].
21 : ///
22 : /// If [beamLocation] is given, then it will take into consideration
23 : /// its path blueprints to populate the [pathParameters] attribute.
24 : ///
25 : /// See [Utils.createBeamState].
26 9 : factory BeamState.fromUri(
27 : Uri uri, {
28 : BeamLocation? beamLocation,
29 : Map<String, dynamic> data = const <String, dynamic>{},
30 : }) {
31 9 : return Utils.createBeamState(
32 : uri,
33 : beamLocation: beamLocation,
34 : data: data,
35 : );
36 : }
37 :
38 : /// Creates a [BeamState] from given [uriString] and optional [data].
39 : ///
40 : /// If [beamLocation] is given, then it will take into consideration
41 : /// its path blueprints to populate the [pathParameters] attribute.
42 : ///
43 : /// See [BeamState.fromUri].
44 9 : factory BeamState.fromUriString(
45 : String uriString, {
46 : BeamLocation? beamLocation,
47 : Map<String, dynamic> data = const <String, dynamic>{},
48 : }) {
49 9 : uriString = Utils.trimmed(uriString);
50 9 : final uri = Uri.parse(uriString);
51 9 : return BeamState.fromUri(
52 : uri,
53 : beamLocation: beamLocation,
54 : data: data,
55 : );
56 : }
57 :
58 : /// Path segments of the current URI,
59 : /// in the form as it's defined in [BeamLocation.pathBlueprints].
60 : ///
61 : /// If current URI is '/books/1', this will be `['books', ':bookId']`.
62 : final List<String> pathBlueprintSegments;
63 :
64 : /// Path parameters from the URI,
65 : /// in the form as it's defined in [BeamLocation.pathBlueprints].
66 : ///
67 : /// If current URI is '/books/1', this will be `{'bookId': '1'}`.
68 : final Map<String, String> pathParameters;
69 :
70 : /// Query parameters of the current URI.
71 : ///
72 : /// If current URI is '/books?title=str', this will be `{'title': 'str'}`.
73 : final Map<String, String> queryParameters;
74 :
75 : /// Custom key/value data for arbitrary use.
76 : final Map<String, dynamic> data;
77 :
78 : late Uri _uriBlueprint;
79 :
80 : /// Current URI object in the "blueprint form",
81 : /// as it's defined in [BeamLocation.pathBlueprints].
82 : ///
83 : /// This is constructed from [pathBlueprintSegments] and [queryParameters].
84 : /// See more at [configure].
85 2 : Uri get uriBlueprint => _uriBlueprint;
86 :
87 : late Uri _uri;
88 :
89 : /// Current URI object in the "real form",
90 : /// as it should be shown in browser's URL bar.
91 : ///
92 : /// This is constructed from [pathBlueprintSegments] and [queryParameters],
93 : /// with the addition of replacing each pathBlueprintSegment of the form ':*'
94 : /// with a coresponding value from [pathParameters].
95 : ///
96 : /// See more at [configure].
97 18 : Uri get uri => _uri;
98 :
99 : /// Copies this with configuration for specific [BeamLocation].
100 8 : BeamState copyForLocation(BeamLocation beamLocation) {
101 8 : return Utils.createBeamState(
102 8 : uri,
103 : beamLocation: beamLocation,
104 8 : data: data,
105 : );
106 : }
107 :
108 : /// Returns a configured copy of this.
109 7 : BeamState copyWith({
110 : List<String>? pathBlueprintSegments,
111 : Map<String, String>? pathParameters,
112 : Map<String, String>? queryParameters,
113 : Map<String, dynamic>? data,
114 : }) =>
115 7 : BeamState(
116 : pathBlueprintSegments:
117 7 : pathBlueprintSegments ?? this.pathBlueprintSegments,
118 6 : pathParameters: pathParameters ?? this.pathParameters,
119 6 : queryParameters: queryParameters ?? this.queryParameters,
120 7 : data: data ?? this.data,
121 7 : )..configure();
122 :
123 : /// Constructs [uriBlueprint] and [uri].
124 9 : void configure() {
125 18 : _uriBlueprint = Uri(
126 27 : path: '/' + pathBlueprintSegments.join('/'),
127 24 : queryParameters: queryParameters.isEmpty ? null : queryParameters,
128 : );
129 18 : final pathSegments = List<String>.from(pathBlueprintSegments);
130 27 : for (int i = 0; i < pathSegments.length; i++) {
131 45 : if (pathSegments[i].isNotEmpty && pathSegments[i][0] == ':') {
132 10 : final key = pathSegments[i].substring(1);
133 10 : if (pathParameters.containsKey(key)) {
134 15 : pathSegments[i] = pathParameters[key]!;
135 : }
136 : }
137 : }
138 18 : _uri = Uri(
139 18 : path: '/' + pathSegments.join('/'),
140 24 : queryParameters: queryParameters.isEmpty ? null : queryParameters,
141 : );
142 : }
143 :
144 1 : @override
145 3 : int get hashCode => hashValues(uri, data);
146 :
147 6 : @override
148 : bool operator ==(Object other) {
149 4 : return other is BeamState &&
150 12 : other.uri == uri &&
151 12 : mapEquals(other.data, data);
152 : }
153 : }
|