Skip to content

Commit 1f208c3

Browse files
committed
compose: Have narrowLink take an optional nearMessageId
1 parent f4ec6a1 commit 1f208c3

File tree

2 files changed

+39
-8
lines changed

2 files changed

+39
-8
lines changed

lib/model/compose.dart

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,22 @@ String encodeHashComponent(String str) {
120120
}
121121

122122
/// A URL to the given [Narrow], on `store`'s realm.
123-
Uri narrowLink(PerAccountStore store, Narrow narrow) {
123+
///
124+
/// To include /near/{messageId} in the link, pass a non-null [nearMessageId].
125+
// Why take [nearMessageId] in a param, instead of looking for it in [narrow]?
126+
//
127+
// A reasonable question: after all, the "near" part of a near link (e.g., for
128+
// quote-and-reply) does take the same form as other operator/operand pairs
129+
// that we represent with [ApiNarrowElement]s, like "/stream/48-mobile".
130+
//
131+
// But unlike those other elements, we choose not to give the "near" element
132+
// an [ApiNarrowElement] representation, because it doesn't have quite that role:
133+
// it says where to look in a list of messages, but it doesn't filter the list down.
134+
// In fact, from a brief look at server code, it seems to be *ignored*
135+
// if you include it in the `narrow` param in get-messages requests.
136+
// When you want to point the server to a location in a message list, you
137+
// you do so by passing the `anchor` param.
138+
Uri narrowLink(PerAccountStore store, Narrow narrow, {int? nearMessageId}) {
124139
final apiNarrow = narrow.apiEncode();
125140
final fragment = StringBuffer('narrow');
126141
for (ApiNarrowElement element in apiNarrow) {
@@ -156,8 +171,10 @@ Uri narrowLink(PerAccountStore store, Narrow narrow) {
156171
fragment.write(element.operand.toString());
157172
}
158173
}
174+
175+
if (nearMessageId != null) {
176+
fragment.write('/near/$nearMessageId');
177+
}
178+
159179
return store.account.realmUrl.replace(fragment: fragment.toString());
160180
}
161-
162-
// TODO more, like /near links to messages in conversations
163-
// (also to be used in quote-and-reply)

test/model/compose_test.dart

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,22 +195,27 @@ hello
195195
group('narrowLink', () {
196196
test('AllMessagesNarrow', () {
197197
final store = eg.store();
198-
check(narrowLink(store, const AllMessagesNarrow())).equals(store.account.realmUrl.resolve('#narrow'));
198+
check(narrowLink(store, const AllMessagesNarrow()))
199+
.equals(store.account.realmUrl.resolve('#narrow'));
200+
check(narrowLink(store, const AllMessagesNarrow(), nearMessageId: 1))
201+
.equals(store.account.realmUrl.resolve('#narrow/near/1'));
199202
});
200203

201204
test('StreamNarrow / TopicNarrow', () {
202205
void checkNarrow(String expectedFragment, {
203206
required int streamId,
204207
required String name,
205208
String? topic,
209+
int? nearMessageId,
206210
}) {
207211
assert(expectedFragment.startsWith('#'), 'wrong-looking expectedFragment');
208212
final store = eg.store();
209213
store.addStream(eg.stream(streamId: streamId, name: name));
210214
final narrow = topic == null
211215
? StreamNarrow(streamId)
212216
: TopicNarrow(streamId, topic);
213-
check(narrowLink(store, narrow)).equals(store.account.realmUrl.resolve(expectedFragment));
217+
check(narrowLink(store, narrow, nearMessageId: nearMessageId))
218+
.equals(store.account.realmUrl.resolve(expectedFragment));
214219
}
215220

216221
checkNarrow(streamId: 1, name: 'announce', '#narrow/stream/1-announce');
@@ -219,26 +224,32 @@ hello
219224
checkNarrow(streamId: 415, name: 'chat.zulip.org', '#narrow/stream/415-chat.2Ezulip.2Eorg');
220225
checkNarrow(streamId: 419, name: 'français', '#narrow/stream/419-fran.C3.A7ais');
221226
checkNarrow(streamId: 403, name: 'Hshs[™~}(.', '#narrow/stream/403-Hshs.5B.E2.84.A2~.7D.28.2E');
227+
checkNarrow(streamId: 60, name: 'twitter', nearMessageId: 1570686, '#narrow/stream/60-twitter/near/1570686');
222228

223229
checkNarrow(streamId: 48, name: 'mobile', topic: 'Welcome screen UI',
224230
'#narrow/stream/48-mobile/topic/Welcome.20screen.20UI');
225231
checkNarrow(streamId: 243, name: 'mobile-team', topic: 'Podfile.lock clash #F92',
226232
'#narrow/stream/243-mobile-team/topic/Podfile.2Elock.20clash.20.23F92');
227233
checkNarrow(streamId: 377, name: 'translation/zh_tw', topic: '翻譯 "stream"',
228234
'#narrow/stream/377-translation.2Fzh_tw/topic/.E7.BF.BB.E8.AD.AF.20.22stream.22');
235+
checkNarrow(streamId: 42, name: 'Outreachy 2016-2017', topic: '2017-18 Stream?', nearMessageId: 302690,
236+
'#narrow/stream/42-Outreachy-2016-2017/topic/2017-18.20Stream.3F/near/302690');
229237
});
230238

231239
test('DmNarrow', () {
232240
void checkNarrow(String expectedFragment, String legacyExpectedFragment, {
233241
required List<int> allRecipientIds,
234242
required int selfUserId,
243+
int? nearMessageId,
235244
}) {
236245
assert(expectedFragment.startsWith('#'), 'wrong-looking expectedFragment');
237246
final store = eg.store();
238247
final narrow = DmNarrow(allRecipientIds: allRecipientIds, selfUserId: selfUserId);
239-
check(narrowLink(store, narrow)).equals(store.account.realmUrl.resolve(expectedFragment));
248+
check(narrowLink(store, narrow, nearMessageId: nearMessageId))
249+
.equals(store.account.realmUrl.resolve(expectedFragment));
240250
store.connection.zulipFeatureLevel = 176;
241-
check(narrowLink(store, narrow)).equals(store.account.realmUrl.resolve(legacyExpectedFragment));
251+
check(narrowLink(store, narrow, nearMessageId: nearMessageId))
252+
.equals(store.account.realmUrl.resolve(legacyExpectedFragment));
242253
}
243254

244255
checkNarrow(allRecipientIds: [1], selfUserId: 1,
@@ -253,6 +264,9 @@ hello
253264
checkNarrow(allRecipientIds: [1, 2, 3, 4], selfUserId: 4,
254265
'#narrow/dm/1,2,3,4-group',
255266
'#narrow/pm-with/1,2,3,4-group');
267+
checkNarrow(allRecipientIds: [1, 2], selfUserId: 1, nearMessageId: 12345,
268+
'#narrow/dm/1,2-dm/near/12345',
269+
'#narrow/pm-with/1,2-pm/near/12345');
256270
});
257271

258272
// TODO other Narrow subclasses as we add them:

0 commit comments

Comments
 (0)