我试图允许用户创建自定义锻炼,我想将所有内容保存到他们自己的用户文档中的 firebase 中,包括锻炼名称、时间和练习。
我可以轻松保存名称,但我不确定如何将练习作为选定行保存回 Firestore。我在 HStack 中展示了 ForEach 的练习以进行更多定制。和右侧的按钮切换 检查练习的真假。
我想做两件事。 1)限制他们可以选择的练习数量为4,然后将他们选择的练习写到firebase(包括练习标题,练习图片和练习gif)。
我认为按钮需要一些 id 或索引或某种方式让它知道哪些已被选中,所以当我说要写入 Firestore 时,它只写入选定的 id 或索引。
我不确定如何告诉应用将所选行写入 Firebase。
struct WorkoutBuilder: View {
@Environment(\.presentationMode) var presentationMode
@State var workoutName = ""
@ObservedObject var customWorkoutModel = CustomWorkoutModel()
var body: some View {
VStack(alignment: .leading, spacing: 10){
HStack(alignment: .top){
Button(action: goBack) {
Image(systemName: "chevron.left")
.font(.system(size: 23, weight: .bold, design: .rounded))
.foregroundColor(.black)
.padding(.top, 10)
}
Spacer()
}
.padding(.horizontal, 10)
Text("Name")
.font(.title2)
.fontWeight(.semibold)
RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color("sweatGray"))
.overlay(
TextField("", text: self.$workoutName)
.foregroundColor(.black)
.autocapitalization(.none)
.disableAutocorrection(true)
.padding(.horizontal, 10)
)
.frame(maxWidth: .infinity, maxHeight: 50)
.padding(.bottom, 10)
Text("Layout")
.font(.title2)
.fontWeight(.semibold)
HStack{
RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color("sweatGray"))
.overlay(
Text("20s")
)
.frame(maxWidth: .infinity, maxHeight: 50)
RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color("sweatGray"))
.overlay(
Text("40s")
)
.frame(maxWidth: .infinity, maxHeight: 50)
}
Text("x 4 exercises x 4 rounds")
.frame(alignment: .center)
Text("Exercises")
.font(.title2)
.fontWeight(.semibold)
ScrollView(showsIndicators: false) {
ForEach(customWorkoutModel.customs, id: \.self) { custom in
CustomRow(image: custom.image, title: custom.title, gif: custom.gif)
}
}
Button(action: {
addCustomWorkout()
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Save Workout")
.fontWeight(.bold)
.foregroundColor(.white)
.frame(maxWidth: .infinity, maxHeight: 50)
.background(Color("sweatBlue"))
.cornerRadius(10)
}
}
.padding(.horizontal, 10)
.onAppear() {
self.customWorkoutModel.fetchCustomWorkoutData()
}
}
// Back Button Function
func goBack(){
self.presentationMode.wrappedValue.dismiss()
}
// write custom workout to frestore
func addCustomWorkout() {
let db = Firestore.firestore()
db.collection("users").document(Auth.auth().currentUser?.uid ?? "").collection("CustomWorkout").document(self.workoutName).setData([
"date" : Timestamp(date: Date()),
"title" : self.workoutName,
"classes" : 1,
"hours" : 3, //whatever the workout is set as
"points" : 55,
"exerciseOneName": // I want to save the name of a selected exercise
])
}
}
自定义行
var image : String
var title : String
// var gif : String
@State var selected = ""
@State var gif = ""
@State private var selectedExercise: Bool = false
var body: some View {
HStack{
AnimatedImage(url: URL(string: image))
.resizable()
.scaledToFill()
.frame(width: 80)
Text(title)
.font(.title3)
Spacer()
Button(action: {
self.selectedExercise.toggle()
self.selected = image // I thought I might be able to save it this way using a string but, no!
self.selected = title
self.selected = gif
}) {
Image(systemName: self.selectedExercise == true ? "checkmark.circle.fill" : "checkmark.circle" )
}
// .foregroundColor(selectedExercise ? Color("sweatBlack") : Color.blue)
.padding(.trailing, 10)
}
.frame(height: 80)
.clipped()
.background(Color("sweatGray"))
.cornerRadius(10)
}
}
struct Custom : Identifiable, Hashable {
var id : String = UUID().uuidString
var title : String
var image : String
var gif : String
}
答案 0 :(得分:0)
您可能应该将您选择的项目存储在 CustomRow
上方一级,并将选择向下传递到该行。
我将选定的项目 ID 存储在视图模型中,然后将闭包传递给更改选择的 CustomRow
。
选择更改后,您可以将 Set
写入 Firestore。我假设您只想将 id
列表存储到 Firestore,但理论上,您可以存储整个模型。由于您在评论中说您已经可以保存到 Firestore
,因此我省略了该代码。
class CustomWorkoutModel : ObservableObject {
@Published var customs: [Custom] = [.init(title: "Test", image: "test", gif: "test")]
@Published var selectedCustomIDs: Set<String> = [] //could add a didSet here to write to firestore, or watch with Combine
func changeSelection(id: String, selected: Bool) {
if selected {
selectedCustomIDs.insert(id)
} else {
selectedCustomIDs.remove(id)
}
}
var selectedCustoms : [Custom] {
selectedCustomIDs.compactMap { id in customs.first { custom in
custom.id == id
}}
}
}
struct Custom : Identifiable, Hashable {
var id : String = UUID().uuidString
var title : String
var image : String
var gif : String
}
struct WorkoutBuilder: View {
@Environment(\.presentationMode) private var presentationMode
@State private var workoutName = ""
@ObservedObject private var customWorkoutModel = CustomWorkoutModel()
var body: some View {
VStack(alignment: .leading, spacing: 10){
ScrollView(showsIndicators: false) {
ForEach(customWorkoutModel.customs, id: \.self) { custom in
CustomRow(image: custom.image,
title: custom.title,
gif: custom.gif,
selected: customWorkoutModel.selectedCustomIDs.contains(custom.id),
changeSelection: { selected in
customWorkoutModel.changeSelection(id: custom.id, selected: selected)
})
}
Button(action: {
addCustomWorkout()
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Save Workout")
.fontWeight(.bold)
.foregroundColor(.white)
.frame(maxWidth: .infinity, maxHeight: 50)
.background(Color("sweatBlue"))
.cornerRadius(10)
}
}
.padding(.horizontal, 10)
.onAppear() {
//self.customWorkoutModel.fetchCustomWorkoutData()
print("Get data")
}
}
}
// Back Button Function
func goBack(){
self.presentationMode.wrappedValue.dismiss()
}
// write custom workout to frestore
func addCustomWorkout() {
let selected = customWorkoutModel.selectedCustoms
}
}
struct CustomRow : View {
var image : String
var title : String
var gif: String
var selected : Bool
var changeSelection: (Bool) -> Void
var body: some View {
HStack{
Text("Image")
Text(title)
.font(.title3)
Spacer()
Button(action: {
self.changeSelection(!selected)
}) {
Image(systemName: selected ? "checkmark.circle.fill" : "checkmark.circle" )
}
// .foregroundColor(selectedExercise ? Color("sweatBlack") : Color.blue)
.padding(.trailing, 10)
}
.frame(height: 80)
.clipped()
.background(Color("sweatGray"))
.cornerRadius(10)
}
}