Skip to content

Commit cb94d4e

Browse files
committed
internal_link [nfc]: Propagate InternalLink up to caller
1 parent 17d822f commit cb94d4e

File tree

3 files changed

+38
-14
lines changed

3 files changed

+38
-14
lines changed

lib/model/internal_link.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,29 +125,33 @@ class NarrowLink extends InternalLink {
125125
final Narrow narrow;
126126
}
127127

128-
/// A [Narrow] from a given URL, on `store`'s realm.
128+
/// Try to parse the given URL as a page in this app, on `store`'s realm.
129129
///
130130
/// `url` must already be a result from [PerAccountStore.tryResolveUrl]
131131
/// on `store`.
132132
///
133-
/// Returns `null` if any of the operator/operand pairs are invalid.
133+
/// Returns null if the URL isn't on this realm,
134+
/// or isn't a valid Zulip URL,
135+
/// or isn't currently supported as leading to a page in this app.
134136
///
137+
/// In particular this will return null if `url` is a `/#narrow/…` URL
138+
/// and any of the operator/operand pairs are invalid.
135139
/// Since narrow links can combine operators in ways our [Narrow] type can't
136140
/// represent, this can also return null for valid narrow links.
137141
///
138142
/// This can also return null for some valid narrow links that our Narrow
139143
/// type *could* accurately represent. We should try to understand these
140-
/// better, but some kinds will be rare, even unheard-of:
144+
/// better, but some kinds will be rare, even unheard-of. For example:
141145
/// #narrow/stream/1-announce/stream/1-announce (duplicated operator)
142146
// TODO(#252): handle all valid narrow links, returning a search narrow
143-
Narrow? parseInternalLink(Uri url, PerAccountStore store) {
147+
InternalLink? parseInternalLink(Uri url, PerAccountStore store) {
144148
if (!_isInternalLink(url, store.realmUrl)) return null;
145149

146150
final (category, segments) = _getCategoryAndSegmentsFromFragment(url.fragment);
147151
switch (category) {
148152
case 'narrow':
149153
if (segments.isEmpty || !segments.length.isEven) return null;
150-
return _interpretNarrowSegments(segments, store)?.narrow;
154+
return _interpretNarrowSegments(segments, store);
151155
}
152156
return null;
153157
}

lib/widgets/content.dart

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,15 +1536,17 @@ void _launchUrl(BuildContext context, String urlString) async {
15361536
return;
15371537
}
15381538

1539-
final internalNarrow = parseInternalLink(url, store);
1540-
if (internalNarrow != null) {
1541-
unawaited(Navigator.push(context,
1542-
MessageListPage.buildRoute(context: context,
1543-
narrow: internalNarrow)));
1544-
return;
1539+
final internalLink = parseInternalLink(url, store);
1540+
assert(internalLink == null || internalLink.realmUrl == store.realmUrl);
1541+
switch (internalLink) {
1542+
case NarrowLink():
1543+
unawaited(Navigator.push(context,
1544+
MessageListPage.buildRoute(context: context,
1545+
narrow: internalLink.narrow)));
1546+
1547+
case null:
1548+
await PlatformActions.launchUrl(context, url);
15451549
}
1546-
1547-
await PlatformActions.launchUrl(context, url);
15481550
}
15491551

15501552
/// Like [Image.network], but includes [authHeader] if [src] is on-realm.

test/model/internal_link_test.dart

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,14 @@ void main() {
160160
test(urlString, () async {
161161
final store = await setupStore(realmUrl: realmUrl, streams: streams, users: users);
162162
final url = store.tryResolveUrl(urlString)!;
163-
check(parseInternalLink(url, store)).equals(expected);
163+
final result = parseInternalLink(url, store);
164+
if (expected == null) {
165+
check(result).isNull();
166+
} else {
167+
check(result).isA<NarrowLink>()
168+
..realmUrl.equals(realmUrl)
169+
..narrow.equals(expected);
170+
}
164171
});
165172
}
166173
}
@@ -258,6 +265,9 @@ void main() {
258265
final url = store.tryResolveUrl(urlString)!;
259266
final result = parseInternalLink(url, store);
260267
check(result != null).equals(expected);
268+
if (result != null) {
269+
check(result).realmUrl.equals(realmUrl);
270+
}
261271
});
262272
}
263273
}
@@ -564,3 +574,11 @@ void main() {
564574
});
565575
});
566576
}
577+
578+
extension InternalLinkChecks on Subject<InternalLink> {
579+
Subject<Uri> get realmUrl => has((x) => x.realmUrl, 'realmUrl');
580+
}
581+
582+
extension NarrowLinkChecks on Subject<NarrowLink> {
583+
Subject<Narrow> get narrow => has((x) => x.narrow, 'narrow');
584+
}

0 commit comments

Comments
 (0)