SwiftUI resize a rectangle to fit the content - swift

using SwiftUI on my project I'm try to display some data in a list.
I would like to insert on the left side of my cell a rectangle(), but I can't find the way to fix the height.
(i don't want to manual input the height otherwise it doesn't look good on different device)
I'm try using geometry render but not working.
I highlight on the attached picture my idea...
here my code:
import SwiftUI
struct MatchViewUser: View {
var match : MatchModel
var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}
var timeFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "HH:mm a"
formatter.amSymbol = "AM"
formatter.pmSymbol = "PM"
return formatter
}
var body: some View {
GeometryReader { geometry in
HStack {
Rectangle().frame(width: 30,height: geometry.size.height ,alignment: .leading)
VStack(alignment:.leading){
HStack{
Text("\(self.match.dateMatch, formatter: self.dateFormatter)")
Spacer()
Text("Time:\(self.match.dateMatch, formatter: self.timeFormatter)")
}.font(.headline).foregroundColor(.blue)
Divider().padding(.horizontal)
HStack{
VStack(alignment:.leading){
Text("Match Name:").bold()
Text("\(self.match.matchName)").font(.body)
}
Spacer()
VStack(alignment:.leading){
Text("Pitch Name").bold()
Text("\(self.match.pitchName)").font(.body)
}
Spacer()
VStack(alignment:.trailing){
Text("Player").bold()
Text("\(self.match.maxPlayer)").font(.body)
}
}.font(.headline)
}
}
}
}
}

Here is a demo of possible approach (simplified your code w/o dependent model). Prepared & tested with Xcode 11.4 / iOS 13.4
struct DemoView: View {
var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}
let dateMatch = Date()
var timeFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "HH:mm a"
formatter.amSymbol = "AM"
formatter.pmSymbol = "PM"
return formatter
}
var body: some View {
HStack {
VStack(alignment:.leading){
HStack{
Text("\(self.dateMatch, formatter: self.dateFormatter)")
Spacer()
Text("Time:\(self.dateMatch, formatter: self.timeFormatter)")
}.font(.headline).foregroundColor(.blue)
Divider().padding(.horizontal)
HStack{
VStack(alignment:.leading){
Text("Match Name:").bold()
Text("Demo1").font(.body)
}
Spacer()
VStack(alignment:.leading){
Text("Pitch Name").bold()
Text("Demo2").font(.body)
}
Spacer()
VStack(alignment:.trailing){
Text("Player").bold()
Text("10").font(.body)
}
}.font(.headline)
}.padding(.leading, 38)
}.overlay(
Rectangle().frame(width: 30)
, alignment: .leading)
}
}

Related

SwiftUI show List of Dates from Core Data

