Here is the code of login page, navigate from tabview using navigation-link
and here I want to pop back once get the api response,
Also if any way to pop back using navigationLink same link push, please let me know.
thanks in advance!!
struct LoginBody: View {
#ObservedObject var viewModel = LoginViewModel()
#State private var email: String = ""
#State private var password: String = ""
#Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
var loginButton: some View {
Button(action: {
DispatchQueue.main.async {
print("Email:- ", email)
print("Password:- ", password)
viewModel.loginAPI(email: email, password: password)
DispatchQueue.main.asyncAfter(deadline: .now() + 8, execute: {
print("presentationMode dismiss")
self.presentationMode.wrappedValue.dismiss()
})
}
}) {
HStack(alignment: .center) {
Spacer()
Text("Login")
.font(.system(size: 20).bold())
.frame(alignment: .center)
Spacer()
}
}
.padding(EdgeInsets(top: 15, leading: 20, bottom: 15, trailing: 20))
.background(Color(#colorLiteral(red: 0.3340760444, green: 0.764342023, blue: 0.8197288968, alpha: 1)))
.foregroundColor(Color.white)
.cornerRadius(5)
.shadow(color: Color.init(red: 0.0, green: 0.0, blue: 0.0, opacity: 0.4), radius: 2, x: 0, y: 2)
.frame(height: 40, alignment: .center)
}
}
don't know how you get this to compile, but rename "loginButton" to "body".
Related
I am working on developing a quiz app. I have the following code, in two SwiftUI Views. Right now, the entire screen background color changes if you get an answer correct(to green)/incorrect(to red) but I want only the button background color to change, and the background of the screen to remain white. How do I implement this in the code?
Content View Swift:
import SwiftUI
struct ContentView: View {
let question = Question(questionText: "What was the first computer bug?", possibleAnswers: ["Ant", "Beetle", "Moth", "Fly"], correctAnswerIndex: 2)
#State var mainColor = Color(red: 255/255, green: 255/255, blue: 255/255)
#State var textBackgroundColor = Color.white
var body: some View {
ZStack {
mainColor.ignoresSafeArea()
VStack{
Text("Question 1 of 10")
.font(.callout)
.foregroundColor(.gray)
.padding(.bottom, 1)
.padding(.trailing, 170)
.multilineTextAlignment(.leading)
Text(question.questionText)
.font(.largeTitle)
.multilineTextAlignment(.leading)
.bold()
.background(textBackgroundColor)
Spacer()
.frame(height: 200)
VStack(spacing: 20){
ForEach(0..<question.possibleAnswers.count) { answerIndex in
Button(action: {
print("Tapped on option with the text: \(question.possibleAnswers[answerIndex])")
mainColor = answerIndex == question.correctAnswerIndex ? .green : .red
textBackgroundColor = answerIndex == question.correctAnswerIndex ? .green : .red
print(textBackgroundColor)
}, label: {
ChoiceTextView(choiceText: question.possibleAnswers[answerIndex])
})
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
ChoiceTextView:
import SwiftUI
struct ChoiceTextView: View {
let choiceText: String
let accentColor = Color(red: 48/255, green: 105/255, blue: 240/255)
#State var textBackgroundColor = Color.white
var body: some View {
Text(choiceText)
.frame(width:250)
.foregroundColor(.black)
.padding()
// make background white to put shadow later
.background(textBackgroundColor)
.cornerRadius(10)
.shadow(color: Color(hue: 1.0, saturation: 0.0, brightness: 0.869), radius: 5, x: 0, y: 5)
}
}
struct ChoiceTextView_Previews: PreviewProvider {
static var previews: some View {
ChoiceTextView(choiceText: "Choice Text!", textBackgroundColor: Color.white)
}
}
Please help me figure this out!
I think this code does what you are trying to achieve.
Basically, avoid using the color to the main view's background and instead, put it in the button background modifier.
Also, instead of using the index of the array I use the value. I think it's easier to identify plus it avoids the ForEach warning that shows up for using a non fixed Int value.
struct Question {
let questionText: String
let possibleAnswers: [String]
let correctAnswer: String
}
struct ContentView: View {
let question = Question(
questionText: "What was the first computer bug?",
possibleAnswers: ["Ant", "Beetle", "Moth", "Fly"],
correctAnswer: "Beetle"
)
var body: some View {
ZStack {
VStack{
Text("Question 1 of 10")
.font(.callout)
.foregroundColor(.gray)
.padding(.bottom, 1)
.padding(.trailing, 170)
.multilineTextAlignment(.leading)
Text(question.questionText)
.font(.largeTitle)
.multilineTextAlignment(.leading)
.bold()
Spacer()
.frame(height: 200)
VStack(spacing: 20){
ForEach(question.possibleAnswers, id: \.self) { answer in
ChoiceButton(
answer: answer,
question: question
)
}
}
}
}
}
}
struct ChoiceButton: View {
let answer: String
let question: Question
#State private var mainColor = Color(red: 255/255, green: 255/255, blue: 255/255)
var body: some View {
Button {
print("Tapped on option with the text: \(answer)")
mainColor = answer == question.correctAnswer ? .green : .red
} label: {
Text(answer)
.frame(width:250)
.foregroundColor(.black)
.padding()
// make background white to put shadow later
.background(mainColor)
.cornerRadius(10)
.shadow(color: Color(hue: 1.0, saturation: 0.0, brightness: 0.869), radius: 5, x: 0, y: 5)
}
}
}
I have a list generated from a ForEach loop:
struct TrainingList: View {
#EnvironmentObject var trainingVM: TrainingViewModel
var body: some View {
VStack(alignment: .leading) {
Text("Your training sessions")
.font(.system(size: 35, weight: .semibold, design: .default))
.padding(.all, 10)
.foregroundColor(.white)
Divider()
ScrollView{
if(trainingVM.loading){
ProgressView("Loading training session").progressViewStyle(CircularProgressViewStyle(tint: .blue))
}
LazyVStack {
ForEach(trainingVM.trainingList) { training in
TrainingCell(training: training)
}
}
}
Spacer()
}
.background {
Rectangle()
.fill(Color(.sRGB, red: 41/255, green: 41/255, blue: 41/255))
.cornerRadius(10, corners: [.topRight, .bottomRight])
.shadow(color: .black.opacity(1), radius: 8, x: 6, y: 0)
}
.frame(width: 650)
.zIndex(.infinity)
}
}
Each TrainingCell has a button that opens an extra panel on the side of it. To indicate which row has the panel opened the button changes its styling:
struct TrainingCell: View {
#EnvironmentObject var trainingVM: TrainingViewModel
#State var showEvents = false
let training: Training
var body: some View {
HStack(spacing: 0) {
ZStack(alignment: .top) {
RoundedRectangle(cornerRadius: 10, style: .continuous)
.fill(Color(.sRGB, red: 41/255, green: 41/255, blue: 41/255))
VStack {
HStack(spacing: 10) {
VStack(alignment: .leading, spacing: 5) {
HStack{
Text(training.readableDate, style: .date)
.font(.system(size: 25, weight: .semibold, design: .default))
.foregroundColor(.white)
Text(" | ")
Text(training.readableDate, style: .time)
.font(.system(size: 25, weight: .semibold, design: .default))
.foregroundColor(.white)
}
VStack(alignment: .leading,spacing: 5){
HStack {
HStack(spacing: 5) {
Image(systemName: "person.text.rectangle.fill")
.foregroundColor(Color(.sRGB, red: 10/255, green: 90/255, blue: 254/255))
Text(training.instructor.fullName)
.foregroundColor(.white)
}
}
HStack{
ForEach(training.students){ student in
HStack(spacing: 5) {
Image(systemName: "person")
.imageScale(.medium)
.foregroundColor(Color(.sRGB, red: 10/255, green: 90/255, blue: 254/255))
Text(student.fullName_shortenedFirstName)
.foregroundColor(.white)
}
}
}
}
.font(.system(size: 20, weight: .regular, design: .default))
.foregroundColor(.primary)
}
.frame(maxHeight: .infinity, alignment: .center)
.clipped()
Spacer()
View_Close_Button(showEvents: $showEvents)
}
.frame(maxWidth: .infinity, maxHeight: 80, alignment: .top)
.padding(.all)
.background {
RoundedRectangle(cornerRadius: 0, style: .continuous)
.fill(Color(.sRGB, red: 41/255, green: 44/255, blue: 49/255))
.shadow(color: .black.opacity(1), radius: 5, x: 0, y: 5)
}
}
}
}
}
}
The button code:
struct View_Close_Button: View {
#EnvironmentObject var trainingVM: TrainingViewModel
#Binding var showEvents: Bool
var body: some View {
HStack
{
Image(systemName: showEvents ? "xmark" : "eye")
.imageScale(.large)
.padding(.horizontal, 5)
.font(.system(size: 17, weight: .regular, design: .default))
Text(showEvents ? "Close" : "View")
.padding(.all, 10)
.font(.system(size: 25, weight: .regular, design: .default))
.multilineTextAlignment(.leading)
}
.onTapGesture {
withAnimation(.easeIn(duration: 0.3)) {
showEvents.toggle()
if(showEvents) {
trainingVM.showingEvents = true
}else{
trainingVM.showingEvents = false
}
}
}
.foregroundColor(.white)
.background {
Capsule(style: .continuous)
.foregroundColor(showEvents ? Color(.sRGB, red: 253/255, green: 77/255, blue: 77/255) : Color(.sRGB, red: 10/255, green: 90/255, blue: 254/255))
.clipped()
.frame(maxWidth: 180)
}
}
}
Which should result in this:
The only problem I have is that all button can be activated at the same time. How would I go about disabling the rest of the button when one is tapped?
I need the user to only be able to have on of the button displayed as "X Close"
I tought about looping trough other buttons to deactivate them programatically before activating the one that was tapped but I have no clue how
You could keep track of the activated button in the parent view.
If you have some kind of unique identifier per button you could make a variable in the parent view that contains the active identifier.
You can pass that variable as a binding into the button views and depending on that you can change the views appearance.
This way there is always just one active button. When a button is clicked you can set the value of the binding variable in the button view with the unique identifier of this button and the other views change automatically.
On the TrainingList you can define a variable with the active tab:
#State var activeTab: Int = 0
On TrainingCell you can add this variable as a binding.
#Binding var activeTab: Int
And you pass it like:
TrainingCell(training: training, activeTab: $activeTab)
Then on View_Close_Button you can add two variables:
#Binding var activeTab: Int
#State var training: Training
And pass it like this on the TrainingCell:
View_Close_Button(showEvents: $showEvents, activeTab: $activeTab, training: training)
In the View_Close_Button you can use this to get the value and set the styles accordingly:
Image(systemName: activeTab == training.id ? "xmark" : "eye")
Text(activeTab == training.id ? "Close" : "View")
And you can set it when the button it tapped:
.onTapGesture {
withAnimation(.easeIn(duration: 0.3) {
activeTab = training.id
}
}
I use a systemImage, with a onTapGesture function attached to it, to switch a boolean Variable to true. When that boolean variable is true, the view is changed. I positioned that systemImage at the top left part of the screen, using position(x:,y:) function. However, onTapGesture does not work when the value for "y" is bellow 100.
The code:
import SwiftUI
import FirebaseFirestoreSwift
import Firebase
struct ChatView: View {
#Environment(\.presentationMode) var presentationMode
#StateObject var homeData:HomeModel
#State var queryView:Bool = false
#EnvironmentObject var model:ContentModel
var user = Auth.auth().currentUser
let db = Firestore.firestore()
//If it is the first time when user scrolls
#State var scrolled = false
// #GestureState var isLongPressed = false
var body: some View {
if queryView == false {
VStack(spacing: 0) {
Text("\(homeData.query) Global Chat").foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))).font(.title3).padding(.top, 30)
Text("Welcome \(model.firstName) \(model.secondName) !").foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))).font(.callout)
Image(systemName: "arrow.backward.square")
.position(x: 30, y: 0)
.foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1)))
.font(.system(size: 30, weight: .regular))
.onTapGesture {
withAnimation(.easeOut) {
queryView = true
}
print("TAPPED")
}
ScrollViewReader { reader in
ScrollView{
VStack(spacing: 15) {
ForEach(homeData.msgs) { msg in
ChatRow(chatData: msg, firstName: model.firstName, secondName: model.secondName).onAppear(){
if msg.id == self.homeData.msgs.last!.id && !scrolled {
reader.scrollTo(homeData.msgs.last!.id, anchor: .bottom)
scrolled = true
}
// print(model.firstName)
// print(model.secondName)
}
}.onChange(of: homeData.msgs) { value in
reader.scrollTo(homeData.msgs.last!.id, anchor: .bottom)
}
}
}.padding(.vertical)
}.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height - 135)
HStack(spacing:15) {
TextField("Enter message", text: $homeData.txt)
.padding(.horizontal)
//Fixed height for animation...
.frame(height: 45)
.foregroundColor(Color(.black))
.background(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1)).opacity(1.0))
.clipShape(Capsule())
if homeData.txt != "" {
Button {
homeData.writeAllMessages()
} label: {
Image(systemName: "paperplane.fill")
.font(.system(size: 22))
.foregroundColor(.white)
.frame(width: 45, height: 45)
.background(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1)))
.clipShape(Circle())
}
}
}.animation(.default)
.padding()
Spacer().frame(height: 100)
}.background(Color(.black).scaledToFill().frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height).ignoresSafeArea())
.navigationBarBackButtonHidden(true)
} else {
QueryView(query: homeData.query)
}
}
}
What shall I do in order to make that TapGesture work anywhere on the screen?
To provide more info,I use the systemImage with that tapgesture function because when I use the NavigationLink back button the transition to its parent view is too slow and laggy.
It's probably because the NavigationBar is still at the top of your View even though the Back button is hidden.
Try adding .navigationBarHidden(true) instead of .navigationBarBackButtonHidden(true).
I can't seem to find the reason why there's a space between my list and navigation view. When I remove my navigation bar items, my list fills the space, when I have my navigation bar items, there's a gap between the navigation bar and my list. The style I'm using for my navigation bar is inline. Is this a bug in Xcode or is there something that I'm missing. Here's the code below.
...
import SwiftUI
struct DigitalReceiptContent: View {
#ObservedObject var store = ReceiptStore()
#State var showProfile = false
func addUpdate() {
store.updates.append(Update(name: "New Purchase", purchase: "$0.00", date: "00/00/21"))
}
var body: some View {
NavigationView {
List {
ForEach(store.updates) { update in
NavigationLink(destination: FullDigitalReceipt(update: update))
{
HStack {
Circle()
.frame(width: 50, height: 50)
.background(Color(#colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)))
.foregroundColor(.gray)
.cornerRadius(50)
.shadow(color: Color.black.opacity(0.6), radius: 2, x: 0, y: 1)
Text(update.name)
.font(.system(size: 20, weight: .bold))
.padding(.leading)
Spacer()
VStack(alignment: .trailing, spacing: 4.0) {
Text(update.date)
.font(.caption)
Text(update.purchase)
.foregroundColor(Color(#colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)))
.fontWeight(.heavy)
}
}
.padding()
}
}
.onDelete{ index in
self.store.updates.remove(at: index.first!)
}
}
.listStyle(GroupedListStyle())
.navigationBarTitle(Text("Purchases"), displayMode: .inline)
.navigationBarItems(
// Selection button; organize purchases
leading: EditButton(),
trailing: Button(action: {self.showProfile.toggle() }) { Image(systemName: "person.crop.circle")
}
.sheet(isPresented: $showProfile) {
ProfileSettings()
})
}
}
}
...
*DataStoreCode:
How can I assign a variable to the parameter in the getTrailer function ?
I can't send data to the parameter when I click and the link doesn't work
class DataStore: ObservableObject {
#Published var movie: MovieRoot?
#Published var trailer: TrailerRoot?
#Published var url: String?
init() {
self.getMovies()
self.getTrailers(url: url ?? "")
}
func getMovies() {
JSONService().getMovies(url: "https://api.themoviedb.org/3/movie/upcoming?api_key=594b8eb4999a812345136ee3ed1ebdb&language=tr-TR&page=1", model: movie) { (result) in
self.movie = result
}
}
func getTrailers(url: String) { //This parameter.
JSONService().getMovies(url: url, model: trailer) { (result) in
self.trailer = result
}
}
}
My ContentView Codes:
ForEach(store.movie?.results ?? []) { item in
VStack()
.onTapGesture {
self.show.toggle()
self.store.url = "https://api.themoviedb.org/3/movie/\(item.id)/videos?api_key=594b8eb499123456ad5136ee3ed1ebdb&language=en-US"
print(self.store.trailer?.results)
}
}
JSON Service
class JSONService {
func getMovies<T: Decodable>(url: String, model: T, completion: #escaping (T) -> ()) {
guard let url = URL(string: url) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
do {
let items = try JSONDecoder().decode(T.self, from: data)
DispatchQueue.main.async {
completion(items)
}
} catch let error {
print(error)
}
}
.resume()
}
}
ContentView
struct ContentView: View {
#State var show: Bool
//#State var movie: MovieRoot
#ObservedObject var store = DataStore()
#State var selectedMovie: Movie
#State var id: Int
var imageURL = "https://image.tmdb.org/t/p/w185_and_h278_bestv2"
//var trailerURL = "https://api.themoviedb.org/3/movie/338762/videos?api_key=594b8eb4999a8b44ad5136ee3ed1ebdb&language=en-US"
var body: some View {
ZStack {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(store.movie?.results ?? []) { item in
GeometryReader { geometry in
VStack {
//Image("film")
WebImage(url: URL(string: self.imageURL + item.poster_path))
.resizable()
.retryOnAppear(true)
.onSuccess()
.renderingMode(.original)
.cornerRadius(30)
.frame(width: 185, height: 278)
.shadow(color: Color.black.opacity(0.4), radius: 10, x: 0, y: 10)
.animation(.spring(response: 0.5, dampingFraction: 0.6, blendDuration: 0))
Text(item.title)
.font(.system(size: 20, weight: .bold))
CircleView(firstColor: #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1), secondColor: #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1), width: 50, height: 50, percent: item.vote_average)
}
.rotation3DEffect(Angle(degrees: Double(geometry.frame(in: .global).minX - 30) / -20), axis: (x: 0, y: 10.0, z: 0))
.frame(width: UIScreen.main.bounds.width)
.onTapGesture {
self.show.toggle()
Here-> self.store.url = "https://api.themoviedb.org/3/movie/\(item.id)/videos?api_key=594b8eb4999a8b44ad5136ee3ed1ebdb&language=en-US"
print(self.store.trailer?.results)
}
.offset(y: self.show ? .zero : -UIScreen.main.bounds.height)
.animation(.easeIn)
}
.frame(width: UIScreen.main.bounds.width)
}
}
.frame(maxHeight: .infinity)
}
DetailView(show: $show, movie: $selectedMovie)
}
// .onAppear {
// JSONService().getMovie(url: "https://api.themoviedb.org/3/movie/upcoming?api_key=594b8eb4999a8b44ad5136ee3ed1ebdb&language=tr-TR&page=1") { (result) in
// self.movie.results = result.results
// }
// }
}
}
How can I check that the url variable in the DataSource class has changed. I'm throwing item.id into the url variable, but it doesn't work.
I redirect the data in Content View to the Detail View page.
DetailView
struct DetailView: View {
#ObservedObject var trailer = DataStore()
#Binding var show: Bool
#Binding var movie: Movie
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack {
Image(systemName: "multiply.circle")
.imageScale(.large)
.padding()
.onTapGesture {
self.show.toggle()
}
.onDisappear()
WebView(request: URLRequest(url: URL(string: "https://www.youtube.com/watch?v=gn5QmllRCn4")!))
.frame(height: UIScreen.main.bounds.height * 0.3)
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(20)
.shadow(color: Color.black.opacity(0.3), radius: 10, x: 0, y: 10)
HStack {
Text(movie.title)
.font(.system(size: 20, weight: .semibold))
Spacer()
CircleView(firstColor: #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1), secondColor: #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1), width: 30, height: 30, percent: 4.6)
}
.padding(.horizontal)
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(10)
.shadow(color: Color.black.opacity(0.3), radius: 5, x: 0, y: 5)
.padding()
Text(movie.overview)
.padding()
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(20)
.padding(.horizontal)
.shadow(color: Color.black.opacity(0.3), radius: 10, x: 0, y: 10)
}
}
.animation(.easeIn)
.offset(y: show ? UIScreen.main.bounds.height : .zero)
.onReceive(trailer.$url) { (_) in
}
}
}