Skip to content

Commit 2c06248

Browse files
committed
action_sheet: Pass/use whole-page context in show{Message,Topic}ActionSheet
1 parent c2ef9de commit 2c06248

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

lib/widgets/action_sheet.dart

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,16 @@ class ActionSheetCancelButton extends StatelessWidget {
163163
}
164164

165165
/// Show a sheet of actions you can take on a topic.
166-
void showTopicActionSheet(BuildContext context, {
166+
///
167+
/// [pageContext] should be the context of the whole page in the nav,
168+
/// not of the specific element that was long-pressed.
169+
/// The long-pressed element live-updates on server events,
170+
/// so it might unmount before the action-sheet buttons have finished using it.
171+
void showTopicActionSheet(BuildContext pageContext, {
167172
required int channelId,
168173
required TopicName topic,
169174
}) {
170-
final store = PerAccountStoreWidget.of(context);
175+
final store = PerAccountStoreWidget.of(pageContext);
171176
final subscription = store.subscriptions[channelId];
172177

173178
final optionButtons = <ActionSheetMenuItemButton>[];
@@ -237,7 +242,7 @@ void showTopicActionSheet(BuildContext context, {
237242
currentVisibilityPolicy: visibilityPolicy,
238243
newVisibilityPolicy: to,
239244
narrow: TopicNarrow(channelId, topic),
240-
pageContext: context);
245+
pageContext: pageContext);
241246
}));
242247

243248
if (optionButtons.isEmpty) {
@@ -250,7 +255,7 @@ void showTopicActionSheet(BuildContext context, {
250255
return;
251256
}
252257

253-
_showActionSheet(context, optionButtons: optionButtons);
258+
_showActionSheet(pageContext, optionButtons: optionButtons);
254259
}
255260

256261
class UserTopicUpdateButton extends ActionSheetMenuItemButton {
@@ -390,6 +395,9 @@ void showMessageActionSheet({required BuildContext context, required Message mes
390395
final markAsUnreadSupported = store.connection.zulipFeatureLevel! >= 155; // TODO(server-6)
391396
final showMarkAsUnreadButton = markAsUnreadSupported && isMessageRead;
392397

398+
// TODO like in showTopicActionSheet, don't pass buttons a BuildContext
399+
// for live-updating UI that could unmount before it's finished being used.
400+
393401
final optionButtons = [
394402
ReactionButtons(message: message, pageContext: context),
395403
StarButton(message: message, pageContext: context),

lib/widgets/inbox.dart

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,34 @@ import 'text.dart';
1313
import 'theme.dart';
1414
import 'unread_count_badge.dart';
1515

16+
17+
/// The interface for the state of an [InboxPageBody].
18+
///
19+
/// To obtain one of these, see [InboxPageBody.ancestorOf].
20+
abstract class InboxPageState {
21+
BuildContext get context;
22+
}
23+
1624
class InboxPageBody extends StatefulWidget {
1725
const InboxPageBody({super.key});
1826

27+
/// The [InboxPageState] above this context in the tree.
28+
///
29+
/// Uses the inefficient [BuildContext.findAncestorStateOfType];
30+
/// don't call this in a build method.
31+
// If we do find ourselves wanting this in a build method, it won't be hard
32+
// to enable that: we'd just need to add an [InheritedWidget] here.
33+
static InboxPageState ancestorOf(BuildContext context) {
34+
final state = context.findAncestorStateOfType<_InboxPageState>();
35+
assert(state != null, 'No InboxPageBody ancestor');
36+
return state!;
37+
}
38+
1939
@override
2040
State<InboxPageBody> createState() => _InboxPageState();
2141
}
2242

23-
class _InboxPageState extends State<InboxPageBody> with PerAccountStoreAwareStateMixin<InboxPageBody> {
43+
class _InboxPageState extends State<InboxPageBody> with PerAccountStoreAwareStateMixin<InboxPageBody> implements InboxPageState {
2444
Unreads? unreadsModel;
2545
RecentDmConversationsView? recentDmConversationsModel;
2646

@@ -516,7 +536,8 @@ class _TopicItem extends StatelessWidget {
516536
Navigator.push(context,
517537
MessageListPage.buildRoute(context: context, narrow: narrow));
518538
},
519-
onLongPress: () => showTopicActionSheet(context,
539+
onLongPress: () => showTopicActionSheet(
540+
InboxPageBody.ancestorOf(context).context,
520541
channelId: streamId, topic: topic),
521542
child: ConstrainedBox(constraints: const BoxConstraints(minHeight: 34),
522543
child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [

lib/widgets/message_list.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ abstract class MessageListPageState {
183183
///
184184
/// This is null if [MessageList] has not mounted yet.
185185
MessageListView? get model;
186+
187+
BuildContext get context;
186188
}
187189

188190
class MessageListPage extends StatefulWidget {
@@ -400,7 +402,8 @@ class MessageListAppBarTitle extends StatelessWidget {
400402
width: double.infinity,
401403
child: GestureDetector(
402404
behavior: HitTestBehavior.translucent,
403-
onLongPress: () => showTopicActionSheet(context,
405+
onLongPress: () => showTopicActionSheet(
406+
MessageListPage.ancestorOf(context).context,
404407
channelId: streamId, topic: topic),
405408
child: Column(
406409
crossAxisAlignment: willCenterTitle ? CrossAxisAlignment.center
@@ -1112,7 +1115,8 @@ class StreamMessageRecipientHeader extends StatelessWidget {
11121115
onTap: () => Navigator.push(context,
11131116
MessageListPage.buildRoute(context: context,
11141117
narrow: TopicNarrow.ofMessage(message))),
1115-
onLongPress: () => showTopicActionSheet(context,
1118+
onLongPress: () => showTopicActionSheet(
1119+
MessageListPage.ancestorOf(context).context,
11161120
channelId: message.streamId, topic: topic),
11171121
child: ColoredBox(
11181122
color: backgroundColor,

0 commit comments

Comments
 (0)