@@ -109,6 +109,23 @@ Uri narrowLink(PerAccountStore store, Narrow narrow, {int? nearMessageId}) {
109
109
return result;
110
110
}
111
111
112
+ /// The result of parsing some URL within a Zulip realm,
113
+ /// when the URL corresponds to some page in this app.
114
+ sealed class InternalLink {
115
+ InternalLink ({required this .realmUrl});
116
+
117
+ final Uri realmUrl;
118
+ }
119
+
120
+ /// The result of parsing some URL that points to a narrow on a Zulip realm,
121
+ /// when the narrow is of a type that this app understands.
122
+ class NarrowLink extends InternalLink {
123
+ NarrowLink (this .narrow, this .nearMessageId, {required super .realmUrl});
124
+
125
+ final Narrow narrow;
126
+ final int ? nearMessageId;
127
+ }
128
+
112
129
/// A [Narrow] from a given URL, on `store` 's realm.
113
130
///
114
131
/// `url` must already be a result from [PerAccountStore.tryResolveUrl]
@@ -124,7 +141,7 @@ Uri narrowLink(PerAccountStore store, Narrow narrow, {int? nearMessageId}) {
124
141
/// better, but some kinds will be rare, even unheard-of:
125
142
/// #narrow/stream/1-announce/stream/1-announce (duplicated operator)
126
143
// TODO(#252): handle all valid narrow links, returning a search narrow
127
- Narrow ? parseInternalLink (Uri url, PerAccountStore store) {
144
+ InternalLink ? parseInternalLink (Uri url, PerAccountStore store) {
128
145
if (! _isInternalLink (url, store.realmUrl)) return null ;
129
146
130
147
final (category, segments) = _getCategoryAndSegmentsFromFragment (url.fragment);
@@ -155,7 +172,7 @@ bool _isInternalLink(Uri url, Uri realmUrl) {
155
172
return (category, segments);
156
173
}
157
174
158
- Narrow ? _interpretNarrowSegments (List <String > segments, PerAccountStore store) {
175
+ NarrowLink ? _interpretNarrowSegments (List <String > segments, PerAccountStore store) {
159
176
assert (segments.isNotEmpty);
160
177
assert (segments.length.isEven);
161
178
@@ -164,6 +181,7 @@ Narrow? _interpretNarrowSegments(List<String> segments, PerAccountStore store) {
164
181
ApiNarrowDm ? dmElement;
165
182
ApiNarrowWith ? withElement;
166
183
Set <IsOperand > isElementOperands = {};
184
+ int ? nearMessageId;
167
185
168
186
for (var i = 0 ; i < segments.length; i += 2 ) {
169
187
final (operator , negated) = _parseOperator (segments[i]);
@@ -201,24 +219,26 @@ Narrow? _interpretNarrowSegments(List<String> segments, PerAccountStore store) {
201
219
// It is fine to have duplicates of the same [IsOperand].
202
220
isElementOperands.add (IsOperand .fromRawString (operand));
203
221
204
- case _NarrowOperator .near: // TODO(#82): support for near
205
- continue ;
222
+ case _NarrowOperator .near:
223
+ if (nearMessageId != null ) return null ;
224
+ nearMessageId = int .tryParse (operand, radix: 10 );
206
225
207
226
case _NarrowOperator .unknown:
208
227
return null ;
209
228
}
210
229
}
211
230
231
+ final Narrow ? narrow;
212
232
if (isElementOperands.isNotEmpty) {
213
233
if (streamElement != null || topicElement != null || dmElement != null || withElement != null ) {
214
234
return null ;
215
235
}
216
236
if (isElementOperands.length > 1 ) return null ;
217
237
switch (isElementOperands.single) {
218
238
case IsOperand .mentioned:
219
- return const MentionsNarrow ();
239
+ narrow = const MentionsNarrow ();
220
240
case IsOperand .starred:
221
- return const StarredMessagesNarrow ();
241
+ narrow = const StarredMessagesNarrow ();
222
242
case IsOperand .dm:
223
243
case IsOperand .private:
224
244
case IsOperand .alerted:
@@ -230,17 +250,20 @@ Narrow? _interpretNarrowSegments(List<String> segments, PerAccountStore store) {
230
250
}
231
251
} else if (dmElement != null ) {
232
252
if (streamElement != null || topicElement != null || withElement != null ) return null ;
233
- return DmNarrow .withUsers (dmElement.operand, selfUserId: store.selfUserId);
253
+ narrow = DmNarrow .withUsers (dmElement.operand, selfUserId: store.selfUserId);
234
254
} else if (streamElement != null ) {
235
255
final streamId = streamElement.operand;
236
256
if (topicElement != null ) {
237
- return TopicNarrow (streamId, topicElement.operand, with_: withElement? .operand);
257
+ narrow = TopicNarrow (streamId, topicElement.operand, with_: withElement? .operand);
238
258
} else {
239
259
if (withElement != null ) return null ;
240
- return ChannelNarrow (streamId);
260
+ narrow = ChannelNarrow (streamId);
241
261
}
262
+ } else {
263
+ return null ;
242
264
}
243
- return null ;
265
+
266
+ return NarrowLink (narrow, nearMessageId, realmUrl: store.realmUrl);
244
267
}
245
268
246
269
@JsonEnum (fieldRename: FieldRename .kebab, alwaysCreate: true )
0 commit comments