Struggling with layout in SwiftUI on TVOS - layout

I have a workable UI in TVOS using SwiftUI, but I can't figure out how to make it lay out properly.
Goals:
Screen is full screen, not inset in safe area
Album image is square, aspect ratio preserved, fills top-to-bottom
Album and artist text lays out comfortably, near the album art
import SwiftUI
struct ContentView: View {
#ObservedObject var ds = DataStore()
var body: some View {
HStack(alignment: .top) {
if (ds.currentRoom.albumImage != nil) {
Image(uiImage: ds.currentRoom.albumImage!)
.resizable()
.aspectRatio(contentMode: ContentMode.fit)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.background(Color.black)
}
VStack(alignment: .leading, spacing: 8) {
Text(ds.currentRoom.artist ?? "?")
.font(.system(.title, design: .default))
.bold()
.foregroundColor(Color.gray)
.padding(.top, 100)
Text(ds.currentRoom.title ?? "?")
.font(.system(.headline, design: .default))
.foregroundColor(Color.gray)
.padding(.bottom, 100)
Button(action: { print ("pressed!" )} ) {
Image(systemName: "playpause")
.font(.system(.title, design: .default))
.foregroundColor(Color.gray)
.padding(30)
.overlay(
RoundedRectangle(cornerRadius: 16)
.stroke(Color.green, lineWidth: 4)
)
}
}
}
.padding(20)
.background(Color.black)
.edgesIgnoringSafeArea(.all)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
In case it helps, here are the relevant helper and DataSource methods:
The DataStore() class has this method:
import SwiftUI
import Combine
class CurrentRoom {
var artist: String?
var title: String?
var album: String?
var albumArtURI: String?
var absoluteAlbumArtURI: String?
var albumImage: UIImage?
}
class DataStore: ObservableObject {
#Published var currentRoom: CurrentRoom = CurrentRoom()
init() {
getCurrentRoom()
}
func getCurrentRoom() {
currentRoom.artist = "Eilen Jewell"
currentRoom.album = "Sundown over Ghost Town"
currentRoom.title = "Half-Broke Horse"
currentRoom.absoluteAlbumArtURI = "https://images-na.ssl-images-amazon.com/images/I/71mkKfTQD0L._SX425_.jpg"
currentRoom.albumImage = Api().getImageDataFromURI(UrlAsString: currentRoom.absoluteAlbumArtURI)
}
}
struct DataStore_Previews: PreviewProvider {
static var previews: some View {
/*#START_MENU_TOKEN#*/Text("Hello, World!")/*#END_MENU_TOKEN#*/
}
}
Finally:
class Api {
func getImageDataFromURI(UrlAsString: String?) -> UIImage? {
if let URI = UrlAsString {
if URI.starts(with: "http") {
if let url = URL(string: URI) {
let data = try? Data(contentsOf: url)
if let imageData = data {
return UIImage(data: imageData)
}
}
}
}
return nil
}
}
Goal:

You can either go with Asperis answer, or, if ContentMode.Fit is important to you (as you don't want to clip the image), just remove the width part of the frame modifier at your Image, and then add a Spacer behind the VStack, which will consume the rest:
struct ContentView: View {
#ObservedObject var ds = DataStore()
var body: some View {
HStack(alignment: .top) {
if (ds.currentRoom.albumImage != nil) {
Image(uiImage: ds.currentRoom.albumImage!)
.resizable()
.aspectRatio(contentMode: ContentMode.fit)
.frame(minHeight: 0, maxHeight: .infinity)
.background(Color.black)
}
VStack(alignment: .leading, spacing: 8) {
Text(ds.currentRoom.artist ?? "?")
.font(.system(.title, design: .default))
.bold()
.foregroundColor(Color.gray)
.padding(.top, 100)
Text(ds.currentRoom.title ?? "?")
.font(.system(.headline, design: .default))
.foregroundColor(Color.gray)
.padding(.bottom, 100)
Button(action: { print ("pressed!" )} ) {
Image(systemName: "playpause")
.font(.system(.title, design: .default))
.foregroundColor(Color.gray)
.padding(30)
.overlay(
RoundedRectangle(cornerRadius: 16)
.stroke(Color.green, lineWidth: 4)
)
}
}
.padding(.leading, 10)
Spacer()
}
.padding(20)
.background(Color.black)
.edgesIgnoringSafeArea(.all)
}
}
This will result in this image:
Correct layout

Related

Core Data, Problem with updating (duplicating instead)

I am new to Swift UI. Could you please help me with core data updating?
Here is the point of a problem:
I am building a WatchOS app. There are 3 Views there:
FirstView - a view with a button to Add a new Goal and a List of added Goals.
AddGoalView - appears after pressing Add new Goal.
RingView - a view with a Goal Ring (similar to activity ring mechanics) and all the data presented.
The point of the problem is the next:
After adding a new Goal everything is alright. The Data passes correctly from AddGoalView to the FirstView. I need only 2 items to be passed out of AddGoalView (One String and one Double).
Then, after pressing on the recently created Goal I appear on the Ring View. I successfully pass there 2 items (that String and Double I mentioned).
On the RingView I want to update the 3-rd Item (double) and send it back. So it can be updated on the FirstView.
the Result:
Instead of updating this 3-d Item it just seems to create a completely new Goal on the First View below the previous Goal. Photo
My Code (FirstView):
struct FirstView: View {
#FetchRequest (
entity:NewGoal.entity(),
sortDescriptors:[NSSortDescriptor(keyPath: \NewGoal.dateAdded, ascending: false)],
animation: .easeInOut )
var results:FetchedResults<NewGoal>
#State var showMe = false
var body: some View {
ScrollView{
VStack{
VStack(alignment: .leading){
Text("My Goals:")
NavigationLink(
destination: AddGoalView(),
isActive: $showMe,
label: {
Image(systemName: "plus")
Text("Set Money Goal")
})
Text("Recents:")
ForEach(results){ item in
VStack(alignment: .leading){
NavigationLink(
destination: RingView(GTitle: item.goalTitle ?? "", Sum: item.neededSum),
label: {
HStack{
Image(systemName: "gear")
VStack(alignment: .leading){
Text(item.goalTitle ?? "")
HStack{
Text("$\(item.yourSum, specifier: "%.f")") ///This item doesn't update
Text("/ $\(item.neededSum, specifier: "%.f")")
}
}
}
})
}
}
}
}
}
}
}
My Code (AddGoalView):
struct AddGoalView: View {
#State private var goalTitle = ""
#State private var showMe:Bool = true
#State private var neededSum:Double = 0.0
#State private var isFocusedNum = false
#Environment(\.managedObjectContext) var context
#Environment(\.presentationMode) var presentationMode
var body: some View {
ScrollView{
VStack (alignment: .leading, spacing: 6){
TextField("Goal Name...", text: $goalTitle)
HStack{
Text("$\(neededSum, specifier: "%.f")")
.overlay(
RoundedRectangle(cornerRadius: 9)
.stroke(isFocusedNum ? Color.red : Color.white, lineWidth: 1)
.opacity(1.0))
.focusable(true) { newState in isFocusedNum = newState}
.animation(.easeInOut(duration: 0.1), value: isFocusedNum)
.digitalCrownRotation(
$neededSum,
from: 0,
through: 100000,
by: 25,
sensitivity: .high)
}
Button(action: addGoal) {
Text("Add Goal")
}
.disabled(neededSum == 0.0)
.disabled(goalTitle == "")
.navigationTitle("Edit")
}
}
}
private func addGoal(){
let goal = NewGoal(context: context)
goal.goalTitle = goalTitle
goal.dateAdded = Date()
goal.neededSum = neededSum
do{
try context.save()
presentationMode.wrappedValue.dismiss()
}catch let err{
print(err.localizedDescription)
}
}
My Code (RingView Code):
struct RingView: View {
#State private var isFocusedSum = false
#State private var yournewSum:Double = 0.0
var goalItem: NewGoal?
var Sum:Double
var GTitle:String
#Environment(\.managedObjectContext) var context
#Environment(\.presentationMode) var presentationMode
#FetchRequest var results: FetchedResults<NewGoal>
init(GTitle: String, Sum: Double){
self.GTitle = GTitle
self.Sum = Sum
let predicate = NSPredicate(format:"goalTitle == %#", GTitle)
self._results=FetchRequest(
entity: NewGoal.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \NewGoal.dateAdded, ascending: false)],
predicate: predicate,
animation: .easeInOut
)
}
var body: some View {
ZStack{
ForEach(results) { item in
RingShape(percent:(yournewSum/item.neededSum*100), startAngle: -90, drawnClockwise: false) /// Ring
.stroke(style: StrokeStyle(lineWidth: 10, lineCap: .round))
.fill(AngularGradient(gradient: Gradient(colors: [.red, .pink, .red]), center: .center))
.frame(width: 155, height: 155)
HStack(alignment: .top){
Spacer()
Button(action: addSum) { ///BUTTON TO Update
Image(systemName: "gear")
}
.clipShape(Circle())
}
VStack(alignment: .trailing, spacing: 0.0){
Spacer()
Text("$\(yournewSum, specifier: "%.f")") /// Here is the data I want to change via Digital Crown and update
.font(.title3)
.overlay(
RoundedRectangle(cornerRadius: 7)
.stroke(Color.white, lineWidth: 2)
.opacity(isFocusedSum ? 1.0:0.0)
)
.focusable(true) { newState in isFocusedSum = newState}
.animation(.easeInOut(duration: 0.3), value: isFocusedSum)
.digitalCrownRotation(
$yournewSum,
from: 0,
through: Double((item.neededSum)),
by: 10,
sensitivity: .high)
Text("/ $\(item.neededSum, specifier: "%.f")") ///Here is the Double data I entered in AddGoalView
.font(.caption)
}
.frame(width: 200, height: 230)
.padding(.top, 7)
VStack(alignment: .center, spacing: 1.0){
Text(item.goalTitle ?? "Your Goal Name") ///Here is the String data I entered in AddGoalView
.foregroundColor(.gray)
}
.padding(.top, 200.0)
}
}
.padding([.top, .leading, .trailing], 5.0)
}
private func addSum(){
let goal = goalItem == nil ? NewGoal(context: context): goalItem
goal?.yourSum = yournewSum //// I am trying to update the Data here, but after running the func it creates a duplicate.
do{
try context.save()
presentationMode.wrappedValue.dismiss()
} catch let err{
print(err.localizedDescription)
}
}
You never give var goalItem: NewGoal? the initial value of the item you want to update.
try replacing this
RingView(GTitle: item.goalTitle ?? "", Sum: item.neededSum)
with
RingView(goalItem: item, GTitle: item.goalTitle ?? "", Sum: item.neededSum)
and of course your have to change your initializer for RingView to
init(goalItem: NewGoal? = nil, GTitle: String, Sum: Double){
and add to the initializer this line
self.goalItem = goalItem

Aligning Text within ZStack based on rotation in SwiftUI

I'm having some trouble aligning Text inside a ZStack...more specifically, if I rotate the device after I started the app...
I want the Text to be aligned to the top leading of the View, but below you can see images of what's happening...
If I open the app with the device in portrait, the alignment is correct...
Alignment with app started in portrait
...but if I rotate the device to landscape, the text moves to the top center...
Alignment after rotation to landscape
Same thing if I start the app with the device in landscape, all aligned correctly...
Alignment with app started in landscape
...but if I rotate the device to portrait, the text almost disappear completely...
Alignment after rotation to portrait
This is the code for the ContentView:
import SwiftUI
let furl = URL(fileURLWithPath: "path")
struct ContentView: View {
#State private var selected = 0
var body: some View {
TabView(selection: $selected) {
NavigationView {
HomeView()
}
.navigationViewStyle(StackNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 0 ? "house.fill" : "house"))
Text("Home")
}.tag(0)
NavigationView {
CategoryView(dm: DownloadManager())
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 1 ? "text.justify" : "text.justify"))
Text("Categorie")
}.tag(1)
NavigationView {
GalleryView(dm: DownloadManager())
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 2 ? "photo.fill" : "photo"))
Text("Galleria")
}.tag(2)
NavigationView {
FavoritesView()
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 3 ? "star.fill" : "star"))
Text("Preferiti")
}.tag(3)
NavigationView {
InfoView()
}
.navigationViewStyle(StackNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 4 ? "info.circle.fill" : "info.circle"))
Text("Informazioni")
}.tag(4)
}
.accentColor(.white)
.onAppear() {
UINavigationBar.appearance().barTintColor = UIColor(red: 112.0/255.0, green: 90.0/255.0, blue: 143.0/255.0, alpha: 1.0)
UITabBar.appearance().barTintColor = UIColor(red: 112.0/255.0, green: 90.0/255.0, blue: 143.0/255.0, alpha: 1.0)
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
This is the code for the HomeView (where I have the problem):
import SwiftUI
struct HomeView: View {
#State private var showAlertSheet = false
#ObservedObject var monitor = NetworkMonitor()
var body: some View {
ZStack {
Image("vivibusso_home")
.resizable()
.aspectRatio(contentMode: .fill)
.clipped()
VStack(alignment: .leading) {
Text("Benvenuto")
.font(.largeTitle)
.fontWeight(.bold)
.padding(.leading)
Text("a Busso!")
.font(.largeTitle)
.fontWeight(.bold)
.padding(.leading)
}
.frame(maxWidth: UIScreen.main.bounds.width, maxHeight: UIScreen.main.bounds.height, alignment: .topLeading)
.padding(.top)
}
.navigationTitle(Text("ViviBusso"))
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(trailing:
Button (action: {
self.showAlertSheet = true
}) {
Image(systemName: monitor.isConnected ? "wifi" : "wifi.slash")
})
.alert(isPresented: $showAlertSheet) {
if monitor.isConnected {
return Alert(title: Text("Tutto OK!"), message: Text("ViviBusso funziona correttamente!"), dismissButton: .default(Text("OK")))
}
return Alert(title: Text("Attenzione!"), message: Text("ViviBusso ha bisogno della connessione Internet per funzionare!"), dismissButton: .default(Text("OK")))
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
How can I solve this?
Thank you!
ZStack(alignment:.topLeading) { //<= here
GeometryReader { proxy in //<= here
Image("vivibusso_home")
.resizable()
.aspectRatio(contentMode: .fill)
.border(Color.black)
.frame(width: proxy.size.width, height: proxy.size.height)// <= here
}
VStack(alignment: .leading) {
Text("Benvenuto")
.font(.largeTitle)
.fontWeight(.bold)
.padding(.leading)
Text("a Busso!")
.font(.largeTitle)
.fontWeight(.bold)
.padding(.leading)
}
//<=here
.padding(.top)
}
.navigationTitle(Text("ViviBusso"))
...

Warning: Attempt to present * on * which is already presenting (null) SwiftUI

I am relatively new to iOS app development as well as SwiftUI and I am currently working on an app that allows the user to create a schedule by the week.
I recently modified the entity to also accept time inputs so that the lists organize themselves based on the time they were scheduled for. Here's a quick look:
Main List View
However, when I click on each item it sends me to the wrong event.
In UIKit I noticed this problem was mainly prevalent due to a call to multiple views being presented, however I could not see where I would be presenting multiple views.
Main List View
List {
ForEach(self.Events) { event in
if("\(event.dotw ?? "Unknown")" == self.name) {
Button(action: {
self.isEvent.toggle()
}) {
HStack {
Text("\(event.name ?? "Unknown")")
.foregroundColor(Color.white)
Spacer()
Text("\(event.time ?? Date(), formatter: Self.taskDateFormat)")
}
}
.sheet(isPresented: self.$isEvent){
EventView(eventName: "\(event.name ?? "Unknown")", description: "\(event.descript ?? "Unknown")", eventTime: (event.time ?? Date())).environment(\.managedObjectContext, self.managedObjectContext)
}
.buttonStyle(ItemButton())
}
}.onDelete { indexSet in
let deleteItem = self.Events[indexSet.first!]
self.managedObjectContext.delete(deleteItem)
do{
try self.managedObjectContext.save()
} catch {
print(error)
}
}
Button(action: {
self.isPresented.toggle()
}) {
HStack {
Text("new")
Spacer()
}
}
.buttonStyle(NewItemButton())
.sheet(isPresented:$isPresented) {
NewEventView(dotw: self.name).environment(\.managedObjectContext, self.managedObjectContext)
}
}
.onAppear {
UITableView.appearance().separatorStyle = .none
}.onDisappear {
UITableView.appearance().separatorStyle = .singleLine
}
.navigationBarHidden(true)
.navigationBarTitle("")
.edgesIgnoringSafeArea(.top)
}
.edgesIgnoringSafeArea(.top)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
This code:
.sheet(isPresented: self.$isEvent){
EventView(eventName: "\(event.name ?? "Unknown")", description: "\(event.descript ?? "Unknown")", eventTime: (event.time ?? Date())).environment(\.managedObjectContext, self.managedObjectContext)
}
Is where I am assuming the problem lies however I could find nothing wrong with it
Event View
struct EventView: View {
var eventName: String
var description: String
var eventTime: Date
var body: some View {
VStack {
VStack {
Image(systemName: "chevron.compact.down")
.foregroundColor(.white)
.imageScale(.large)
.padding()
HStack {
Text(eventName)
.foregroundColor(.white)
.font(.largeTitle)
.padding(.top, 15)
.padding(.leading, 20)
Spacer()
}
.padding(.bottom)
.frame(maxWidth:.infinity)
}
.background(Color.gray)
.shadow(color: Color.black.opacity(0.2), radius: 7, x: 3, y: 3)
.shadow(color: Color.white.opacity(0.7), radius: 4, x: -5, y: -5)
VStack(alignment:.leading) {
HStack {
Text(description)
.padding(.leading, 20)
.padding(.top, 30)
.foregroundColor(.gray)
Spacer()
}
Spacer()
}
.frame(maxWidth:.infinity,maxHeight:.infinity)
}
.edgesIgnoringSafeArea(.top)
}
}
Event Entity Initializer
import Foundation
import CoreData
import SwiftUI
public class Event:NSManagedObject,Identifiable {
#NSManaged public var name: String?
#NSManaged public var createdAt: Date?
#NSManaged public var descript: String?
#NSManaged public var dotw: String?
#NSManaged public var time: Date?
}
extension Event {
static func getAllEvents() -> NSFetchRequest<Event> {
let request: NSFetchRequest<Event> = NSFetchRequest<Event>(entityName: "Event")
let sortDescriptor = NSSortDescriptor(key: "time", ascending:true)
let sortDescriptor2 = NSSortDescriptor(key: "createdAt", ascending: true)
request.sortDescriptors = [sortDescriptor,sortDescriptor2]
return request
}
}
Are your Events identifiable? This helps SwiftUI knowing which is which:
struct Events: Identifiable {
var id = UUID()
var name: String
}
Might also help to put .id(event.id) in your ForEach block to identify it there too.

Same image being shown when showing a modal via .sheet after iterating array

In a swiftui app, I am iterating an array of entities and showing thumbmnail images and have it set up that when one is tapped, a detail view is shown with that particular full size image. The problem is that it's always the most recent image being shown when going to the detail screen.
Main view:
if documents.count > 0 {
ScrollView(.horizontal, showsIndicators: true) {
HStack {
ForEach(documents, id: \.self.id) {(doc: Document) in
Image(uiImage: UIImage(data: doc.image)!)
.resizable()
.frame(width: 40, height: 50, alignment: .center)
.clipShape(Rectangle())
.cornerRadius(8)
.scaledToFit()
.onTapGesture {
self.showImageDetail = true
}
.padding(.all, 5)
.sheet(isPresented: self.$showImageDetail, content: {
ImageViewDetail(image: UIImage(data: doc.image)!)
})
}
}
}
}
When ImageDetailView is shown, it's alway the most recent image saved. Below is the detail view code:
import SwiftUI
struct ImageViewDetail: View {
#Environment(\.presentationMode) var presentationMode
#State var image: UIImage
#State var scale: CGFloat = 1.0
var body: some View {
VStack {
Image(uiImage: image)
.resizable()
.padding()
.scaledToFit()
.scaleEffect(scale)
.cornerRadius(8)
.gesture(MagnificationGesture()
.onChanged {value in
self.scale = value.magnitude
}
)
HStack {
Button("Back") {
self.presentationMode.wrappedValue.dismiss()
}
.buttonStyle(FillStyle(width: 86, height: 32))
.padding(.trailing, 10)
Button("Delete") {
}
.buttonStyle(FillStyle(width: 86, height: 32))
.padding(.leading, 10)
}
}
.navigationBarTitle("Image", displayMode: .inline)
}
}
Any help would be greatly appreciated - I can't seem to see why the right image is not displayed by the ImageDetailView? Many thanks in advance.
Replace the Bool state with a Document? state:
#State var selectedDocument: Document?
var body: some View {
HStack {
ForEach(documents, id: \.self.id) {(doc: Document) in
Image(uiImage: UIImage(data: doc.image)!)
.onTapGesture {
self.selectedDocument = doc
}
}
}
}
.sheet(item: $selectedDocument) {
ImageViewDetail(image: UIImage(data: $0.image)!)
}
}
Sheet can be only one in view hierarchy, so below it is relocated for HStack and it is needed to add member currentImage
Here is scratchy approach... (not tested - might be needed take care of optionals)
#State private var currentImage: UIImage = UIImage() // < needed optionals?
...
ScrollView(.horizontal, showsIndicators: true) {
HStack {
ForEach(documents, id: \.self.id) {(doc: Document) in
Image(uiImage: UIImage(data: doc.image)!)
.resizable()
.frame(width: 40, height: 50, alignment: .center)
.clipShape(Rectangle())
.cornerRadius(8)
.scaledToFit()
.onTapGesture {
self.currentImage = UIImage(data: doc.image) ?? UIImage() // < current
self.showImageDetail = true
}
.padding(.all, 5)
}
}
.sheet(isPresented: self.$showImageDetail, content: { // < one sheet
ImageViewDetail(image: self.currentImage)
})
}

SwiftUI - Unable to reference #Published value outside Struct

I am new to SwiftUI and am hoping for some assistance with a project I am developing.
I am unable to reference #published value outside a struct.
All values are correctly functioning within the struct using:
#ObservableObject
#Publihsed
#ObservedObject
I have a Struct within ContentView which is linked to another View where I would like to display Quantity and Costs.
I have attempted various ways to access the values as can be seen in the struct NewOrders, but I keep getting zero and not getting the updated value.
Am I missing a step or executing code incorrectly?
Thanks in advance
class MealOrders: ObservableObject {
//Jollof Rice - Published
#Published var jollof = 0
//Swallow - Published
#Published var swallow = 0
//Pepper Soup - Published
#Published var pepperSoup = 0
}
struct ContentView: View {
var body: some View {
VStack {
NavigationView {
Section {
VStack(alignment: .leading) {
NavigationLink(destination: MenuOption()) {
Text("Meal Options")
}
Spacer()
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight:
.infinity, alignment: .topLeading)
}.padding() //Vstack End
}
Section {
VStack {
Image("africanfoods")
.resizable()
.frame(width: 275.0, height: 250.0)
.clipShape(Circle())
.overlay(Circle().stroke(Color.black, lineWidth: 5))
.scaledToFit()
}
} //Section End
Section { //Social Media
VStack {
Spacer()
HStack {
Spacer()
Image("facebook")
.resizable()
.frame(width:40, height: 40)
.scaledToFit()
.padding()
Image("instergram")
.resizable()
.frame(width:40, height: 40)
.scaledToFit()
.padding()
Image("youtube")
.resizable()
.frame(width:40, height: 40)
.scaledToFit()
.padding()
Image("twitter")
.resizable()
.frame(width:40, height: 40)
.scaledToFit()
.padding(.horizontal, 50)
}
} //Vstack End
} //Social Media
.navigationBarTitle(Text("African Foods Center"))
} //NavView End
} //VStack End
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct MenuOption: View {
//Object Observed Declarations
#ObservedObject var meals = MealOrders()
//Meal Prices
#State private var jolloRiceUnitCost = 14.95 //Jollof Rice Unit Cost
#State private var swallowUnitCost = 12.50 //Swallow Unit Cost
#State private var pepperSoupUnitCost = 13.50 //Pepper Soup Unit Cost
#State private var deliveryCost = 5.99 //Delivery Cost
#State private var menuItem = 0
var menuItems = ["Rice Meals", "Swallow Meals", "Pepper Soups"]
//Meals Calculator
var calculateMeal: Double {
var orderCost = 0.0
//Jollof Rice
if menuItems[menuItem] == "Rice Meals" {
orderCost = self.jolloRiceUnitCost * Double(self.meals.jollof)
return orderCost
//Swallow - Pounded Yam / Eba
} else if menuItems[menuItem] == "Swallow Meals" {
orderCost = self.swallowUnitCost * Double(self.meals.swallow)
} else if menuItems[menuItem] == "Pepper Soups" {
orderCost = self.pepperSoupUnitCost * Double(self.meals.pepperSoup)
}
return orderCost
}
var body: some View {
VStack(alignment: .leading) {
Section(header: Text("Select Meal").padding(.horizontal, 25)) {
Picker("Select Item", selection: $menuItem) {
ForEach(0 ..< menuItems.count) {
Text(self.menuItems[$0])
}
}.pickerStyle(SegmentedPickerStyle())
.padding(.horizontal, 25)
if menuItems[menuItem] == "Rice Meals" {
Text("Rice Meals:")
.foregroundColor(.black)
.padding(.horizontal, 25)
Spacer().frame(height:20)
`Text("Rice meals consist of Jollof Rice, Rice and Stew, Fried
Rice. You can option in meat, fish and or plantain with any of the meals")`
.foregroundColor(.blue)
.lineLimit(nil)
.padding(.horizontal, 25)
Spacer().frame(height:60)
//Insert image - Jollof Rice
Image("jollofRice")
.resizable()
.frame(width:250, height: 250)
.scaledToFit()
.border(Color.black, width: 4)
.padding(.horizontal, 100)
Spacer().frame(height:20)
HStack {
Stepper("Quantity (Max 5)",value: $meals.jollof, in: 0...5)
.padding(.horizontal, 45)
Text("\(meals.jollof): £\(calculateMeal, specifier: "%.2f")")
.padding()
}.padding()
Section { //Button Order
VStack {//Add Stepper for Quantity
Spacer()
HStack(alignment: .center, spacing: 140) {
Spacer()
Button(action: {}) {
NavigationLink(destination: Text("Jollof:: \(meals.jollof), £\(calculateMeal, specifier: "%.2f")")) {
Text("Create Order")
.font(.system(size: 14))
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(6)
}.padding()
Spacer()
}
}
} //Vstack End
} //Button Section End
} else if menuItems[menuItem] == "Swallow Meals" {
Text("Swallow")
.foregroundColor(.green)
.padding(.horizontal, 25)
Spacer().frame(height:20)
`Text("Swallow is the colloqual word for Pounded Yam, Eba, Fufu or Amala. This is complemented with soups, such as Egusi, Okra etc. You could have this meal with either meat or fish")`
.foregroundColor(.blue)
.lineLimit(nil)
.padding(.horizontal, 25)
Spacer().frame(height:60)
//Inset Image
Image("poundedYamEgusi")
.resizable()
.frame(width:250, height:250)
.scaledToFit()
.border(Color.black, width: 4)
.padding(.horizontal, 100)
HStack {//Add Stepper for Quantity
Stepper("Quantity (Max 5)",value: $meals.swallow, in: 0...5)
.padding(.horizontal, 45)
Text("\(meals.swallow): £\(calculateMeal, specifier: "%.2f")")
.padding()
}.padding()
//Insert Order Button
Section {
VStack {
Spacer()
HStack(alignment: .center, spacing: 140) {
Spacer()
Button(action: {}) {
NavigationLink(destination: Text("Swallow: \(meals.swallow), £\(calculateMeal, specifier: "%.2f")")) {
Text("Create Order")
.font(.system(size: 14))
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(6)
}.padding()
Spacer()
}
}
} //VStack End
} //Section End
} else if menuItems[menuItem] == "Pepper Soups" {
Text("Pepper Soup")
.foregroundColor(.red)
.padding(.horizontal, 25)
Spacer().frame(height:20)
`Text("Pepper soup is normally taken after one has had either Pounded Yam or rice meals. Depending on the audeience, the soup can be lightly spicy to very hot. Pepper soup can be had with either fish or meat")`
.foregroundColor(.blue)
.lineLimit(nil)
.padding(.horizontal, 25)
Spacer().frame(height:60)
//Insert Image
Image("pepperSoupYam")
.resizable()
.frame(width:250, height:250)
.scaledToFit()
.border(Color.black, width: 4)
.padding(.horizontal, 100)
HStack {//Add Stepper Quantity for Pepper Soup
Stepper("Quantity (5 Max)",value: $meals.pepperSoup, in: 0...5)
.padding(.horizontal, 45)
Text("\(meals.pepperSoup): £\(calculateMeal, specifier: "%.2f")")
.padding()
}.padding()
//Inset Order Button
Section {
VStack {
Spacer()
HStack(alignment: .center, spacing: 140) {
Spacer()
Button(action: {}) {
NavigationLink(destination: NewOrders()) {
Text("Create Order")
.font(.system(size: 14))
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(6)
}.padding()
Spacer()
}
}
}
}
}
Spacer()
}.font(.system(size: 14))
.foregroundColor(.purple)
} //Vstack Ending
} //View Ending
}
//This sis going to be the Orders Struct
struct NewOrders: View {
#ObservedObject var orderUpdatedV2 = MealOrders()
#State private var orderUpdate = MenuOption().meals.jollof
var body: some View {
//let mealsU: ContentView
NavigationView{
VStack {
List {
Text("")
}
}
}.navigationBarTitle("Meal Order")
}
}
This line below is incorrect because creates new value, that's why you have nil
#State private var orderUpdate = MenuOption().meals.jollof
instead you need to have (as far as I understood your code)
#Binding var orderUpdate: Int
and pass it in place of creating
NavigationLink(destination: NewOrders(orderUpdate: $meals.jollof)) {
Note: This is the idea, I'm not sure copy/paste will work, because provided your code snapshot is not compilable at my side.

Resources