Skip to content

Commit 3c3dd16

Browse files
authored
feat(ui, localization): Add confirmation dialog for end vote in Polls (#2237)
Co-authored-by: xsahil03x <25670178+xsahil03x@users.noreply.github.com>
1 parent c91d86d commit 3c3dd16

21 files changed

+301
-5
lines changed

packages/stream_chat_flutter/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Added support for Draft messages preview.
66
- Added a new `StreamDraftListView` for displaying draft messages.
7+
- Added a confirmation dialog for end vote in Polls. [[#2211]](https://github.com/GetStream/stream-chat-flutter/issues/2211)
78

89
🔄 Changed
910

packages/stream_chat_flutter/lib/src/localization/translations.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,9 +443,15 @@ abstract class Translations {
443443
/// The label for "Enter your comment".
444444
String get enterYourCommentLabel;
445445

446+
/// The confirmation text shown when the user tries to end a poll.
447+
String get endVoteConfirmationText;
448+
446449
/// The label for "Create".
447450
String get createLabel;
448451

452+
/// The label for "End".
453+
String get endLabel;
454+
449455
/// The label for Poll voting mode.
450456
///
451457
/// Returns different labels based on the [votingMode].
@@ -1096,9 +1102,16 @@ Attachment limit exceeded: it's not possible to add more than $limit attachments
10961102
@override
10971103
String get enterYourCommentLabel => 'Enter your comment';
10981104

1105+
@override
1106+
String get endVoteConfirmationText =>
1107+
'Are you sure you want to end the vote?';
1108+
10991109
@override
11001110
String get createLabel => 'Create';
11011111

1112+
@override
1113+
String get endLabel => 'End';
1114+
11021115
@override
11031116
String pollVotingModeLabel(PollVotingMode votingMode) {
11041117
return votingMode.when(

packages/stream_chat_flutter/lib/src/message_widget/poll_message.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:flutter/material.dart';
22
import 'package:stream_chat_flutter/src/misc/empty_widget.dart';
33
import 'package:stream_chat_flutter/src/poll/interactor/poll_add_comment_dialog.dart';
4+
import 'package:stream_chat_flutter/src/poll/interactor/poll_end_vote_dialog.dart';
45
import 'package:stream_chat_flutter/src/poll/interactor/poll_suggest_option_dialog.dart';
56
import 'package:stream_chat_flutter/src/poll/interactor/stream_poll_interactor.dart';
67
import 'package:stream_chat_flutter/src/poll/stream_poll_comments_dialog.dart';
@@ -67,6 +68,13 @@ class _PollMessageState extends State<PollMessage> {
6768

6869
final channel = StreamChannel.of(context).channel;
6970

71+
Future<void> onEndVote() async {
72+
final confirm = await showPollEndVoteDialog(context: context);
73+
if (confirm == null || !confirm) return;
74+
75+
channel.closePoll(poll).ignore();
76+
}
77+
7078
Future<void> onAddComment() async {
7179
final commentText = await showPollAddCommentDialog(
7280
context: context,
@@ -94,7 +102,7 @@ class _PollMessageState extends State<PollMessage> {
94102
poll: poll,
95103
currentUser: currentUser,
96104
visibleOptionCount: _maxVisibleOptionCount,
97-
onEndVote: () => channel.closePoll(poll),
105+
onEndVote: onEndVote,
98106
onCastVote: (option) => channel.castPollVote(message, poll, option),
99107
onRemoveVote: (vote) => channel.removePollVote(message, poll, vote),
100108
onAddComment: onAddComment,
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:stream_chat_flutter/src/theme/poll_interactor_theme.dart';
3+
import 'package:stream_chat_flutter/src/theme/stream_chat_theme.dart';
4+
import 'package:stream_chat_flutter/src/utils/extensions.dart';
5+
6+
/// {@template showPollSuggestOptionDialog}
7+
/// Shows a dialog that allows the user to end vote for a poll.
8+
/// {@endtemplate}
9+
Future<bool?> showPollEndVoteDialog({
10+
required BuildContext context,
11+
}) {
12+
return showDialog<bool?>(
13+
context: context,
14+
builder: (_) => const PollEndVoteDialog(),
15+
);
16+
}
17+
18+
/// {@template pollEndVoteDialog}
19+
/// A dialog that allows the user to end vote for a poll.
20+
/// {@endtemplate}
21+
class PollEndVoteDialog extends StatelessWidget {
22+
/// {@macro pollEndVoteDialog}
23+
const PollEndVoteDialog({super.key});
24+
25+
@override
26+
Widget build(BuildContext context) {
27+
final theme = StreamChatTheme.of(context);
28+
final pollInteractorTheme = StreamPollInteractorTheme.of(context);
29+
30+
final actions = [
31+
TextButton(
32+
onPressed: () => Navigator.of(context).maybePop(false),
33+
style: TextButton.styleFrom(
34+
textStyle: theme.textTheme.headlineBold,
35+
foregroundColor: theme.colorTheme.accentPrimary,
36+
disabledForegroundColor: theme.colorTheme.disabled,
37+
),
38+
child: Text(context.translations.cancelLabel.toUpperCase()),
39+
),
40+
TextButton(
41+
onPressed: () => Navigator.of(context).maybePop(true),
42+
style: TextButton.styleFrom(
43+
textStyle: theme.textTheme.headlineBold,
44+
foregroundColor: theme.colorTheme.accentPrimary,
45+
disabledForegroundColor: theme.colorTheme.disabled,
46+
),
47+
child: Text(context.translations.endLabel.toUpperCase()),
48+
),
49+
];
50+
51+
return AlertDialog(
52+
title: Text(
53+
context.translations.endVoteConfirmationText,
54+
style: pollInteractorTheme.pollActionDialogTitleStyle,
55+
),
56+
actions: actions,
57+
titlePadding: const EdgeInsets.symmetric(vertical: 14, horizontal: 16),
58+
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
59+
contentPadding: const EdgeInsets.all(16),
60+
actionsPadding: const EdgeInsets.all(8),
61+
backgroundColor: theme.colorTheme.appBg,
62+
);
63+
}
64+
}
2.24 KB
Loading
2.27 KB
Loading
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// ignore_for_file: lines_longer_than_80_chars
2+
3+
import 'package:alchemist/alchemist.dart';
4+
import 'package:flutter/material.dart';
5+
import 'package:flutter_test/flutter_test.dart';
6+
import 'package:stream_chat_flutter/src/poll/interactor/poll_end_vote_dialog.dart';
7+
import 'package:stream_chat_flutter/src/theme/stream_chat_theme.dart';
8+
9+
void main() {
10+
group('showPollEndVoteDialog', () {
11+
testWidgets(
12+
"returns 'True' when 'End' button is pressed",
13+
(tester) async {
14+
bool? value;
15+
16+
await tester.pumpWidget(
17+
_wrapWithMaterialApp(
18+
Builder(
19+
builder: (context) => Center(
20+
child: TextButton(
21+
onPressed: () async {
22+
value = await showPollEndVoteDialog(context: context);
23+
},
24+
child: const Text('End Vote'),
25+
),
26+
),
27+
),
28+
),
29+
);
30+
31+
await tester.tap(find.text('End Vote'));
32+
await tester.pumpAndSettle();
33+
34+
await tester.tap(find.text('END'));
35+
await tester.pumpAndSettle();
36+
37+
expect(value, isTrue);
38+
},
39+
);
40+
41+
testWidgets(
42+
"returns 'False' when 'Cancel' button is pressed",
43+
(tester) async {
44+
bool? value;
45+
46+
await tester.pumpWidget(
47+
_wrapWithMaterialApp(
48+
Builder(
49+
builder: (context) => Center(
50+
child: TextButton(
51+
onPressed: () async {
52+
value = await showPollEndVoteDialog(context: context);
53+
},
54+
child: const Text('End Vote'),
55+
),
56+
),
57+
),
58+
),
59+
);
60+
61+
await tester.tap(find.text('End Vote'));
62+
await tester.pumpAndSettle();
63+
64+
await tester.tap(find.text('CANCEL'));
65+
await tester.pumpAndSettle();
66+
67+
expect(value, isFalse);
68+
},
69+
);
70+
71+
testWidgets(
72+
"returns 'null' when dialog is dismissed",
73+
(tester) async {
74+
bool? value;
75+
76+
await tester.pumpWidget(
77+
_wrapWithMaterialApp(
78+
Builder(
79+
builder: (context) => Center(
80+
child: TextButton(
81+
onPressed: () async {
82+
value = await showPollEndVoteDialog(context: context);
83+
},
84+
child: const Text('End Vote'),
85+
),
86+
),
87+
),
88+
),
89+
);
90+
91+
await tester.tap(find.text('End Vote'));
92+
await tester.pumpAndSettle();
93+
94+
await tester.tapAt(Offset.zero);
95+
96+
expect(value, isNull);
97+
},
98+
);
99+
});
100+
101+
for (final brightness in Brightness.values) {
102+
goldenTest(
103+
'[${brightness.name}] -> PollEndVoteDialog looks fine',
104+
fileName: 'poll_end_vote_dialog_${brightness.name}',
105+
constraints: const BoxConstraints.tightFor(width: 400, height: 200),
106+
builder: () => _wrapWithMaterialApp(
107+
brightness: brightness,
108+
const PollEndVoteDialog(),
109+
),
110+
);
111+
}
112+
}
113+
114+
Widget _wrapWithMaterialApp(
115+
Widget widget, {
116+
Brightness? brightness,
117+
}) {
118+
return StreamChatTheme(
119+
data: StreamChatThemeData(brightness: brightness),
120+
child: MaterialApp(
121+
home: widget,
122+
),
123+
);
124+
}

packages/stream_chat_localizations/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
## Upcoming
22

33
- Added translations for new `draftLabel` label.
4+
- Added translations for new `endLabel` label.
5+
- Added translations for new `endVoteConfirmationText` text.
46

57
## 9.8.0
68

packages/stream_chat_localizations/example/lib/add_new_lang.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,9 +577,16 @@ class NnStreamChatLocalizations extends GlobalStreamChatLocalizations {
577577
@override
578578
String get enterYourCommentLabel => 'Enter your comment';
579579

580+
@override
581+
String get endVoteConfirmationText =>
582+
'Are you sure you want to end the poll?';
583+
580584
@override
581585
String get createLabel => 'Create';
582586

587+
@override
588+
String get endLabel => 'End';
589+
583590
@override
584591
String pollVotingModeLabel(PollVotingMode votingMode) {
585592
return votingMode.when(

packages/stream_chat_localizations/lib/src/stream_chat_localizations_ca.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,11 +556,18 @@ class StreamChatLocalizationsCa extends GlobalStreamChatLocalizations {
556556
String get updateYourCommentLabel => 'Actualitzar el vostre comentari';
557557

558558
@override
559-
String get enterYourCommentLabel => 'Introduïu el vostre comentari';
559+
String get enterYourCommentLabel => 'Introdueix el teu comentari';
560+
561+
@override
562+
String get endVoteConfirmationText =>
563+
'Estàs segur que vols finalitzar la votació?';
560564

561565
@override
562566
String get createLabel => 'Crear';
563567

568+
@override
569+
String get endLabel => 'Finalitzar';
570+
564571
@override
565572
String pollVotingModeLabel(PollVotingMode votingMode) {
566573
return votingMode.when(

0 commit comments

Comments
 (0)