Repository: zulip/zulip-flutter (language: dart)

Issue:
Make "All channels" view more similar to "Channels"

We should make the UI of the "All channels" view match the "Channels" view better:

- Click on the row should navigate to the channel.
- Long press should open the channel menu.
- Remove the `...` buttons, as users can follow the regular pattern of opening the menu with a long press when needed.


Discussion hints:
nan

Pull request: all_channels: Replace three dot menu with long press gesture and add on tap to feed
Fixes #1914

<details>
<summary>Before and After still </summary>

### Page View
| Before | After |
| --- | --- |
|<img width="360" height="1200" alt="Screenshot_1761912198" src="https://github.com/user-attachments/assets/3f03cc3c-0322-4a53-b140-e7de74c565a2" /> | <img width="360" height="1200" alt="Screenshot_1761912094" src="https://github.com/user-attachments/assets/793d4ca3-e6d5-421c-b8ba-4ac106d605a7" /> |



</details>

<details>
<summary>After Max Sys Font</summary>

| After Max Sys Font |
| --- |
<img width="360" height="1200" alt="Screenshot_1761913062" src="https://github.com/user-attachments/assets/45f80c63-158f-41a9-8656-560fc594bab7" />|

</details>

<details>
<summary>Long Press View</summary>

| Long Press on Public Channel |  ~~Long Press on Private Channel~~ Not part of this PR anymore |
| --- | --- |
| <img width="360" height="1200" alt="public-long" src="https://github.com/user-attachments/assets/59ec7506-3b76-4f55-b2fb-acc2e91df937" /> | <img width="360" height="1200" alt="private-long" src="https://github.com/user-attachments/assets/d9464281-b1ef-4bca-aef5-50da8125197f" /> |

</details>

<details>
<summary>Gesture Press Views</summary>

## Gesture press in default sys font  
https://github.com/user-attachments/assets/de182d27-9f3f-4304-8ffe-5856f0669f6b

## ~Unsub from private channel 200 milliseconds fade~. Not part of PR
https://github.com/user-attachments/assets/7f1b0f99-8ae5-47bf-8b05-764614e53a39
</details>

Test command: flutter test test/widgets/all_channels_test.dart --reporter expanded 2>&1

Fix patch:
diff --git a/lib/widgets/all_channels.dart b/lib/widgets/all_channels.dart
index 3aaf0d8baf..7d662bcc2d 100644
--- a/lib/widgets/all_channels.dart
+++ b/lib/widgets/all_channels.dart
@@ -5,11 +5,13 @@ import '../api/route/channels.dart';
 import '../generated/l10n/zulip_localizations.dart';
 import '../log.dart';
 import '../model/channel.dart';
+import '../model/narrow.dart';
 import 'action_sheet.dart';
 import 'actions.dart';
 import 'app_bar.dart';
 import 'button.dart';
 import 'icons.dart';
+import 'message_list.dart';
 import 'page.dart';
 import 'remote_settings.dart';
 import 'store.dart';
@@ -96,28 +98,30 @@ class AllChannelsListEntry extends StatelessWidget {
     final Subscription? subscription = channel is Subscription ? channel : null;
     final hasContentAccess = store.selfHasContentAccess(channel);
 
-    return Padding(
-      padding: EdgeInsetsDirectional.only(start: 8, end: 4),
-      child: Row(spacing: 6, children: [
-        Icon(
-          size: 20,
-          color: colorSwatchFor(context, subscription).iconOnPlainBackground,
-          iconDataForStream(channel)),
-        Expanded(
-          child: Text(
-            style: TextStyle(
-              color: designVariables.textMessage,
-              fontSize: 17,
-              height: 20 / 17,
-            ).merge(weightVariableTextStyle(context, wght: 600)),
-            channel.name)),
-        if (hasContentAccess) _SubscribeToggle(channel: channel),
-        ZulipIconButton(
-          icon: ZulipIcons.more_horizontal,
-          onPressed: () {
-            showChannelActionSheet(context, channelId: channel.streamId);
-          }),
-      ]));
+    return InkWell(
+      onTap: !hasContentAccess ? null : () => Navigator.push(context,
+        MessageListPage.buildRoute(context: context,
+          narrow: ChannelNarrow(channel.streamId))),
+      onLongPress: () => showChannelActionSheet(context, channelId: channel.streamId),
+      child: ConstrainedBox(constraints: const BoxConstraints(minHeight: 44),
+        child: Padding(padding: const EdgeInsetsDirectional.only(start: 8, end: 12),
+          child: Row(spacing: 6, children: [
+            Icon(
+              size: 20,
+              color: colorSwatchFor(context, subscription).iconOnPlainBackground,
+              iconDataForStream(channel)),
+            Expanded(
+              child: Text(
+                maxLines: 1,
+                overflow: TextOverflow.ellipsis,
+                style: TextStyle(
+                  color: designVariables.textMessage,
+                  fontSize: 17,
+                  height: 20 / 17,
+                ).merge(weightVariableTextStyle(context, wght: 600)),
+                channel.name)),
+            if (hasContentAccess) _SubscribeToggle(channel: channel),
+          ]))));
   }
 }
 


Test patch:
diff --git a/test/widgets/all_channels_test.dart b/test/widgets/all_channels_test.dart
index b47546be40..f6e1092781 100644
--- a/test/widgets/all_channels_test.dart
+++ b/test/widgets/all_channels_test.dart
@@ -12,6 +12,7 @@ import 'package:zulip/widgets/app_bar.dart';
 import 'package:zulip/widgets/button.dart';
 import 'package:zulip/widgets/home.dart';
 import 'package:zulip/widgets/icons.dart';
+import 'package:zulip/widgets/message_list.dart';
 import 'package:zulip/widgets/page.dart';
 import 'package:zulip/widgets/remote_settings.dart';
 import 'package:zulip/widgets/theme.dart';
@@ -203,20 +204,37 @@ void main() {
         check(maybeToggle).isNull();
       }
 
-      check(findInRow(find.byIcon(ZulipIcons.more_horizontal))).findsOne();
+      final touchTargetSize = tester.getSize(findElement);
+      check(touchTargetSize.height).equals(44);
     }
   });
 
-  testWidgets('tapping three-dots button opens channel action sheet', (tester) async {
+  testWidgets('open channel action sheet on long press', (tester) async {
     await setupAllChannelsPage(tester, channels: [eg.stream()]);
 
-    await tester.tap(find.byIcon(ZulipIcons.more_horizontal));
+    await tester.longPress(find.byType(AllChannelsListEntry));
     await tester.pump();
     await transitionDurationObserver.pumpPastTransition(tester);
 
     check(find.byType(BottomSheet)).findsOne();
   });
 
+  testWidgets('navigate to channel feed on tap', (tester) async {
+    final channel = eg.stream(name: 'some-channel');
+    await setupAllChannelsPage(tester, channels: [channel]);
+
+    connection.prepare(json: eg.newestGetMessagesResult(
+      foundOldest: true, messages: [eg.streamMessage(stream: channel)]).toJson());
+    await tester.tap(find.byType(AllChannelsListEntry));
+    await tester.pump();
+    await transitionDurationObserver.pumpPastTransition(tester);
+
+    check(find.descendant(
+      of: find.byType(MessageListPage),
+      matching: find.text('some-channel')),
+    ).findsOne();
+  });
+
   testWidgets('use toggle switch to subscribe/unsubscribe', (tester) async {
     final channel = eg.stream();
     await setupAllChannelsPage(tester, channels: [channel]);