I try to show the time from in Core Data saved Dates in a List, but it isn't showing anything in the rows of the List. But it creates one row for every entry in Core Data.
struct TopBoxView: View {
#Environment(\.managedObjectContext) var newFlaschen
#FetchRequest(sortDescriptors: []) var flasche: FetchedResults<Flasche>
let dateFormatter = DateFormatter()
var body: some View {
GroupBox() {
VStack {
Text("Letzte Flaschen")
.foregroundColor(.white)
.font(.system(size: 28, weight: .medium, design: .default))
.padding(.top, 25)
List(flasche) { flaschen in //here it should create the List
Text("\(flaschen.zeit ?? "nix")")
.listRowBackground(Color("listRowColor"))
}
.scrollContentBackground(.hidden)
.padding(.horizontal, 13.0)
.multilineTextAlignment(.center)
_VSpacer()
.frame(height: 10)
}
}
.groupBoxStyle(GroupBoxStandardStyle(width: 290))
.padding(.top, 10)
.scrollIndicators(.hidden)
}
}
At the Moment the dates are already saved as Strings in CoreData:
struct BottomBoxView: View {
let dateFormatter = DateFormatter()
#State var menge = ""
#State var time = Date.now
#State var anmerkungen = ""
#Environment(\.managedObjectContext) var newFlasche
#FetchRequest(sortDescriptors: []) var flasche: FetchedResults<Flasche>
func submit() {
let neueFlasche = Flasche(context: newFlasche)
let formattedTime = dateFormatter.string(from: time)
neueFlasche.id = UUID()
neueFlasche.menge = menge
neueFlasche.zeit = formattedTime
neueFlasche.anmerkungen = anmerkungen
try? newFlasche.save()
}
the function is called by a button
I should add, that when i try to show another String, that is created as a string, not as a Date, it shows it without problems.
I tried .formatted and i tried to save it as a string
I don't know what i did different to some of my previous tries, but now I have the Time saved as a Date and with this code I show it:
List(flasche) { flasche in
Text((flasche.zeit?.formatted() ?? "none"))
.listRowBackground(Color("listRowColor"))
}
Thank you, for your Help!

Streak builder app using Swift and SwiftUI

I am looking to make a Streak builder app using Swift and SwiftUI. However, I am finding it difficult to create the logic for the counter using the Date(). Any suggestions will be highly appreciated.
Mainly I wanna replicate the Streak thing from the Duolingo app.
// I have this extension to follow up on the Date from the time user clicks it.
extension Date {
// for tomorow's Date
static var tomorrow: Date { return Date().dayAfter }
static var today: Date {return Date()}
var dayAfter: Date {
return Calendar.current.date(byAdding: .day, value: 1, to: Date())!
}
}
// More or less this was supposed to be my view.
struct StreakTrial: View {
#State var counter = 0
#State var TapDate: Date = Date.today
var body: some View {
NavigationView {
VStack{
Button {
// if TapDate != Date.today {
// counter += 1
// let TapDate = Date.tomorrow
// }
// else if TapDate == Date.tomorrow {
// counter = counter
// }
} label: {
Image(systemName: "flame")
.resizable()
.frame(width: 40, height: 50)
.padding()
.scaledToFit()
.background(Color.gray)
.foregroundColor(Color.orange)
.cornerRadius(12)
Text("\(counter)").foregroundColor(.gray)
}
Text("\(Date())")
.padding()
Text("\(Date().dayAfter)")
.padding()
}
}
}
}
**SO I TRIED SOME TUTORIALS OF #NICK SARNO WHICH GOES LIKE SWIFTFUL THINKING ON YOUTUBE AND GOT IT DONE**
*This code is compatible with Xcode 14.0*
import SwiftUI
extension Date {
// for tomorow's Date
static var tomorrow: Date { return Date().dayAfter }
static var today: Date {return Date()}
var dayAfter: Date {
return Calendar.current.date(byAdding: .day, value: 1, to: Date())!
// just add .minute after byAdding: , to create a streak minute counter and check the logic.
}
static func getTodayDate() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "E d MMM yyyy"
//to continue with the minute streak builder just add "E d MMM yyyy h:mm a" above, it will allow date formatting with minutes and follow the changes in dayAfter
return dateFormatter.string(from: Date.today)
}
static func getTomDate() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "E d MMM yyyy"
return dateFormatter.string(from: Date.tomorrow)
}
}
struct StreakApp: View {
#AppStorage("counter") var counter = 0
#AppStorage("tapDate") var TapDate: String?
#AppStorage("Tappable") var ButtonTapped = false
var body: some View {
NavigationView {
VStack{
VStack {
Text("\(counter)").foregroundColor(.gray)
Text("Restore your streak on ")
Text(TapDate ?? "No Date")
Image(systemName: "flame")
.resizable()
.frame(width: 40, height: 50)
.padding()
.scaledToFit()
.background(ButtonTapped ? Color.red : Color.gray)
.foregroundColor(ButtonTapped ? Color.orange : Color.black)
.cornerRadius(12)
}
Button {
if TapDate == nil {
//Check if user has already tapped
self.ButtonTapped = true
counter += 1
self.TapDate = ("\(Date.getTomDate())")
}
else if ("\(Date.getTodayDate())") == TapDate {
//Check for the consecutive Day of Streak
self.TapDate = ("\(Date.getTomDate())")
counter += 1
//Let's light the flame back again.
self.ButtonTapped = true
}
} label: {
RoundedRectangle(cornerRadius: 12, style: .continuous)
.foregroundColor(.black)
.frame(width: 120, height: 40)
.overlay {
Text("Add Streak")
.foregroundColor(.white)
}
}
.padding()
//This button is only for testing purpose.
Button {
self.TapDate = nil
self.ButtonTapped = false
self.counter = 0
} label: {
RoundedRectangle(cornerRadius: 12, style: .continuous)
.foregroundColor(.black)
.frame(width: 160, height: 40)
.overlay {
Text("Reset Streak")
.foregroundColor(.white)
}
}
}
//Ensuer the flame dies out if we run into any other day except today or tommorow.
.onAppear {
if ("\(Date.getTodayDate())") == TapDate ||
("\(Date.getTomDate())") == TapDate {
self.ButtonTapped = true
}
//Breaking the Streak
else {
self.TapDate = nil
self.ButtonTapped = false
self.counter = 0
}
}
}
}
}
struct StreakApp_Previews: PreviewProvider {
static var previews: some View {
StreakApp()
}
}

SwiftUI: DatePicker/Date() formating

