Post

Replies

Boosts

Views

Activity

SwiftUI Chart SectorMark Flips Pie Selection On User Input???
Confused as to why the Chart flips with each user input. The console is also output unique id for each slice which was not my intention. Not sure if the unique .id is the culprit behind the flip. selectedCount changed to: Optional(3) Selected slice: Optional(App.EmojiUsage(id: 69090646-0D0A-4FE8-86EC-4103608DC3F7, emojiTab: App.emojiTab.sad, count: 1)) Scheduling reset task to run in 2 seconds Resetting selected slice and count selectedCount changed to: Optional(1) Selected slice: Optional(App.EmojiUsage(id: DE4A76D1-CC57-4FA0-A261-9AD1A6E28F95, emojiTab: App.emojiTab.happy, count: 2)) Scheduling reset task to run in 2 seconds Resetting selected slice and count selectedCount changed to: Optional(3) Selected slice: Optional(App.EmojiUsage(id: 5052F8EA-2582-4E72-A61D-01FCCDF3DB03, emojiTab: App.emojiTab.sad, count: 1)) Scheduling reset task to run in 2 seconds Resetting selected slice and count selectedCount changed to: Optional(0) Selected slice: Optional(App.EmojiUsage(id: 5C1AB577-6CFC-4BA8-A9DF-30822EF79B91, emojiTab: App.emojiTab.happy, count: 2)) Scheduling reset task to run in 2 seconds @Model class AppModel { var id: String var journalEntry: String var date: Date var emojiTab: emojiTab init(journalEntry: String, date: Date, emojiTab: emojiTab) { self.id = UUID().uuidString self.journalEntry = journalEntry self.date = date self.emojiTab = emojiTab } } struct EmojiPrompt: Identifiable { var id = UUID() var icon: RiveViewModel var emojitab: emojiTab var title: String } enum emojiTab: String, Codable, Plottable { case happy case sad case sleep var primitivePlottable: Double { switch self { case .sleep: return 0.0 case .happy: return 1.0 case .sad: return 2.0 } } } var emojiPrompt = [ EmojiPrompt( icon: RiveViewModel( fileName: "app", stateMachineName: "happyBtnSM", artboardName: "happyBtn" ), emojitab: .happy, title: "Happy 1" ), EmojiPrompt( icon: RiveViewModel( fileName: "app", stateMachineName: "sadBtnSM", artboardName: "sadBtn" ), emojitab: .sad, title: "Sad 2" ), EmojiPrompt( icon: RiveViewModel( fileName: "app", stateMachineName: "happyBtnSM", artboardName: "happyBtn" ), emojitab: .sleep, title: "Sleep" ) ] import SwiftUI import SwiftData import RiveRuntime import Charts struct SectorChartView: View { @Environment(\.modelContext) private var context: ModelContext @Binding var selectedEmojiUsage: EmojiUsage? @State private var selectedCount: Int? @Binding var selectedSlice: EmojiUsage? @State private var resetTask: DispatchWorkItem? // State variable for the reset task var emojiUsageData: [EmojiUsage] var resetDelay: TimeInterval = 2.0 // Adjustable delay for reset var body: some View { ZStack { Chart { ForEach(emojiUsageData) { data in SectorMark( angle: .value("Count", data.count), innerRadius: .ratio(0.70), outerRadius: selectedSlice?.emojiTab == data.emojiTab ? .ratio(1.0) : .ratio(0.75), angularInset: 1.5 ) .cornerRadius(4) .foregroundStyle(by: .value("Emoji", data.emojiTab.rawValue.capitalized)) } } .chartAngleSelection(value: $selectedCount) .chartBackground { chartProxy in GeometryReader { geo in let frame = geo[chartProxy.plotFrame!] VStack { if let selectedEmojiUsage = selectedEmojiUsage { RiveViewModel(fileName: "app", stateMachineName: "\(selectedEmojiUsage.emojiTab.rawValue)BtnSM", artboardName: "\(selectedEmojiUsage.emojiTab.rawValue)Btn") .view() .frame(width: 120, height: 120) .id(selectedEmojiUsage.emojiTab.rawValue) // Force re-render when the emojiTab changes } else { RiveViewModel(fileName: "app", stateMachineName: "sleepBtnSM", artboardName: "sleepBtn") .view() .frame(width: 120, height: 120) .id("sleep") // Force re-render when default state } } .position(x: frame.midX, y: frame.midY) } } } .onChange(of: selectedCount) { oldValue, newValue in // Ensure reset task is only scheduled if there is a valid new value guard newValue != nil else { return } resetTask?.cancel() // Cancel any existing reset task print("selectedCount changed to: \(String(describing: newValue))") if let newValue = newValue { withAnimation { getSelectedSlice(value: newValue) } let task = DispatchWorkItem { withAnimation(.easeIn) { print("Resetting selected slice and count") self.selectedSlice = nil self.selectedCount = nil self.selectedEmojiUsage = nil } } resetTask = task print("Scheduling reset task to run in 2 seconds") DispatchQueue.main.asyncAfter(deadline: .now() + resetDelay, execute: task) // Schedule reset after specified delay } } .frame(width: 250, height: 250) } private func getSelectedSlice(value: Int) { var cumulativeTotal = 0 _ = emojiUsageData.first { emojiRange in cumulativeTotal += emojiRange.count if value <= cumulativeTotal { selectedSlice = emojiRange selectedEmojiUsage = emojiRange print("Selected slice: \(String(describing: selectedSlice))") return true } return false } } } var emojiUsageData: [EmojiUsage] { let groupedEntries = Dictionary(grouping: entries, by: { $0.emojiTab }) return groupedEntries.map { (key, value) in EmojiUsage(emojiTab: key, count: value.count) } } struct EmojiUsage: Identifiable { var id = UUID() var emojiTab: emojiTab var count: Int }
3
0
565
Jul ’24
Unable to trigger a .toggle() to a ForEach loop of items in an array.
import SwiftUI import RiveRuntime struct MenuCardView: View { @State private var CardOne = false @State private var CardTwo: Bool = false @AppStorage("selectedCard") var selectedCard: SelectedCard = .CardOne var body: some View { ZStack { ScrollView (.horizontal, showsIndicators: true ) { VStack(spacing:0) { TabView { CardView } .tabViewStyle(.page) .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height) } } if CardOne { Moon_Event() .frame(width: 400, height: 780) .opacity(CardOne ? 1 : 0) .offset(y: CardOne ? 20 : 0) .overlay ( Button { withAnimation(.spring()) { CardOne.toggle() } } label: { Image(systemName: "xmark") .frame(width: 40, height: 40) .foregroundStyle(.black) .background(.white) .mask(Circle()) .shadow(color: Color("Shadow").opacity(0.3) ,radius: 5, x: 0, y:3) } .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) .offset(y: CardOne ? 15 : 200) ) .transition(.opacity.combined(with: .move(edge: .top))) .zIndex(1) } if CardTwo { Sun_Event() .frame(width: 400, height: 780) .opacity(CardTwo ? 1 : 0) .offset(y: CardTwo ? 20 : 0) .overlay ( Button { withAnimation(.spring()) { CardTwo.toggle() } } label: { Image(systemName: "xmark") .frame(width: 40, height: 40) .foregroundStyle(.black) .background(.white) .mask(Circle()) .shadow(color: Color("Shadow").opacity(0.3) ,radius: 5, x: 0, y:3) } .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) .offset(y: CardTwo ? 15 : 200) ) .transition(.opacity.combined(with: .move(edge: .top))) .zIndex(1) } } } } var CardView: some View { ForEach(menuItems) { items in GeometryReader { proxy in items.rvm.view() .padding(.vertical, 220) .rotation3DEffect(.degrees(proxy.frame(in: .global).minX / -10), axis: (x: 0, y: 1, z: 0)) .shadow(color: Color("Shadow").opacity(0.8), radius: 10, x: 0, y: 10) .onTapGesture { location in withAnimation(.spring()) { print("Location: \(location)") // items.message.toggle() nor selectedCard.toggle() seem to work. I'm just trying to create a simple .toggle() for which items is on the screen.// } } Text("\(items.message)") .padding(.top, 290) } } .padding(20) .frame(height: UIScreen.main.bounds.height) } struct MenuItems: Identifiable { var id = UUID() var rvm: RiveViewModel var modal: SelectedCard var message: String } var menuItems = [ MenuItems(rvm: RiveViewModel(fileName: "mooncard"), modal: .CardOne, message: "CardOne"), MenuItems(rvm: RiveViewModel(fileName: "suncard"), modal: .CardTwo, message: "CardTwo"), MenuItems(rvm: RiveViewModel(fileName: "mooncard"), modal: .CardThree, message: "CardThree"), MenuItems(rvm: RiveViewModel(fileName: "suncard"), modal: .CardFour, message: "CardFour") ] enum SelectedCard: String { case CardOne case CardTwo case CardThree case CardFour } #Preview { MenuCardView() }
1
0
220
Dec ’23