Skip to content

Commit 912f243

Browse files
committed
action_sheet: Always confirm before unsubscribing from a channel
Fixes #1827. (That is, always confirm when unsubscribing via the action sheet -- I've added a test that we *don't* always confirm in the "All channels" page, since that could be annoying, as mentioned in the issue.)
1 parent dbea8ec commit 912f243

File tree

4 files changed

+38
-4
lines changed

4 files changed

+38
-4
lines changed

lib/widgets/actions.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,11 @@ abstract final class ZulipAction {
247247
///
248248
/// A confirmation dialog is shown if the user would not have permission
249249
/// to resubscribe.
250+
/// If [alwaysAsk] is true (the default),
251+
/// a confirmation dialog is shown unconditionally.
250252
static Future<void> unsubscribeFromChannel(BuildContext context, {
251253
required int channelId,
254+
bool alwaysAsk = true,
252255
}) async {
253256
final store = PerAccountStoreWidget.of(context);
254257
final subscription = store.subscriptions[channelId];
@@ -258,9 +261,9 @@ abstract final class ZulipAction {
258261
final couldResubscribe = !subscription.inviteOnly
259262
|| store.selfHasPermissionForGroupSetting(subscription.canSubscribeGroup,
260263
GroupSettingType.stream, 'can_subscribe_group');
264+
final zulipLocalizations = ZulipLocalizations.of(context);
261265
if (!couldResubscribe) {
262266
// TODO(#1788) warn if org would lose content access (nobody can subscribe)
263-
final zulipLocalizations = ZulipLocalizations.of(context);
264267

265268
final dialog = showSuggestedActionDialog(context: context,
266269
title: zulipLocalizations.unsubscribeConfirmationDialogTitle('#${subscription.name}'),
@@ -269,6 +272,12 @@ abstract final class ZulipAction {
269272
actionButtonText: zulipLocalizations.unsubscribeConfirmationDialogConfirmButton);
270273
if (await dialog.result != true) return;
271274
if (!context.mounted) return;
275+
} else if (alwaysAsk) {
276+
final dialog = showSuggestedActionDialog(context: context,
277+
title: zulipLocalizations.unsubscribeConfirmationDialogTitle('#${subscription.name}'),
278+
actionButtonText: zulipLocalizations.unsubscribeConfirmationDialogConfirmButton);
279+
if (await dialog.result != true) return;
280+
if (!context.mounted) return;
272281
}
273282

274283
try {

lib/widgets/all_channels.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ class _SubscribeToggle extends StatelessWidget {
139139
subscriptions: [channel.name]);
140140
} else {
141141
await ZulipAction.unsubscribeFromChannel(context,
142-
channelId: channel.streamId);
142+
channelId: channel.streamId,
143+
alwaysAsk: false);
143144
}
144145
},
145146
// TODO(#741) interpret API errors for user

test/widgets/action_sheet_test.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,9 +573,15 @@ void main() {
573573

574574
connection.prepare(json: {});
575575
await tapButton(tester);
576-
await tester.pump(Duration.zero);
576+
await tester.pump();
577577

578-
checkNoDialog(tester);
578+
final (unsubscribeButton, cancelButton) = checkSuggestedActionDialog(tester,
579+
expectedTitle: 'Unsubscribe from #${channel.name}?',
580+
expectDestructiveActionButton: false,
581+
expectedActionButtonText: 'Unsubscribe');
582+
await tester.tap(find.byWidget(unsubscribeButton));
583+
await tester.pump();
584+
await tester.pump(Duration.zero);
579585

580586
check(connection.lastRequest).isA<http.Request>()
581587
..method.equals('DELETE')

test/widgets/all_channels_test.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,24 @@ void main() {
241241
});
242242
});
243243

244+
testWidgets('Toggle "off" to unsubscribe, public channel', (tester) async {
245+
final channel = eg.stream(inviteOnly: false);
246+
final subscription = eg.subscription(channel);
247+
248+
await setupAllChannelsPage(tester, channels: [subscription]);
249+
250+
connection.prepare(json: {});
251+
await tester.tap(find.byType(Toggle));
252+
await tester.pump(Duration.zero);
253+
checkNoDialog(tester);
254+
check(connection.lastRequest).isA<http.Request>()
255+
..method.equals('DELETE')
256+
..url.path.equals('/api/v1/users/me/subscriptions')
257+
..bodyFields.deepEquals({
258+
'subscriptions': jsonEncode([channel.name]),
259+
});
260+
});
261+
244262
testWidgets('Toggle "off" to unsubscribe, but without resubscribe permission', (tester) async {
245263
final channel = eg.stream(
246264
inviteOnly: true, canSubscribeGroup: eg.groupSetting(members: []));

0 commit comments

Comments
 (0)