I have a .sheet element, that acts as a form when a user is adding to a calendar. Everything works as expected, but as soon as they submit, and upload the Date, Start Time, and end time into firebase where it's held, I noticed a problem. The date and time were formated weird.
My question is, how can I change the var scheduledate to a mm/dd/yy format when stored, and how can I change the var starttime and var endtime to a h:mm format when stored.
Here's my code:
struct SheetView: View {
var userEmail = Auth.auth().currentUser?.email
#Environment(\.dismiss) var dismiss
#State private var scheduledate = Date() //Store this as mm/dd/yy
#State private var startTime = Date() //Store this as h:mm
#State private var endTime = Date() //Store this as h:mm
#State private var scheduleairplane = ""
#State private var scheduleinstructor = ""
var body: some View {
VStack {
HStack {
Text("New Flight")
.font(.title)
.fontWeight(.bold)
Spacer()
Button("Cancel") {
dismiss()
}
}
.padding()
VStack {
DatePicker("Date", selection: $scheduledate, displayedComponents: .date)
.datePickerStyle(GraphicalDatePickerStyle())
.frame(maxHeight: 400)
DatePicker("Start Time", selection: $startTime, displayedComponents: .hourAndMinute)
.datePickerStyle(GraphicalDatePickerStyle())
.padding(.leading)
DatePicker("End Time", selection: $endTime, displayedComponents: .hourAndMinute)
.datePickerStyle(GraphicalDatePickerStyle())
.padding(.leading)
}
VStack {
TextField("Airplane...", text: self.$scheduleairplane)
.padding([.leading, .trailing])
.offset(x: 10)
.frame(height: 30)
.overlay(
RoundedRectangle(cornerRadius: 30)
.stroke(Color.white, lineWidth: 1)
.padding([.leading, .trailing])
)
TextField("Instructor...", text: self.$scheduleinstructor)
.padding([.leading, .trailing])
.offset(x: 10)
.frame(height: 30)
.overlay(
RoundedRectangle(cornerRadius: 30)
.stroke(Color.white, lineWidth: 1)
.padding([.leading, .trailing])
)
}
Spacer(minLength: 0)
Button(action: {
let doc = db.collection("Scheduled").document("\(userEmail ?? "Error")")
// Atomically add a new region to the "regions" array field.
doc.updateData([
"Airplanes": FieldValue.arrayUnion(["\(scheduleairplane)"])
])
doc.updateData([
"Date": FieldValue.arrayUnion(["\(scheduledate)"])
])
doc.updateData([
"Time": FieldValue.arrayUnion(["\(ScheduledTime)"])
])
doc.updateData([
"Instructor": FieldValue.arrayUnion(["\(scheduleinstructor)"])
])
}) {
Text("Submit")
}
.foregroundColor(.white)
.frame(width: 120, height: 45)
.background(Color("Blue"))
.cornerRadius(30)
.padding(.bottom)
}
}
}
Thanks for all the help but I found an answer
here that works very well and is easy.
I used 3 different functions that I ran when I click the button. Then I send them off to firebase with the new values.
func updateDate() {
let selecteddate = scheduleddate //Here it gets the date and saves as another variable
let formatter1 = DateFormatter()
formatter1.dateStyle = .short
//I then made a saved string called newscheduledate to use this new variable anywhere in my project.
newscheduledate = formatter1.string(from: selecteddate) //Here is when it sets the conversion to a string which I used when I sent to firebase.
}
I then used this piece of code below twice, for the start time, and the end time.
func updateTime() {
let selectedtime = startTime //Here it gets the date
let formatter2 = DateFormatter()
formatter2.timeStyle = .medium
//I have a saved string called newstarttime to use this new variable anywhere in my project.
newstarttime = formatter2.string(from: selectedtime)
}
class GeneralExtension{
static func DateToStr(date:Date,format:String = "yyyy/MM/dd HH:mm:ss")->String{
let timeFormatter = DateFormatter()
timeFormatter.locale = Locale.current
timeFormatter.timeZone = TimeZone.current
timeFormatter.dateFormat = format
let nowTimestr = timeFormatter.string(from: date)
return nowTimestr
}
static func StrToDate(dateStr:String,format:String = "yyyy/MM/dd HH:mm:ss")->Date{
var cbDate:Date = Date()
if(!dateStr.isEmpty){
let dateFormatter=DateFormatter()
dateFormatter.dateFormat=format
let tmpDate = dateFormatter.date(from: dateStr)
if let tmpDate = tmpDate{
cbDate = tmpDate
}
}
return cbDate
}
}
example
GeneralExtension.DateToStr(date: dateSetting,format: "MM")
or
extension String{
func StrToDate(format:String = "yyyy/MM/dd HH:mm:ss")->Date{
var cbDate:Date = Date()
if(!self.isEmpty){
let dateFormatter=DateFormatter()
dateFormatter.dateFormat=format
let tmpDate = dateFormatter.date(from: self)
if let tmpDate = tmpDate{
cbDate = tmpDate
}
}
return cbDate
}
}
extension Date{
func DateToStr(format:String = "yyyy/MM/dd HH:mm:ss")->String{
let timeFormatter = DateFormatter()
timeFormatter.locale = Locale.current
timeFormatter.timeZone = TimeZone.current
timeFormatter.dateFormat = format
let nowTimestr = timeFormatter.string(from: self)
return nowTimestr
}
}
example
let date = Date()
let dateStr = date.DateToStr("MM")
let convertDate = dateStr.StrToDate()

