Post

Replies

Boosts

Views

Created

Rotate View around an other View SwiftUI
Hello I created a custom shape in SwiftUI and I am trying to rotate it around a circle, but it works just on the top part of the circle, can you help me make it rotate exactly around the circle? (And also can I get the same effect using radians? How?) Here is the code: import SwiftUI struct MyGameView: View { @State private var degress: Double = 0 let timer = Timer.publish(every: 0.05, on: .main, in: .common).autoconnect() var body: some View { VStack{ ZStack{ Circle() .frame(width: 80) ZStack{ Circle() .stroke(lineWidth: 1) .frame(width: 300) BallonShape() .scaledToFit() .scaleEffect(0.2) .foregroundColor(.red) .rotationEffect(.degrees(degress), anchor: .bottom) .offset(x: 0, y: -170) } } } .onReceive(timer) { input in withAnimation(.easeIn(duration: 0.05).speed(10)){ degress += 1 } } } } struct BallonShape: Shape { func path(in rect: CGRect) -> Path { Path { path in path.move(to: CGPoint(x: rect.midX, y: (rect.maxY + rect.midY) / 2)) path.addCurve(to: CGPoint(x: rect.midX, y: rect.minY), control1: CGPoint(x: (rect.midX + rect.minX) / 2, y: rect.minY), control2: CGPoint(x: (rect.midX + rect.minX) / 2, y: rect.minY)) path.addCurve(to: CGPoint(x: rect.midX, y: (rect.maxY + rect.midY) / 2), control1: CGPoint(x: (rect.midX + rect.maxX) / 2, y: rect.minY), control2: CGPoint(x: (rect.midX + rect.maxX) / 2, y: rect.minY)) } } } Thank You very much!
3
0
2.1k
Sep ’21
onDelete not working properly in my app
Hello In my app I have a list of items in a ForEach and at the end of the ForEach there is a .onDelete. (This is in a View that I called AllHistoryView) The items are represented by a CoreData NSManagedObject that I called LifetimeInputs with 3 properties: date: Date, imageTemplate: String, valori: Double The problem is that, when I add (in a different View) an item with the date of tomorrow and then I add another to item with the date of today and then go to the AllHistoryView where there are all the items and delete slowly the item with date of tomorrow (especially at the end of the swipe action) instead of deleting the item that I swiped it deletes the on before it, how can I solve this problem? Here is the AllHistoryView code: import SwiftUI import CoreData struct AllHistoryView: View { @Environment(\.managedObjectContext) var viewContext @FetchRequest(entity: LifetimeInputs.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \LifetimeInputs.date, ascending: true)], animation: .default) var lifetimeInputsModel: FetchedResults<LifetimeInputs> @State private var text: String = "" @State private var ascending: Bool = true @State var sortDescriptor: NSSortDescriptor = NSSortDescriptor(keyPath: \LifetimeInputs.date, ascending: true) @Environment(\.dynamicTypeSize) var dynamicTypeSize var size: CGFloat{ if UIDevice.current.userInterfaceIdiom == .phone { switch dynamicTypeSize { case .xSmall: return 11 case .small: return 13 case .medium: return 15 case .large: return 17 case .xLarge: return 19 case .xxLarge: return 21 case .xxxLarge: return 23 default: return 23 } } else { switch dynamicTypeSize { case .xSmall: return 13 case .small: return 15 case .medium: return 17 case .large: return 19 case .xLarge: return 21 case .xxLarge: return 23 case .xxxLarge: return 25 case .accessibility1: return 27 case .accessibility2: return 29 default: return 29 } } } var body: some View { theView() } @ViewBuilder func theView() -> some View{ NavigationView{ if !lifetimeInputsModel.isEmpty{ List{ SectionList(sortDescripter: sortDescriptor, text: $text) .environment(\.managedObjectContext, viewContext) .onChange(of: ascending, perform: { _ in if ascending { withAnimation { sortDescriptor = NSSortDescriptor(keyPath: \LifetimeInputs.date, ascending: true) } } else { withAnimation { sortDescriptor = NSSortDescriptor(keyPath: \LifetimeInputs.date, ascending: false) } } }) } .searchable(text: $text, placement: .navigationBarDrawer, prompt: "Quantity or date".localized()) .navigationBarTitle("History", displayMode: .inline) .toolbar{ ToolbarItem(placement: .automatic) { Image(systemName: "arrow.up.arrow.down.circle") .foregroundColor(.primary) .font(.system(size: size)) .rotation3DEffect(.degrees(ascending ? 0 : 180), axis: (x: 1, y: 0, z: 0)) .opacity(0.5) .onTapGesture { ascending.toggle() } } } } else{ VStack{ Text("No Data".localized()) .font(.largeTitle) .fontWeight(.semibold) .foregroundColor(.secondary) } .padding(.bottom) .navigationBarTitle("History", displayMode: .inline) } } } } struct SectionList: View { @Environment(\.managedObjectContext) var viewContext @FetchRequest var lifetimeInputsModel: FetchedResults<LifetimeInputs> @Binding var text: String init(sortDescripter: NSSortDescriptor, text: Binding<String>) { let request: NSFetchRequest<LifetimeInputs> = LifetimeInputs.fetchRequest() request.sortDescriptors = [sortDescripter] _lifetimeInputsModel = FetchRequest<LifetimeInputs>(fetchRequest: request) self._text = text } @FetchRequest(entity: Limit.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Limit.date, ascending: true)], animation: .default) var limit: FetchedResults<Limit> @Environment(\.dynamicTypeSize) var dynamicTypeSize var size: CGFloat{ if UIDevice.current.userInterfaceIdiom == .phone { switch dynamicTypeSize { case .xSmall: return 11 case .small: return 13 case .medium: return 15 case .large: return 17 case .xLarge: return 19 case .xxLarge: return 21 case .xxxLarge: return 23 default: return 23 } } else { switch dynamicTypeSize { case .xSmall: return 13 case .small: return 15 case .medium: return 17 case .large: return 19 case .xLarge: return 21 case .xxLarge: return 23 case .xxxLarge: return 25 case .accessibility1: return 27 case .accessibility2: return 29 default: return 29 } } } @StateObject var lifeTimeInputsViewModel = LifeTimeInputsViewModel() var body: some View { Section{ ForEach(lifetimeInputsModel.filter { text.isEmpty || "\($0)".contains(text) }){ lifetimeInputs in HStack{ Text("\(lifetimeInputs.valori, specifier: format(unita: !limit.isEmpty ? limit[0].unita ?? ml : ml)) \(!limit.isEmpty ? limit[0].unita ?? ml: ml)") .font(.system(size: size)) Spacer() Text("\(dateFormatter.string(from: lifetimeInputs.date ?? Date()))") .font(.system(size: size)) } } .onDelete(perform: { offsets in lifeTimeInputsViewModel.deleteItems(offsets: offsets) }) } header: { Text("History".localized()).font(.system(size: size - 4)) } } } Thank You very much!
0
0
742
Sep ’21
Notify when @FetchRequest changes?
Hello @FetchRequest( entity: Book(), sortDescriptors: [] ) var books: FetchedResults<Book> How can I get notified when books changes? I was thinking about putting this... .onReceive(NotificationCenter.default.publisher(for: .NSManagedObjectContextDidSave), perform: { _ in}) ... in my main View but this would notify me if anything gets saved and that is not what I want. I want to get notified just if a certain FetchRequest changes (in this case books)? How can I do that? Thank You!
4
1
2.6k
Sep ’21
Notify when @FetchRequest changes?
Hello @FetchRequest( entity: Book(), sortDescriptors: [] ) var books: FetchedResults<Book> How can I get notified when books changes? I was thinking about putting this... .onReceive(NotificationCenter.default.publisher(for: .NSManagedObjectContextDidSave), perform: { _ in}) ... in my main View but this would notify me if anything gets saved and that is not what I want. I want to get notified just if a certain FetchRequest changes (in this case books)? And in another thread I was told to use... .onRecevie(books.publisher){ _ in .... } ...however using this code publishes each member of the sequence as a separate element, I want it to publish just once? Thank You!
0
0
573
Sep ’21
Use onChange on FetchedResults/@FetchRequest variable or get notified when the variable changes
Hello @FetchRequest( entity: Book.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Book.entity.date, ascending: true)] ) var books: FetchedResults<Book.entity> How can I get notified when anything in book changes without using .onRecevie(books.publisher){ _ in .... } And is there any way to use .onChange modifier with books? Thank You!
1
1
1.1k
Sep ’21
Core Data Predicate Filter By Today's Date
Hello I am using a SwiftUI @FetchRequest to displays Core Data items, one of the properties of the entity is date, and I want to filter items by today's Date, this is the @FetchRequest: @FetchRequest( entity: Book.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Book.date, ascending: true)], predicate: NSPredicate(format: "date == %@"), animation: .default) var books: FetchedResults<Book> How do I complete the NSPredicate to make it work? (I know that there are no arguments in the predicate yet) Thank You!
1
0
4.8k
Sep ’21
.onDelete resets NSPredicate (Core Data, SwiftUI)
Hello I have a list of data in SwiftUI. The data shown in the list can be saved or deleted by using Core Data. In the @FetchRequest property that I am using to display data, I initialized an NSPredicate and in the view, I gave the possibility to the user to change the value of the predicate so that he can filter data, and that is all working, the problem shows up when I delete data from the list when I do so the predicate becomes nil and I don't know why. Here is the code struct SectionList: View { @FetchRequest( entity: LifetimeInputs.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \LifetimeInputs.date, ascending: true)], predicate: nil ) var lifetimeInputsModel: FetchedResults<LifetimeInputs> @FetchRequest(entity: Limit.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Limit.date, ascending: false)]) var limit: FetchedResults<Limit> @Environment(\.dynamicTypeSize) var dynamicTypeSize var size: CGFloat{ if UIDevice.current.userInterfaceIdiom == .phone { switch dynamicTypeSize { case .xSmall: return 11 case .small: return 13 case .medium: return 15 case .large: return 17 case .xLarge: return 19 case .xxLarge: return 21 case .xxxLarge: return 23 default: return 23 } } else { switch dynamicTypeSize { case .xSmall: return 13 case .small: return 15 case .medium: return 17 case .large: return 19 case .xLarge: return 21 case .xxLarge: return 23 case .xxxLarge: return 25 case .accessibility1: return 27 case .accessibility2: return 29 default: return 29 } } } @StateObject var lifeTimeInputsViewModel = LifeTimeInputsViewModel() @Environment(\.managedObjectContext) private var viewContext var conversion: Double { if !limit.isEmpty{ switch limit.last?.unita { case Unit.ml.rawValue: return 1 case Unit.oz.rawValue: return 29.574 default: return 1 } } return 1 } @State private var wantsToFilter: Bool = false @State private var dateSelected = Date() var body: some View { Section{ HStack{ Text("Filter") Spacer() Image(systemName: wantsToFilter ? "checkmark.circle" : "xmark") .font(.system(size: size + 6)) .foregroundColor(wantsToFilter ? .green : .red) .onTapGesture { wantsToFilter.toggle() if wantsToFilter{ lifetimeInputsModel.nsPredicate = NSPredicate( format: "date >= %@ && date <= %@", Calendar.current.dateInterval(of: .day, for: dateSelected)!.start as CVarArg, Calendar.current.dateInterval(of: .day, for: dateSelected)!.end as CVarArg ) } else{ lifetimeInputsModel.nsPredicate = nil } } } DatePicker("Date", selection: $dateSelected, displayedComponents: .date) } header: { Text("Filter") .font(.system(size: size - 4)) } .onChange(of: dateSelected, perform: { _ in if wantsToFilter{ lifetimeInputsModel.nsPredicate = NSPredicate( format: "date >= %@ && date <= %@", Calendar.current.dateInterval(of: .day, for: dateSelected)!.start as CVarArg, Calendar.current.dateInterval(of: .day, for: dateSelected)!.end as CVarArg ) } }) Section{ ForEach(lifetimeInputsModel){ lifetimeInputs in HStack{ Text("\(lifetimeInputs.valori / conversion, specifier: format(unita: !limit.isEmpty ? limit[limit.count - 1].unita ?? ml : ml)) \(!limit.isEmpty ? limit[limit.count - 1].unita ?? ml: ml)") .font(.system(size: size)) Spacer() Text("\(dateFormatter.string(from: lifetimeInputs.date ?? Date()))") .font(.system(size: size)) } } .onDelete{lifeTimeInputsViewModel.deleteItems(offsets: $0, lifetimeInputsModel: lifetimeInputsModel); } } header: { Text("History \(lifetimeInputsModel.count)".localized()).font(.system(size: size - 4)) } } } Thank You!
3
0
1.5k
Oct ’21
SwiftUI Core Data save single values
Hello I am using CoreData in my App and want to save a single Picker value. I could create an entity with an Integer attribute and always edit the first object in the EntityList. But that doesn't sound like a clean solution. The Picker is placed inside a settings view and has to be synced with iCloud. Is there a simple way to do this? Thank You
1
0
713
Oct ’21
@propertywrapper in SwiftUI
Hello I created a @propertyWrapper to limit the number a variable can reach. I tried it in a SwiftUI view with a button that increases the value of the variable and it works, the variable stops at the maximum number set in the initializer. However if I try it with a Textflied it doesn't work, if I insert a higher number than the one set nothing happens, it makes me do it. How can I solve this problem, I know the problem has to do with Binding but I don't know exactly what it is, here is the code: import SwiftUI struct ContentView: View { @Maximum(maximum: 12) var quantity: Int var body: some View { NavigationView{ Form{ TextField("", value: $quantity, format: .number, prompt: Text("Pizza").foregroundColor(.red)) Button { quantity += 1 } label: { Text("\(quantity)") } } } } } @propertyWrapper struct Maximum<T: Comparable> where T: Numeric { @State private var number: T = 0 var max: T var wrappedValue: T { get { number } nonmutating set { number = min(newValue, max) } } var projectedValue: Binding<T> { Binding( get: { wrappedValue }, set: { wrappedValue = $0 } ) } init(maximum: T){ max = maximum } } extension Maximum: DynamicProperty { } Thank You for your time
0
0
958
Dec ’21
Siri Shortcuts with CoreData
Hello I created a simple SwiftUI app with Core Data and I want to be able to add data via the shortcuts app, I created a shortcut that takes some text as input and returns it in uppercase and when I run the shortcut in the shortcuts app, it works, however when I added an "add" function (to save data in the Core Data database) to the intent handle function, and I run it again nothing is saved in the app, here is the code: class MakeUppercaseIntentHandler: NSObject, MakeUppercaseIntentHandling { let persistenceController = PersistenceController() func handle(intent: MakeUppercaseIntent, completion: @escaping (MakeUppercaseIntentResponse) -> Void) { if let inputText = intent.text { let uppercaseText = inputText.uppercased() completion(MakeUppercaseIntentResponse.success(result: add(text: uppercaseText))) } else { completion(MakeUppercaseIntentResponse.failure(error: "The text entred is invalid")) } } func resolveText(for intent: MakeUppercaseIntent, with completion: @escaping (MakeUppercaseTextResolutionResult) -> Void) { if let text = intent.text, !text.isEmpty { completion(MakeUppercaseTextResolutionResult.success(with: text)) } else { completion(MakeUppercaseTextResolutionResult.unsupported(forReason: .noText)) } } func add(text: String) -> String{ let newItem = Item(context: persistenceController.container.viewContext) newItem.text = text do { try persistenceController.container.viewContext.save() } catch { let nsError = error as NSError fatalError("Unresolved error \(nsError), \(nsError.userInfo)") } return text } } Thank You
3
0
1.1k
Dec ’21
Siri Shortcuts with SwiftUI and Core Data
Hello, I have created a simple SwiftUI app with Core Data and want to be able to add data via the shortcuts app, I have implemented Intents and the IntentHandler class. When I create a shortcut to add data to my app and run it, nothing happens in the app, the list does not refresh, the only way to see the added data is to close the app completely and reopen it. How can I refresh the UI immediately? I will post my Core Data stack and my SwiftUI view. struct PersistenceController { static let shared = PersistenceController() let container: NSPersistentContainer init() { container = NSPersistentContainer(name: "SiriShort") guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.SiriShortcut2")?.appendingPathComponent("SiriShort.sqlite") else { fatalError("Shared file container could not be created.") } let storeDescription = NSPersistentStoreDescription(url: fileContainer) storeDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) storeDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) container.persistentStoreDescriptions = [storeDescription] container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) container.viewContext.automaticallyMergesChangesFromParent = true container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy } } View: import SwiftUI import CoreData import Intents struct ContentView: View { @Environment(\.managedObjectContext) private var viewContext @State private var view: Bool = false @FetchRequest( sortDescriptors: [NSSortDescriptor(keyPath: \Item.text, ascending: true)], animation: .default) private var items: FetchedResults<Item> var body: some View { NavigationView { List { ForEach(items) { item in Text(item.text!) } .onDelete(perform: deleteItems) } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } } private func addItem() { withAnimation { let newItem = Item(context: viewContext) newItem.text = "\(Int.random(in: 0...1000))" do { try viewContext.save() } catch { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. let nsError = error as NSError fatalError("Unresolved error \(nsError), \(nsError.userInfo)") } makeDonation(text: newItem.text!) } } func makeDonation(text: String) { let intent = MakeUppercaseIntent() intent.text = text intent.unit = "1" intent.suggestedInvocationPhrase = "Add \(text) to app" let interaction = INInteraction(intent: intent, response: nil) interaction.donate { (error) in if error != nil { if let error = error as NSError? { print("Donation failed: %@" + error.localizedDescription) } } else { print("Successfully donated interaction") } } } private func deleteItems(offsets: IndexSet) { withAnimation { offsets.map { items[$0] }.forEach(viewContext.delete) do { try viewContext.save() } catch { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. let nsError = error as NSError fatalError("Unresolved error \(nsError), \(nsError.userInfo)") } } } }
4
0
2.2k
Dec ’21