How can i remove the detail disclosure icon/area from a List using ForEachStore in SwiftUI

I am new to the TCA world and I am trying to build a list that has a NavigationLink for opening a detail view. Now by default SwiftUI puts the detail disclosure item (chevron right icon) which can be removed using different techniques in vanilla SwiftUI, I used to tackle this issue by adding .opacity(0) to the NavigationList inside a ZStack, but I am unable to figure out how to remove it using NavigationLink inside a ForEachStore?

Hi @saifullahsajid, I believe that whatever tricks you use in vanilla SwiftUI to hide the chevron would equally apply to TCA. Can you share some code to show us what the vanilla SwiftUI code looks like and why it is not working in TCA?

Here is how I did it in vanilla SwiftUI. This is a pretty old snippet btw.

List {
    ForEach(self.conversations, id: \.id) { conversation in
        ZStack {
            ChatsListView()
            NavigationLink(destination: MessagesView() {
                EmptyView()
            }.opacity(0)
        }
    }
    .listRowBackground(Colors.primary)
    .listRowSeparator(.hidden)
}
.listStyle(.plain)

Hi @saifullahsajid, I would expect that technique to work just as well in TCA. What troubles did you have?

Alright so here goes my current implementation of the List:

List {
    ForEachStore(
        self.store.scope(
            state: { $0.filteredItems },
                action: HomeViewFeature.Action.itemDetail(id:action:)
        )
    ) { itemsStore in
         ItemRowView(store: itemsStore)
    }
    .listRowBackground(Colors.primary)
    .listRowSeparator(.hidden)
}
.listStyle(.plain)

And here is my ItemRowView:

public var body: some View {
    WithViewStore(self.store) { viewStore in
        NavigationLink(
            unwrap: Binding(get: { viewStore.route }, set: { _ in }),
            case: /ItemRowFeature.State.Route.itemDetail,
            onNavigate: { viewStore.send(.setEditNavigation(isActive: $0)) },
            destination: { itemViewModel in
                IfLetStore<ItemDetailFeature.State, ItemDetailFeature.Action, ItemDetailView?>(
                    self.store.scope(
                        state: { state in
                            guard case .itemDetail(let itemDetailState) = state.route else {
                                return nil
                            }
                            return itemDetailState
                        },
                        action: { .edit($0) }
                    ),
                    then: { ItemDetailView(store: $0) }
                )
            }
            ) {
                ZStack {
                    RoundedRectangle(cornerRadius: 15.0)
                         .fill(Color(UIColor.systemGray6))
                    HStack {
                        VStack(alignment: .leading, spacing: 9) {
                            Text(viewStore.item.name ?? "")
                                .font(.body)
                            }
                        }
                    }
                    .padding(.vertical, 9)
                }
            }
            .opacity(0)
        }
    }

If I add the opacity here it uses the opacity for the whole view, which hides the whole row. I don't know which is the appropriate location for the opacity in this case.

In your first code snippet (in vanilla SwiftUI) you had structured the row like this:

That is, the ZStack contained both the ChatsListView and the NavigationLink.

Whereas in the TCA code you just posted, the ZStack is inside the NavigationLink.

Is there any reason you can't restructure the view hierarchy to be more similar to what you did for vanilla SwiftUI?

1 Like

You are right! it totally makes sense now. I just followed the same arrangement as I did in vanilla SwiftUI and it worked like a charm. Thank you so much @mbrandonw.