I write the following code and brought this kind of output.
By using the .onTapGesture method I find the selected day from HStack
But I want to change the background color based on cell selection in Hstack.
Anyone give some idea or suggestions for changing the selected cell Background color on HStack.
Or share any references with me.
struct CalendarDay: Identifiable {
let id = UUID()
var number: String
var weekday: String
var isToday: Bool
}
struct ContentView: View {
#State var days = [CalendarDay]()
var body: some View {
ZStack{
VStack {
//MARK: CALENDAR
ScrollView(.horizontal, showsIndicators: false){
HStack(spacing: 20) {
ForEach(days) { day in
CalendarView(
number: day.number,
days: day.weekday,
color: day.isToday ? #colorLiteral(red: 0.9060331583, green: 0.2547450066, blue: 0.3359550834, alpha: 1) : #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
textcolor: day.isToday ? #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) : #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
)
.onTapGesture{
print(day)
}
}
}
.padding(.leading,10)
.padding(.bottom, 10)
.shadow(radius: 3, x: 3, y: 3)
}
}
}
.onAppear {
getCurrentWeekdays()
}
}
func getCurrentWeekdays() {
/// from https://stackoverflow.com/a/62355272/14351818
let dateComponents = Calendar(identifier: .gregorian).dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date())
let startOfWeek = Calendar(identifier: .gregorian).date(from: dateComponents)!
let startOfWeekNoon = Calendar(identifier: .gregorian).date(bySettingHour: 12, minute: 0, second: 0, of: startOfWeek)!
days = (0...6).map {
let calendar = Calendar(identifier: .gregorian)
let date = calendar.date(byAdding: .day, value: $0, to: startOfWeekNoon)!
let numberDateFormatter = DateFormatter()
numberDateFormatter.dateFormat = "d"
let number = numberDateFormatter.string(from: date)
let weekdayDateFormatter = DateFormatter()
weekdayDateFormatter.dateFormat = "E"
let weekday = weekdayDateFormatter.string(from: date)
let calendarDay = CalendarDay(
number: number,
weekday: weekday,
isToday: calendar.component(.day, from: Date()) == calendar.component(.day, from: date)
)
return calendarDay
}
}
}
struct CalendarView: View {
var number : String
var days : String
var color : UIColor
var textcolor : UIColor
var body: some View {
VStack{
Text(self.number)
.font(.system(size: 20, weight: .bold, design: .rounded))
.foregroundColor(Color(self.textcolor))
Text(self.days)
.font(.headline)
.foregroundColor(Color(self.textcolor))
}.padding([.top,.bottom], 10)
.padding([.leading,.trailing],10)
.background(Color(self.color))
.cornerRadius(30)
}
}
try something like this:
import SwiftUI
struct CalendarDay: Identifiable {
let id = UUID()
var number: String
var weekday: String
var isToday: Bool
}
struct ContentView: View {
#State var days = [CalendarDay]()
var body: some View {
ZStack{
VStack {
ScrollView(.horizontal, showsIndicators: false){
HStack(spacing: 20) {
// <---
ForEach(days.indices, id: \.self) { i in
CalendarView(
number: days[i].number,
days: days[i].weekday,
color: days[i].isToday ? #colorLiteral(red: 0.9060331583, green: 0.2547450066, blue: 0.3359550834, alpha: 1) : #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
textcolor: days[i].isToday ? #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) : #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
)
.onTapGesture{
print(days[i])
// this is just for replacing the current selection
for j in days.indices { days[j].isToday = false }
days[i].isToday = true
}
}
// <---
}
.padding(.leading,10)
.padding(.bottom, 10)
.shadow(radius: 3, x: 3, y: 3)
}
}
}
.onAppear {
getCurrentWeekdays()
}
}
func getCurrentWeekdays() {
/// from https://stackoverflow.com/a/62355272/14351818
let dateComponents = Calendar(identifier: .gregorian).dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date())
let startOfWeek = Calendar(identifier: .gregorian).date(from: dateComponents)!
let startOfWeekNoon = Calendar(identifier: .gregorian).date(bySettingHour: 12, minute: 0, second: 0, of: startOfWeek)!
days = (0...6).map {
let calendar = Calendar(identifier: .gregorian)
let date = calendar.date(byAdding: .day, value: $0, to: startOfWeekNoon)!
let numberDateFormatter = DateFormatter()
numberDateFormatter.dateFormat = "d"
let number = numberDateFormatter.string(from: date)
let weekdayDateFormatter = DateFormatter()
weekdayDateFormatter.dateFormat = "E"
let weekday = weekdayDateFormatter.string(from: date)
let calendarDay = CalendarDay(
number: number,
weekday: weekday,
isToday: calendar.component(.day, from: Date()) == calendar.component(.day, from: date)
)
return calendarDay
}
}
}
struct CalendarView: View {
var number : String
var days : String
var color : UIColor
var textcolor : UIColor
var body: some View {
VStack{
Text(self.number)
.font(.system(size: 20, weight: .bold, design: .rounded))
.foregroundColor(Color(self.textcolor))
Text(self.days)
.font(.headline)
.foregroundColor(Color(self.textcolor))
}.padding([.top,.bottom], 10)
.padding([.leading,.trailing],10)
.background(Color(self.color))
.cornerRadius(30)
}
}
Related
I have an issue and I hope that I will find the answer here to my questions. I made a Circular Timer, but everytime I'm closing the view , is going back from the start.
I tried to save the value where the time is calculated "onTick", is working for 2-3 seconds, and after again is going back from the start and is countdown from there.
I'll put a picture/video bellow with the behaviour, maybe somone can help me fix it .
Thanks !
This is WaitingOrderView.
struct WaitingOrderView: View {
#State private var timer: AnyCancellable?
#EnvironmentObject var syncViewModel : SyncViewModel
var body: some View {
ZStack {
if syncViewModel._order.id == 0 && syncViewModel._order.status == 0 {
CartView()
}
else if syncViewModel._order.status == syncViewModel.statusList.first(where: { status in
status.key == StatusKey.accepted.rawValue
})?.id
{
OrderConfirmedView()
}
}
.onAppear() {
startFetchStatus()
}
}
func startFetchStatus() {
timer = Timer.publish(every: 20, on: .main, in: .common)
.autoconnect()
.sink { _ in
syncViewModel.fetchOrder(id: syncViewModel._order.id)
}
}
}
The function startFetchStatus() gets the data from the backend every 20 seconds, and it looks like this, for example: Fetch response
This is the CircularTimer View :
let timer = Timer
.publish(every: 5, on: .main, in: .common)
.autoconnect()
#available(iOS 15, *)
struct CircularTimer: View {
#EnvironmentObject var syncViewModel : SyncViewModel
#State var orderDate : Date
#State var orderDeliveryDate : Date
#State var onTick: Double = 1
#State var savedOnTick : Double = 1
let date = Date()
var body: some View {
VStack(spacing : 0){
Image("clock_button")
ZStack{
Circle()
.fill(Color.clear)
.frame(width: 250, height: 250)
.overlay(
Circle().stroke(Color.gray.opacity(22/100), lineWidth: 5)
)
Circle()
.fill(Color.clear)
.frame(width: 250, height: 250)
.overlay(
Circle().trim(from:0, to: onTick)
.stroke(
style: StrokeStyle(
lineWidth: 5,
lineCap: .round ,
lineJoin:.round
)
)
.foregroundColor(
( completed() ? Color.orange : Color.orange)
).animation(
.easeInOut(duration: 0.2)
)
)
.rotationEffect(Angle(degrees: 270.0))
Image("indicator_ellipse")
.resizable()
.frame(width: 230, height: 230)
}
.onAppear {
getData()
print(savedOnTick)
}
.onDisappear {
saveData()
}
}
.onReceive(timer) { time in
progress(time: Int(time.timeIntervalSince1970))
}
}
func completed() -> Bool {
return onTick == 1
}
func progress(time: Int) {
let minutesOrderDeliveryDate = Int(orderDeliveryDate.timeIntervalSince1970)
let minutesOrderDate = Int(orderDate.timeIntervalSince1970)
let minutesCurrentDate = time
let totalMinutes = minutesOrderDeliveryDate - minutesOrderDate
let remainingMinutes = minutesOrderDeliveryDate - minutesCurrentDate
onTick = CGFloat(remainingMinutes) / CGFloat(totalMinutes)
}
func dateFormatTime(date : String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.calendar = Calendar(identifier: .gregorian)
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
return dateFormatter.date(from: date) ?? Date()
}
func saveData() {
UserDefaults.standard.set(onTick, forKey: "onTick")
}
func getData() {
onTick = UserDefaults.standard.double(forKey: "onTick")
}
}
This is OrderConfirmedView :
struct OrderConfirmedVieww: View {
#EnvironmentObject var syncViewModel : SyncViewModel
#State var nowDate: Date = Date()
var body: some View {
VStack {
Spacer()
Text(Texts.orderConfirmedText1)
.font(.title)
.fontWeight(.semibold)
.foregroundColor(.colorGrayDark)
.multilineTextAlignment(.center)
.lineLimit(3)
.padding(40)
CircularTimer(orderDate: dateFormatTime(date: syncViewModel._order.date ?? ""), orderDeliveryDate: dateFormatTime(date: syncViewModel._order.deliveryDate ?? ""))
.padding()
// Spacer()
Text(Texts.orderOraLivrareText)
.font(.headline)
.fontWeight(.thin)
.padding(.bottom)
Text(dateFormatTime(date: syncViewModel._order.deliveryDate ?? ""), style: .time)
.font(.title2)
.fontWeight(.bold)
Spacer()
Spacer()
Button {
} label: {
Text(Texts.orderButtonText)
.font(.headline)
.foregroundColor(.white)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.onboardingColor)
.cornerRadius(20)
}
.padding()
}
}
func dateFormatTime(date : String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.timeZone = .current
return dateFormatter.date(from: date) ?? Date.now
}
}
I've made a similiar question yesterday, but I have fixed the problem. Now I have another issue and I made a new question to ask.
I've made a Circular Timer which countdown : CircularTimer
But if I'm closing the view, and open it again, it starts again from scratch. How can I save the progress of the timer or something like that, so if I'm closing the view, when I'm coming back to be where it was last time ?
Thanks !
This is WaitingOrderView.
struct WaitingOrderView: View {
#State private var timer: AnyCancellable?
#EnvironmentObject var syncViewModel : SyncViewModel
var body: some View {
ZStack {
if syncViewModel._order.id == 0 && syncViewModel._order.status == 0 {
CartView()
}
else if syncViewModel._order.status == syncViewModel.statusList.first(where: { status in
status.key == StatusKey.accepted.rawValue
})?.id
{
OrderConfirmedView()
}
}
.onAppear() {
startFetchStatus()
}
}
func startFetchStatus() {
timer = Timer.publish(every: 20, on: .main, in: .common)
.autoconnect()
.sink { _ in
syncViewModel.fetchOrder(id: syncViewModel._order.id)
}
}
}
The function startFetchStatus() gets the data from the backend every 20 seconds, and it looks like this, for example: Fetch response
This is the CircularTimer View :
let timer = Timer
.publish(every: 1, on: .main, in: .common)
.autoconnect()
#available(iOS 15, *)
struct CircularTimer: View {
var orderDate : Date
var orderDeliveryDate : Date
#State var onTick: CGFloat = 1
let date = Date()
var body: some View {
VStack(spacing : 0){
Image("clock_button")
ZStack{
Circle()
.fill(Color.clear)
.frame(width: 250, height: 250)
.overlay(
Circle().stroke(Color.gray.opacity(22/100), lineWidth: 5)
)
Circle()
.fill(Color.clear)
.frame(width: 250, height: 250)
.overlay(
Circle().trim(from:0, to: onTick)
.stroke(
style: StrokeStyle(
lineWidth: 5,
lineCap: .round ,
lineJoin:.round
)
)
.foregroundColor(
( completed() ? Color.orange: Color.orange)
).animation(
.easeInOut(duration: 0.2)
)
)
.rotationEffect(Angle(degrees: 270.0))
Image("indicator_ellipse")
.resizable()
.frame(width: 230, height: 230)
}
}.onReceive(timer) { time in
progress(time: Int(time.timeIntervalSince1970))
}
}
func completed() -> Bool {
return onTick == 1
}
func progress(time: Int) {
let minutesOrderDeliveryDate = Int(orderDeliveryDate.timeIntervalSince1970)
let minutesOrderDate = Int(orderDate.timeIntervalSince1970)
let minutesCurrentDate = time
let totalMinutes = minutesOrderDeliveryDate - minutesOrderDate
let remainingMinutes = minutesOrderDeliveryDate - minutesCurrentDate
onTick = CGFloat(remainingMinutes) / CGFloat(totalMinutes)
print(onTick)
}
func dateFormatTime(date : String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.timeZone = .current
return dateFormatter.date(from: date) ?? Date.now
}
}
This is OrderConfirmedView :
struct OrderConfirmedVieww: View {
#EnvironmentObject var syncViewModel : SyncViewModel
#State var nowDate: Date = Date()
var body: some View {
VStack {
Spacer()
Text(Texts.orderConfirmedText1)
.font(.title)
.fontWeight(.semibold)
.foregroundColor(.colorGrayDark)
.multilineTextAlignment(.center)
.lineLimit(3)
.padding(40)
CircularTimer(orderDate: dateFormatTime(date: syncViewModel._order.date ?? ""), orderDeliveryDate: dateFormatTime(date: syncViewModel._order.deliveryDate ?? ""))
.padding()
// Spacer()
Text(Texts.orderOraLivrareText)
.font(.headline)
.fontWeight(.thin)
.padding(.bottom)
Text(dateFormatTime(date: syncViewModel._order.deliveryDate ?? ""), style: .time)
.font(.title2)
.fontWeight(.bold)
Spacer()
Spacer()
Button {
} label: {
Text(Texts.orderButtonText)
.font(.headline)
.foregroundColor(.white)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.onboardingColor)
.cornerRadius(20)
}
.padding()
}
}
func dateFormatTime(date : String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.timeZone = .current
return dateFormatter.date(from: date) ?? Date.now
}
}
I need some help. I figured out how to make a Circular Timer, but instead of that, I want to make it with Dates, and my example is using Int values. For example, I'm trying to countdown from a Future Date ( Example : February 4 11:00 PM ) to Date ( February 4 9:00 PM ).
This is the code that I wrote :
import SwiftUI
let timer = Timer
.publish(every: 1, on: .main, in: .common)
.autoconnect()
struct CircularTimer: View {
#State var counter: Int = 0
var countTo: Int = 120
var nowDate = Date()
var futureDate = Date.distantFuture
var body: some View {
VStack{
ZStack{
Circle()
.fill(Color.clear)
.frame(width: 250, height: 250)
.overlay(
Circle().stroke(Color.green, lineWidth: 25)
)
Circle()
.fill(Color.clear)
.frame(width: 250, height: 250)
.overlay(
Circle().trim(from:0, to: progress())
.stroke(
style: StrokeStyle(
lineWidth: 25,
lineCap: .round,
lineJoin:.round
)
)
.foregroundColor(
(completed() ? Color.orange : Color.red)
).animation(
.easeInOut(duration: 0.2)
)
)
}
}.onReceive(timer) { time in
if (self.counter < self.countTo) {
self.counter += 1
}
}
}
func completed() -> Bool {
return progress() == 1
}
func progress() -> CGFloat {
return (CGFloat(counter) / CGFloat(countTo))
}
}
I am also a novice in SwiftUI programming, but I tried to rewrite your solution to get a desired output. All you need is to work with
DateComponents and then with TimeInterval as those two allow you to represent Date() variables in seconds, so you can easily use it for your timer. Here it is:
import SwiftUI
let timer = Timer
.publish(every: 1, on: .main, in: .common)
.autoconnect()
struct CircularTimer: View {
// MARK: Changed type to TIMEINTERVAL
#State var counter: TimeInterval = 0
// MARK: New DATE variables using DATECOMPONENTS
#State var startDate: Date = Calendar.current.date(from: DateComponents(year: 2022, month: 2, day: 4, hour: 11, minute: 00, second: 10)) ?? Date.now
var endDate: Date = Calendar.current.date(from: DateComponents(year: 2022, month: 2, day: 4, hour: 11, minute: 00, second: 00)) ?? Date.now
// MARK: Calculated TIMEINTERVAL instead of original COUNTTO variable
var timeInterval: TimeInterval {
let end = endDate
let start = startDate
return start.timeIntervalSince(end)
}
var body: some View {
NavigationView {
VStack{
ZStack{
Circle()
.fill(Color.clear)
.frame(width: 250, height: 250)
.overlay(
Circle().stroke(Color.green, lineWidth: 25)
)
Circle()
.fill(Color.clear)
.frame(width: 250, height: 250)
.overlay(
Circle().trim(from:0, to: progress())
.stroke(
style: StrokeStyle(
lineWidth: 25,
lineCap: .round,
lineJoin:.round
)
)
.foregroundColor(
(completed() ? Color.orange : Color.red)
).animation(
.easeInOut(duration: 0.2)
)
)
// MARK: Text view for DATE just to show you that timer is working
Text("\(startDate.formatted(date: .long, time: .standard))")
.font(.system(size: 10))
.foregroundColor((timeInterval == 0) ? .orange : .black)
}
}
// MARK: Changed logic for timer calculations
.onReceive(timer) { time in
if (timeInterval != 0) {
counter += 1
startDate -= 1
}
}
// MARK: A few changes to the layout
.navigationTitle("Timer")
.toolbar {
Button("Start again", action: startAgain)
}
}
}
// MARK: Function for a START AGAIN button
func startAgain() {
counter = 0
startDate = Calendar.current.date(from: DateComponents(year: 2022, month: 2, day: 4, hour: 11, minute: 00, second: 10)) ?? Date.now
return
}
func completed() -> Bool {
return progress() == 1
}
func progress() -> CGFloat {
return (CGFloat(counter) / CGFloat(timeInterval + counter))
}
}
Hello guys I'm trying to make a Calendar List in swiftUI :
I want to App get the current date info and show it in index 0 of allDays list and based on the subscription , App Generate an N number of Day object after current date automatically. ie : 365 for 1 year subscription.
The final result is look like this right now it's a hard code.
Here is my code DataModel :
import SwiftUI
import Foundation
import Combine
struct Day : Identifiable {
var id = UUID()
var name : String
var date : String
var title : String
var color : Color
var month : String
var List : [Name?]
}
struct Name : Identifiable {
var id = UUID()
var name: String
var color: Color
}
class AppState : ObservableObject {
#Published var allDays : [Day] = [
Day(name: "Sunday", date: "20", title: "", color: .pink, month: "Jun", List: [
Name(id: UUID(), name: "John", color: .pink),
Name(id: UUID(), name: "Rose", color: .pink),
Name(id: UUID(), name: "Mike", color: .pink),
]),
Day(name: "Monday", date: "21", title: "", color: .yellow, month: "Jun", List: [
Name(id: UUID(), name: "Sara", color: .yellow),
Name(id: UUID(), name: "Jack",color: .yellow),
]),
Day(name: "Tuesday", date: "22", title: "", color: .blue, month: "Jun", List: [
Name(id: UUID(), name: "Rachel",color: .blue),
]),
Day(name: "Wednesday", date: "23", title: "", color: .green, month: "Jun", List: []),
Day(name: "Thursday", date: "24", title: "", color: .orange, month: "Jun", List: []),
Day(name: "Friday", date: "25", title: "", color: .purple, month: "Jun", List: []),
Day(name: "Saturday", date: "26", title: "", color: .red, month: "Jun", List: []),
]
}
and View :
import SwiftUI
struct CalendarList: View {
#EnvironmentObject var appState : AppState
var body: some View {
NavigationView {
List {
ForEach(appState.allDays.indices, id:\.self) { index in
NavigationLink(destination: Text(appState.allDays[index].name) ) {
HStack(alignment: .top) {
RoundedRectangle(cornerRadius: 23)
.frame(width: 74, height: 74)
.foregroundColor(Color.blue)
.overlay(
VStack {
Text(appState.allDays[index].date)
.font(.system(size: 35, weight: .regular))
.foregroundColor(.white)
Text(appState.allDays[index].month)
.foregroundColor(.white)
}
)
.padding(.trailing ,4)
VStack(alignment: .leading, spacing: 5) {
Text(appState.allDays[index].name)
.font(.system(size: 20, weight: .semibold))
Text(appState.allDays[index].title)
.font(.subheadline)
.foregroundColor(Color(#colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)))
}
}
.padding(.vertical ,6)
}
}
}
.navigationTitle("Calendar")
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct CalendarList_Previews: PreviewProvider {
static var previews: some View {
CalendarList()
}
}
You can generate the Day models with a couple of DateFormatter and Calendar methods:
extension Date {
func dayOfWeek(withFormatter dateFormatter: DateFormatter) -> String? {
dateFormatter.dateFormat = "EEEE"
return dateFormatter.string(from: self).capitalized
}
func nameOfMonth(withFormatter dateFormatter: DateFormatter) -> String? {
dateFormatter.dateFormat = "LLLL"
return dateFormatter.string(from: self).capitalized
}
}
func getDays(number: Int) -> [Day] {
let today = Date()
let formatter = DateFormatter()
return (0..<number).map { index -> Day in
let date = Calendar.current.date(byAdding: .day, value: index, to: today) ?? Date()
return Day(name: date.dayOfWeek(withFormatter: formatter) ?? "", date: "\(Calendar.current.component(.day, from: date))", month: date.nameOfMonth(withFormatter: formatter) ?? "")
}
}
Update, due to comments. Full example:
struct Day : Identifiable {
var id = UUID()
var name : String
var date : String
var title : String
var color : Color
var month : String
var List : [Name?]
}
struct Name : Identifiable {
var id = UUID()
var name: String
var color: Color
}
class AppState : ObservableObject {
#Published var allDays : [Day] = []
func generateDays(number: Int){
let today = Date()
let formatter = DateFormatter()
self.allDays = (0..<number).map { index -> Day in
let date = Calendar.current.date(byAdding: .day, value: index, to: today) ?? Date()
return Day(name: date.dayOfWeek(withFormatter: formatter) ?? "", date: "\(Calendar.current.component(.day, from: date))", title: "", color: .red, month: date.nameOfMonth(withFormatter: formatter) ?? "", List: [])
}
}
}
extension Date {
func dayOfWeek(withFormatter dateFormatter: DateFormatter) -> String? {
dateFormatter.dateFormat = "EEEE"
return dateFormatter.string(from: self).capitalized
}
func nameOfMonth(withFormatter dateFormatter: DateFormatter) -> String? {
dateFormatter.dateFormat = "LLLL"
return dateFormatter.string(from: self).capitalized
}
}
struct CalendarList: View {
#EnvironmentObject var appState : AppState
var body: some View {
NavigationView {
List {
ForEach(appState.allDays.indices, id:\.self) { index in
NavigationLink(destination: Text(appState.allDays[index].name) ) {
HStack(alignment: .top) {
RoundedRectangle(cornerRadius: 23)
.frame(width: 74, height: 74)
.foregroundColor(Color.blue)
.overlay(
VStack {
Text(appState.allDays[index].date)
.font(.system(size: 35, weight: .regular))
.foregroundColor(.white)
Text(appState.allDays[index].month)
.foregroundColor(.white)
}
)
.padding(.trailing ,4)
VStack(alignment: .leading, spacing: 5) {
Text(appState.allDays[index].name)
.font(.system(size: 20, weight: .semibold))
Text(appState.allDays[index].title)
.font(.subheadline)
.foregroundColor(Color(#colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)))
}
}
.padding(.vertical ,6)
}
}
}
.navigationTitle("Calendar")
.onAppear {
appState.generateDays(number: 365)
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
This is unrelated to your issue, but I'd also personally choose to use ForEach with direct access to the Day without going through the indices:
ForEach(appState.allDays, id:\.id) { day in
NavigationLink(destination: Text(day.name) ) {
HStack(alignment: .top) {
RoundedRectangle(cornerRadius: 23)
.frame(width: 74, height: 74)
.foregroundColor(Color.blue)
.overlay(
VStack {
Text(day.date)
.font(.system(size: 35, weight: .regular))
.foregroundColor(.white)
Text(day.month)
.foregroundColor(.white)
}
)
.padding(.trailing ,4)
VStack(alignment: .leading, spacing: 5) {
Text(day.name)
.font(.system(size: 20, weight: .semibold))
Text(day.title)
.font(.subheadline)
.foregroundColor(Color(#colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)))
}
}
.padding(.vertical ,6)
}
}
*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
}
}
}