How to use a CommandMenu within a CommandGroup? - swiftui

I would like to create a menu at the import/export location.
CommandGroup(replacing: CommandGroupPlacement.importExport) {
CommandMenu("Import"){
Button("Format I (.f1)"){
print("import Format 1")
}
Button ("Format II (.f2)") {
print("import Format 2")
}
}
}
Unfortunately, CommandMenu isn't a View but a Command. So, how do I combine these two?

Try the following
CommandGroup(replacing: CommandGroupPlacement.importExport) {
Menu("Import") { // << here !!
Button("Format I (.f1)"){
print("import Format 1")
}
Button ("Format II (.f2)") {
print("import Format 2")
}
}
}

Related

How to get a row count in SwiftUI List

I am trying to display the number of rows in a section in its header as shown below as COUNTHERE. The issue I'm running into is that I can't put any code inside the if statement that is not a view so I can't compute anything. Ideas?
struct Day1View: View {
var displayEmployees: [Employee]
var body: some View {
List {
Section(header: Text("Early (\(COUNTHERE)")) {
ForEach(displayEmployees) { employee in
if employee.shift == .early {
switch employee.post {
case .kitchen : Text(employee.name).foregroundColor(.blue)
case .floor : Text(employee.name).foregroundColor(.yellow)
case .upstairs : Text(employee.name).foregroundColor(.red)
case .greeting : Text(employee.name).foregroundColor(.green)
default : Text(employee.name).foregroundColor(.gray)
}
}
}
}
}
Since the section you showed is only for .early shift employees, you can get the count using a filtered version of the original array:
displayEmployees.filter({$0.shift == .early}).count
So your section becomes:
Section(header: Text("Early (\(displayEmployees.filter({$0.shift == .early}).count)")) {
Or, you can add a new computed property for the count:
var displayCount: Int {
return displayEmployees.filter({$0.shift == .early}).count
}
...
Section(header: Text("Early (\(displayCount)")) {

SwiftUI - Change List row background colour programatically

I'm trying to change the background colour of a row in a list based on a value
I have an Int16 value stored in card.owned and I want to change the background if this value is above 0, otherwise use the normal background.
Previously with a table view I could change it with the cellForRowAtIndexPath method, but not sure how to do it with SwiftUI without changing every row
Currently I have
List {
ForEach(cards) { section in
let header: String = nameForSectionHeader(sectionID: section.id)
Section(header: Text(header)) {
ForEach(section) { card in
NavigationLink(destination: CardView(card: card)) {
VStack(alignment: .leading) {
if let name = card.name, let id = card.cardID {
Text("\(id) - \(name)")
}
if let set = card.set, let setName = set.name {
Text("Set: \(setName)")
}
if card.owned > 0 {
Text("Owned: \(card.owned)")
}
}
}
}
}
}
.listRowBackground(lightGreen)
}

SwiftUI: Difference between async{} and Task.init{ }

I am using Xcode 13.4 and trying to launch an async function when the Picker changes.
Picker(NSLocalizedString("Please choose a project", comment: ""), selection: $selectedProjectKey) {
ForEach(projectKeys, id: \.self) {
Text($0)
}
}
.font(.system(size: 14))
.onChange(of: selectedProjectKey, perform: { (selectedKey) in
print("selected key \(selectedKey)")
async {
do {
let projectTasks = try await api.getProjectTasksByProjectKey(projectKey: selectedKey)
projectTasksKeys = projectTasks.map{$0.key}
} catch {
/// To define error behavour
}
}
})
It works, but I know that async is deprecated (yellow warning).
That's why, I tried with Task.init {... } or Task { ... } and instead, I get an error:
"Trailing closure passed to parameter of type 'Decoder' that does not
accept a closure".
I suppose that I did something definitely wrong but I can't understand what it is and what difference there is between async{...} and Task.init { ... } .

iOS 15 NavigationLink pop automatically if destination is created dynamically

This is a problem on iOS 15 RC only. It works all good on iOS 14.
The problem is if my destination on NavigationLink is created dynamically, it pop automatically if i try push a view via NavigationLink. Here is a bit code snippet
NavigationLink(
destination: (createSettingNavigationLink(name: nameAndImage[0])),
label: {
CellButton(title: nameAndImage[0], image: nameAndImage[1])
}
func createSettingNavigationLink(name: String) -> some View {
if name == "shop.Settings" {
return ShopSettings()
}
if name == "shop.Goods" {
return ShopGoodsManagementPage()
}
if name == "shop.Order" {
return ShopOrderPage()
}
if name == "Customer Service" {
return ServiceListPage(isStore: true)
}
if name == "shop.Performance" {
return PerformanceManagementPage()
}
if name == "shop.Earnings" {
return CommissionSummaryPage()
}
if name == "shop.Increase_sales" {
return BCWebView(urlStr: Constants.increaseSalesGuide)
.navigationBarTitle(Text("Increase Sales Guide"), displayMode: .inline)
.navigationBarHidden(false)
)
}
return EmptyView()
}
)
By the way, the approach mentioned here SwiftUI Unexpectedly NavigationLink pops automatically does not help.
My final solution is to change the above function to struct view. I think it makes sense since the struct view seems to keep states while function is pure stateless.

List Section display according to the number of items

I have tried to display a list using ForEach
ForEach(alphabet, id: \.self) { letter in
Section(header: Text(letter).id(letter)) {
ForEach(cats.filter(
{
(cat) -> Bool in
cat.name.prefix(1) == letter
}
), id: \.catId) { cat in
NavigationLink(destination: CatDetailView()) {
CatRow(cat: cat)
}
}
}
}
I would like to only display the Section header if the filtered result is an non-empty list. How can I do that?
As can see in the image, Section A, C, D, ... etc has nothing. I would only like to display Section B.
You need to do this at model level, so would be able to include sections conditionally, like
ForEach(alphabet, id:\.self) { letter in
if viewModel.hasItems(for: letter) {
Section(header: Text(letter).id(letter)) {
ForEach(viewModel.items(for: letter), id:\.catId) { cat in
NavigationLink(destination: CatDetailView()) {
CatRow(cat: cat)
}
}
}
}
}