From 78818db77870c51b5107804fe46259889ef14b3d Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Wed, 1 May 2024 20:30:36 +0200 Subject: [PATCH] Add deck list and add deck views --- WordAX.xcodeproj/project.pbxproj | 8 +++ WordAX/Model/DataController.swift | 17 ++++++ WordAX/Views/Deck/AddDeckView.swift | 55 ++++++++++++++++++ WordAX/Views/Deck/DeckListView.swift | 58 +++++++++++++++++++ .../Views/Flashcards/AddFlashCardView.swift | 17 ++++++ .../Views/Flashcards/FlashCardListView.swift | 16 +++-- WordAX/Views/MainView.swift | 6 ++ 7 files changed, 171 insertions(+), 6 deletions(-) create mode 100644 WordAX/Views/Deck/AddDeckView.swift create mode 100644 WordAX/Views/Deck/DeckListView.swift diff --git a/WordAX.xcodeproj/project.pbxproj b/WordAX.xcodeproj/project.pbxproj index 30ea4a0..9138880 100644 --- a/WordAX.xcodeproj/project.pbxproj +++ b/WordAX.xcodeproj/project.pbxproj @@ -17,6 +17,8 @@ 6C8185082B8B523E0033CF46 /* NextRepetitionButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */; }; 6C81850A2B8BA5740033CF46 /* FlashCardListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185092B8BA5740033CF46 /* FlashCardListView.swift */; }; 6C81850C2B8BA6BC0033CF46 /* FlashCardListRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C81850B2B8BA6BC0033CF46 /* FlashCardListRowView.swift */; }; + 6CB09C2D2BE28C3E0020FE0C /* AddDeckView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CB09C2C2BE28C3E0020FE0C /* AddDeckView.swift */; }; + 6CD2D7CB2BE270240079C4FA /* DeckListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CD2D7CA2BE270240079C4FA /* DeckListView.swift */; }; 6CEF7F522BC2DBF800E205F6 /* AddFlashCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F512BC2DBF800E205F6 /* AddFlashCardView.swift */; }; 6CEF7F7D2BC457E600E205F6 /* DataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F7C2BC457E600E205F6 /* DataController.swift */; }; 6CEF7F812BC4694900E205F6 /* WordAXCD.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F7F2BC4694900E205F6 /* WordAXCD.xcdatamodeld */; }; @@ -40,6 +42,8 @@ 6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextRepetitionButtonView.swift; sourceTree = ""; }; 6C8185092B8BA5740033CF46 /* FlashCardListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardListView.swift; sourceTree = ""; }; 6C81850B2B8BA6BC0033CF46 /* FlashCardListRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardListRowView.swift; sourceTree = ""; }; + 6CB09C2C2BE28C3E0020FE0C /* AddDeckView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddDeckView.swift; sourceTree = ""; }; + 6CD2D7CA2BE270240079C4FA /* DeckListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeckListView.swift; sourceTree = ""; }; 6CD500B52BE15F6D002BF511 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 6CEF7F512BC2DBF800E205F6 /* AddFlashCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFlashCardView.swift; sourceTree = ""; }; 6CEF7F7C2BC457E600E205F6 /* DataController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataController.swift; sourceTree = ""; }; @@ -105,6 +109,8 @@ 6CD2D7C92BE26FFB0079C4FA /* Deck */ = { isa = PBXGroup; children = ( + 6CB09C2C2BE28C3E0020FE0C /* AddDeckView.swift */, + 6CD2D7CA2BE270240079C4FA /* DeckListView.swift */, ); path = Deck; sourceTree = ""; @@ -260,7 +266,9 @@ 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */, 6CEF7F522BC2DBF800E205F6 /* AddFlashCardView.swift in Sources */, 6C8184FE2B88C9580033CF46 /* WordAX.swift in Sources */, + 6CD2D7CB2BE270240079C4FA /* DeckListView.swift in Sources */, 6C4A87D22BE25D260074E0A9 /* Deck+CoreDataClass.swift in Sources */, + 6CB09C2D2BE28C3E0020FE0C /* AddDeckView.swift in Sources */, 6C4A87D32BE25D260074E0A9 /* Deck+CoreDataProperties.swift in Sources */, 6CEF7F812BC4694900E205F6 /* WordAXCD.xcdatamodeld in Sources */, 6C81850C2B8BA6BC0033CF46 /* FlashCardListRowView.swift in Sources */, diff --git a/WordAX/Model/DataController.swift b/WordAX/Model/DataController.swift index 416dcde..9b991a2 100644 --- a/WordAX/Model/DataController.swift +++ b/WordAX/Model/DataController.swift @@ -19,6 +19,22 @@ class DataController: ObservableObject { static var preview: DataController = { let result = DataController(inMemory: true) let viewContext = result.container.viewContext + var decks: [Deck] = [] + var deck = Deck(context: viewContext) + deck.id = UUID() + deck.name = "This is a deck name" + decks.append(deck) + + deck = Deck(context: viewContext) + deck.id = UUID() + deck.name = "Another Deck" + decks.append(deck) + + deck = Deck(context: viewContext) + deck.id = UUID() + deck.name = "Deck" + decks.append(deck) + for _ in 0..<10 { let flashcard = Flashcard(context: viewContext) flashcard.id = UUID() @@ -33,6 +49,7 @@ class DataController: ObservableObject { flashcard.shownCount = [0, 1, 2, 3, 4, 5].randomElement()! flashcard.dateAdded = [Date(), Date().addingTimeInterval(-86400), Date().addingTimeInterval(-172800)].randomElement()! flashcard.favorite = [true, false].randomElement()! +// flashcard.deck = decks.randomElement() } do { try viewContext.save() diff --git a/WordAX/Views/Deck/AddDeckView.swift b/WordAX/Views/Deck/AddDeckView.swift new file mode 100644 index 0000000..7587a53 --- /dev/null +++ b/WordAX/Views/Deck/AddDeckView.swift @@ -0,0 +1,55 @@ +// +// AddDeckView.swift +// WordAX +// +// Created by Oliver Hnát on 01.05.2024. +// + +import SwiftUI + +struct AddDeckView: View { + @Binding var isShowing: Bool + @Environment(\.managedObjectContext) var moc + @State var name: String = "" + var body: some View { + NavigationStack { + List { + TextField("Name", text: $name) + } + .toolbar { + ToolbarItemGroup(placement: .topBarLeading) { + Button(action: { + self.isShowing = false + }, label: { + Text("Cancel") + .foregroundStyle(.red) + }) + } + ToolbarItemGroup(placement: .topBarTrailing) { + Button(action: { + let deck = Deck(context: moc) + deck.id = UUID() + deck.name = name + do { + try moc.save() + self.isShowing = false + } catch { + print("Something went wrong while saving the deck") + } + }, label: { + Text("Create") + .bold() + }) + .disabled(name.isEmpty) + } + } + .navigationTitle("Add Deck") + } + } +} + +#Preview { + @State var isShowing = true + return AddDeckView(isShowing: $isShowing) + .environment(\.managedObjectContext, DataController.preview.container.viewContext) +} diff --git a/WordAX/Views/Deck/DeckListView.swift b/WordAX/Views/Deck/DeckListView.swift new file mode 100644 index 0000000..2ea0b68 --- /dev/null +++ b/WordAX/Views/Deck/DeckListView.swift @@ -0,0 +1,58 @@ +// +// DeckListView.swift +// WordAX +// +// Created by Oliver Hnát on 01.05.2024. +// + +import SwiftUI + +struct DeckListView: View { + @FetchRequest(sortDescriptors: []) var decks: FetchedResults + @State var addDeck = false + @Environment(\.managedObjectContext) var moc + var body: some View { + NavigationSplitView { + List { + ForEach(decks) { deck in + Text(deck.name ?? "Unknown deck name") + } + .onDelete(perform: { offsets in + for index in offsets { + let deck = decks[index] + moc.delete(deck) + } + + do { + try moc.save() + } catch { + print("Something went wrong while deleting an object") + } + }) + } + .toolbar { + ToolbarItemGroup(placement: .topBarLeading) { + EditButton() + } + ToolbarItemGroup(placement: .topBarTrailing) { + Button(action: { + self.addDeck = true + }) { + Image(systemName: "plus") + } + } + } + .navigationTitle("All decks") + } detail: { + Text("Select deck to get details about") + } + .sheet(isPresented: $addDeck, content: { + AddDeckView(isShowing: $addDeck) + }) + } +} + +#Preview { + DeckListView() + .environment(\.managedObjectContext, DataController.preview.container.viewContext) +} diff --git a/WordAX/Views/Flashcards/AddFlashCardView.swift b/WordAX/Views/Flashcards/AddFlashCardView.swift index 1550fad..6294308 100644 --- a/WordAX/Views/Flashcards/AddFlashCardView.swift +++ b/WordAX/Views/Flashcards/AddFlashCardView.swift @@ -13,6 +13,9 @@ struct AddFlashCardView: View { @Binding var isShowing: Bool @Environment(\.managedObjectContext) var moc @FocusState private var focus: Bool + @FetchRequest(sortDescriptors: []) var decks: FetchedResults + @State var selectedDeck: Deck? + @State var createDisabled: Bool = true var body: some View { NavigationStack { List { @@ -20,11 +23,23 @@ struct AddFlashCardView: View { TextField("Name", text: $text) .focused($focus) TextField("Description", text: $description, axis: .vertical) + Picker("Deck", selection: $selectedDeck) { + ForEach(decks) { deck in + Text(deck.name ?? "Unknown deck name") + .tag(deck as Deck?) + } + } + .pickerStyle(.wheel) } .onAppear { self.focus = true } } + .onAppear { + if selectedDeck == nil && !decks.isEmpty { + selectedDeck = decks[0] + } + } .toolbar { ToolbarItemGroup(placement: .topBarLeading) { Button(action: { @@ -42,6 +57,7 @@ struct AddFlashCardView: View { Text("Create") .bold() }) + .disabled(text.count == 0 || description.count == 0 || selectedDeck == nil) } } .navigationTitle("Add Flashcard") @@ -57,6 +73,7 @@ struct AddFlashCardView: View { flashcard.lastSeenOn = nil flashcard.shownCount = 0 flashcard.dateAdded = Date() + flashcard.deck = selectedDeck try? moc.save() } diff --git a/WordAX/Views/Flashcards/FlashCardListView.swift b/WordAX/Views/Flashcards/FlashCardListView.swift index 84b0766..a73ae2a 100644 --- a/WordAX/Views/Flashcards/FlashCardListView.swift +++ b/WordAX/Views/Flashcards/FlashCardListView.swift @@ -48,15 +48,19 @@ struct FlashCardListView: View { } .navigationTitle("All Flashcards") .toolbar { - EditButton() - Button(action: { - self.addFlashcard = true - }) { - Image(systemName: "plus") + ToolbarItemGroup(placement: .topBarLeading) { + EditButton() + } + ToolbarItemGroup(placement: .topBarTrailing) { + Button(action: { + self.addFlashcard = true + }) { + Image(systemName: "plus") + } } } } detail: { - Text("Select word to get details about") + Text("Select flashcard to get details about") } .sheet(isPresented: $addFlashcard, content: { AddFlashCardView(isShowing: $addFlashcard) diff --git a/WordAX/Views/MainView.swift b/WordAX/Views/MainView.swift index 1a74458..3705836 100644 --- a/WordAX/Views/MainView.swift +++ b/WordAX/Views/MainView.swift @@ -28,6 +28,12 @@ struct MainView: View { Image(systemName: "list.bullet") Text("Flashcards") } + DeckListView() + .tag("Decks") + .tabItem { + Image(systemName: "rectangle.stack") + Text("Decks") + } SettingsView() .tag("Settings") .tabItem {