Remove Blurred Preview for ContextMenu on NavigationLink in SwiftUI

I'm trying to add a contextMenu to a NaviagationLink in swiftUI. The result as you can see below is a blurred view is showing as a preview.
NavigationLink {
Text("Item at \(item.timestamp!, formatter: itemFormatter)")
} label: {
Text(item.timestamp!, formatter: itemFormatter)
.padding()
}
.contextMenu(
ContextMenu {
Button(action: {
print("")
}) {
Label("Save", systemImage: "square.and.arrow.up")
}
}
)
private let itemFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .medium
return formatter
}()
I put together some example code to see if I could understand the problem. It's the underlying text in your view which gets blurred by the ContextMenu action. If the items are sufficiently spaced I am not seeing the blurring issue. Here is the code example I set up.
struct ItemWithTimeStamp: Identifiable, Hashable {
var id: UUID
let timestamp: Date
let name: String
}
struct ContentView: View {
let examples = [ItemWithTimeStamp(id: UUID(), timestamp: Date(), name: "Thing One"), ItemWithTimeStamp(id: UUID(), timestamp: Date(timeInterval: 1234, since: .now), name: "Thing Two"), ItemWithTimeStamp(id: UUID(), timestamp: Date(timeInterval: 6543, since: .now), name: "Thing Three")]
var body: some View {
NavigationView {
VStack {
ForEach(examples, id: \.id) { item in
NavigationLink {
Text("Item at \(item.timestamp, formatter: itemFormatter)")
} label: {
Text(item.timestamp, formatter: itemFormatter)
.padding()
}
.contextMenu(
ContextMenu {
Button(action: {
print("Saved")
}) {
Label("Save", systemImage: "square.and.arrow.up")
}
}
)
}
}
}
}
private let itemFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .medium
return formatter
}()
}
This is the View before activating the context menu.
Here I'm activating the ContextMenu and you can see the blurred text in the background. But in my case with standard .padding() between the items the overlap isn't happening so I'm not seeing the blurring issue as you're getting. But I'm not sure what the rest of your view looks like.
I don't know if it suits your purposes but you might try placing the NavigationLink's in a List as they are definitely separated out and will not overlap. Replace the VStack with List in my code to see an example of this.

swiftUI - Date Comparison

I need to compare 2 dates and if it is the same date, do something... (dd/MM to dd/MM only). I generate today's date, then set my own date and when compared, the same dates do not match. (When displaying each date (as Text), the result is the same. E.g. 10-04 and 10-04.)
struct eddEntryView : View { // ContentView
let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM"
return formatter
}()
#State private var today = Date()
let specificDate: Date = {
var components = DateComponents()
components.day = 14
components.month = 04
let newDate = Calendar.current.date(from: components) ?? Date()
return newDate
}()
var entry: Provider.Entry
var body: some View {
HStack{
VStack(alignment: .leading){
if Calendar.current.isDateInToday(specificDate) // today is 14-04, specific date is set for 14-04, but it doesn't work
{
Text("THE SAME: \(specificDate, formatter: dateFormatter)")
.font(.title)
.foregroundColor(Color(.label))
.bold()
Spacer()
} else {
Text("Not the same day... \(specificDate, formatter: dateFormatter)")
.font(.title)
.foregroundColor(Color(.label))
.bold()
Spacer()
}
}
}
There is a function isDateInToday(Date) on Calendar. You could use it like this:
if Calendar.current.isDateInToday(dueDate) {
//...
}
There is also a function that compares whether to date fall on the same day:
Calendar.current.isDate(today, inSameDayAs: dueDate)
Solution:
let today = Date() // Actual date
func formatDate(date: Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM"
return formatter.string(from: date)
}
and then:
if ("\(formatDate(date: today))") .elementsEqual("14-04") // specific date {
Text("the same: \(formatDate(date: today))")
// ... do something for the same day
Spacer()
} else {
// ...
}