Compare commits
10 Commits
880315ee53
...
65d3974d6c
| Author | SHA1 | Date | |
|---|---|---|---|
| 65d3974d6c | |||
| f6c4e68698 | |||
| e11d79acb9 | |||
| a136ee333a | |||
| 492518ccdb | |||
| e0b6365eeb | |||
| 8e0fca1c36 | |||
| df267ebc4e | |||
| 5a5646648f | |||
| ecdea1de2f |
@@ -61,7 +61,7 @@ Why settle for pricey apps when you can have WordAX? We're here to prove that ef
|
|||||||
- [x] Create flashcards
|
- [x] Create flashcards
|
||||||
- [ ] Add tags to cards
|
- [ ] Add tags to cards
|
||||||
- [ ] Specify how often you want each card to be seen (per folder/tag?)
|
- [ ] Specify how often you want each card to be seen (per folder/tag?)
|
||||||
- [ ] Add tags/folders
|
- [x] Add tags/folders - added decks to group cards
|
||||||
- [x] Store cards persistently
|
- [x] Store cards persistently
|
||||||
- [x] For start store them on the phone - stored using Core Data
|
- [x] For start store them on the phone - stored using Core Data
|
||||||
- [ ] Maybe later add a storage in cloud, so that you can sync with other devices if the app is multi-platform?
|
- [ ] Maybe later add a storage in cloud, so that you can sync with other devices if the app is multi-platform?
|
||||||
@@ -70,6 +70,7 @@ Why settle for pricey apps when you can have WordAX? We're here to prove that ef
|
|||||||
- [ ] Make an apple watch version of the app
|
- [ ] Make an apple watch version of the app
|
||||||
- [ ] Option to add a hint
|
- [ ] Option to add a hint
|
||||||
- [ ] Add haptic touch
|
- [ ] Add haptic touch
|
||||||
|
- [ ] Add emoji to decks? design:)
|
||||||
|
|
||||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
6C4A87D22BE25D260074E0A9 /* Deck+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C4A87D02BE25D260074E0A9 /* Deck+CoreDataClass.swift */; };
|
6C4A87D22BE25D260074E0A9 /* Deck+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C4A87D02BE25D260074E0A9 /* Deck+CoreDataClass.swift */; };
|
||||||
6C4A87D32BE25D260074E0A9 /* Deck+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C4A87D12BE25D260074E0A9 /* Deck+CoreDataProperties.swift */; };
|
6C4A87D32BE25D260074E0A9 /* Deck+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C4A87D12BE25D260074E0A9 /* Deck+CoreDataProperties.swift */; };
|
||||||
|
6C7B6D5D2BE69FA900FB6ECC /* DeckSelectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C7B6D5C2BE69FA900FB6ECC /* DeckSelectView.swift */; };
|
||||||
|
6C7B6D5F2BE6A1C100FB6ECC /* DeckRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C7B6D5E2BE6A1C100FB6ECC /* DeckRowView.swift */; };
|
||||||
6C8184FE2B88C9580033CF46 /* WordAX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8184FD2B88C9580033CF46 /* WordAX.swift */; };
|
6C8184FE2B88C9580033CF46 /* WordAX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8184FD2B88C9580033CF46 /* WordAX.swift */; };
|
||||||
6C8185002B88C9660033CF46 /* Miscellaneous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8184FF2B88C9660033CF46 /* Miscellaneous.swift */; };
|
6C8185002B88C9660033CF46 /* Miscellaneous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8184FF2B88C9660033CF46 /* Miscellaneous.swift */; };
|
||||||
6C8185022B88C9FB0033CF46 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185012B88C9FB0033CF46 /* SettingsView.swift */; };
|
6C8185022B88C9FB0033CF46 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185012B88C9FB0033CF46 /* SettingsView.swift */; };
|
||||||
@@ -34,6 +36,8 @@
|
|||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
6C4A87D02BE25D260074E0A9 /* Deck+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Deck+CoreDataClass.swift"; sourceTree = "<group>"; };
|
6C4A87D02BE25D260074E0A9 /* Deck+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Deck+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||||
6C4A87D12BE25D260074E0A9 /* Deck+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Deck+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
6C4A87D12BE25D260074E0A9 /* Deck+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Deck+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
||||||
|
6C7B6D5C2BE69FA900FB6ECC /* DeckSelectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DeckSelectView.swift; path = WordAX/Views/Deck/DeckSelectView.swift; sourceTree = SOURCE_ROOT; };
|
||||||
|
6C7B6D5E2BE6A1C100FB6ECC /* DeckRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeckRowView.swift; sourceTree = "<group>"; };
|
||||||
6C8184FD2B88C9580033CF46 /* WordAX.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAX.swift; sourceTree = "<group>"; };
|
6C8184FD2B88C9580033CF46 /* WordAX.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAX.swift; sourceTree = "<group>"; };
|
||||||
6C8184FF2B88C9660033CF46 /* Miscellaneous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Miscellaneous.swift; sourceTree = "<group>"; };
|
6C8184FF2B88C9660033CF46 /* Miscellaneous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Miscellaneous.swift; sourceTree = "<group>"; };
|
||||||
6C8185012B88C9FB0033CF46 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
6C8185012B88C9FB0033CF46 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||||
@@ -109,7 +113,9 @@
|
|||||||
6CD2D7C92BE26FFB0079C4FA /* Deck */ = {
|
6CD2D7C92BE26FFB0079C4FA /* Deck */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
6C7B6D5E2BE6A1C100FB6ECC /* DeckRowView.swift */,
|
||||||
6CB09C2C2BE28C3E0020FE0C /* AddDeckView.swift */,
|
6CB09C2C2BE28C3E0020FE0C /* AddDeckView.swift */,
|
||||||
|
6C7B6D5C2BE69FA900FB6ECC /* DeckSelectView.swift */,
|
||||||
6CD2D7CA2BE270240079C4FA /* DeckListView.swift */,
|
6CD2D7CA2BE270240079C4FA /* DeckListView.swift */,
|
||||||
);
|
);
|
||||||
path = Deck;
|
path = Deck;
|
||||||
@@ -257,6 +263,7 @@
|
|||||||
6CF439542B83541D004C3543 /* MainView.swift in Sources */,
|
6CF439542B83541D004C3543 /* MainView.swift in Sources */,
|
||||||
6C8185082B8B523E0033CF46 /* NextRepetitionButtonView.swift in Sources */,
|
6C8185082B8B523E0033CF46 /* NextRepetitionButtonView.swift in Sources */,
|
||||||
6C8185062B8A537F0033CF46 /* FlashCardView.swift in Sources */,
|
6C8185062B8A537F0033CF46 /* FlashCardView.swift in Sources */,
|
||||||
|
6C7B6D5F2BE6A1C100FB6ECC /* DeckRowView.swift in Sources */,
|
||||||
6CEF7FA32BC88F6000E205F6 /* Flashcard+CoreDataProperties.swift in Sources */,
|
6CEF7FA32BC88F6000E205F6 /* Flashcard+CoreDataProperties.swift in Sources */,
|
||||||
6C81850A2B8BA5740033CF46 /* FlashCardListView.swift in Sources */,
|
6C81850A2B8BA5740033CF46 /* FlashCardListView.swift in Sources */,
|
||||||
6CEF7FA62BC96F2B00E205F6 /* ButtonHStackView.swift in Sources */,
|
6CEF7FA62BC96F2B00E205F6 /* ButtonHStackView.swift in Sources */,
|
||||||
@@ -271,6 +278,7 @@
|
|||||||
6CB09C2D2BE28C3E0020FE0C /* AddDeckView.swift in Sources */,
|
6CB09C2D2BE28C3E0020FE0C /* AddDeckView.swift in Sources */,
|
||||||
6C4A87D32BE25D260074E0A9 /* Deck+CoreDataProperties.swift in Sources */,
|
6C4A87D32BE25D260074E0A9 /* Deck+CoreDataProperties.swift in Sources */,
|
||||||
6CEF7F812BC4694900E205F6 /* WordAXCD.xcdatamodeld in Sources */,
|
6CEF7F812BC4694900E205F6 /* WordAXCD.xcdatamodeld in Sources */,
|
||||||
|
6C7B6D5D2BE69FA900FB6ECC /* DeckSelectView.swift in Sources */,
|
||||||
6C81850C2B8BA6BC0033CF46 /* FlashCardListRowView.swift in Sources */,
|
6C81850C2B8BA6BC0033CF46 /* FlashCardListRowView.swift in Sources */,
|
||||||
6CEF7F842BC46B5900E205F6 /* Flashcard+CoreDataClass.swift in Sources */,
|
6CEF7F842BC46B5900E205F6 /* Flashcard+CoreDataClass.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class DataController: ObservableObject {
|
|||||||
flashcard.dateAdded = [Date(), Date().addingTimeInterval(-86400), Date().addingTimeInterval(-172800)].randomElement()!
|
flashcard.dateAdded = [Date(), Date().addingTimeInterval(-86400), Date().addingTimeInterval(-172800)].randomElement()!
|
||||||
flashcard.favorite = [true, false].randomElement()!
|
flashcard.favorite = [true, false].randomElement()!
|
||||||
flashcard.deck = decks.randomElement()
|
flashcard.deck = decks.randomElement()
|
||||||
|
flashcard.hint = ["This is a small hint", "Hint", "This is a very long hint that maybe should be even longer olorem ipsum to cover everything but I don't know what else to write Lorem Ipsum", "This is something in between hint that doesn'coveres the mid cases Lorem Ipsujm Lor"].randomElement()
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
try viewContext.save()
|
try viewContext.save()
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public class Flashcard: NSManagedObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getSpacedRepetitionMilestone() -> SpacedRepetitionMilestoneEnum {
|
func getSpacedRepetitionMilestone() -> SpacedRepetitionMilestoneEnum {
|
||||||
SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone)
|
let milestone = SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone)
|
||||||
|
return milestone == .Now || milestone == .OneMinute ? .TenMinutes : milestone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ extension Flashcard {
|
|||||||
@NSManaged public var shown: Bool
|
@NSManaged public var shown: Bool
|
||||||
@NSManaged public var shownCount: Int64
|
@NSManaged public var shownCount: Int64
|
||||||
@NSManaged public var deck: Deck?
|
@NSManaged public var deck: Deck?
|
||||||
|
@NSManaged public var hint: String?
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22757" systemVersion="23D60" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithSwiftData="YES" userDefinedModelVersionIdentifier="">
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22757" systemVersion="23E224" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithSwiftData="YES" userDefinedModelVersionIdentifier="">
|
||||||
<entity name="Deck" representedClassName="Deck" syncable="YES" coreSpotlightDisplayNameExpression="Deck">
|
<entity name="Deck" representedClassName="Deck" syncable="YES" coreSpotlightDisplayNameExpression="Deck">
|
||||||
<attribute name="dateAdded" attributeType="Date" defaultDateTimeInterval="736207200" usesScalarValueType="NO"/>
|
<attribute name="dateAdded" attributeType="Date" defaultDateTimeInterval="736207200" usesScalarValueType="NO"/>
|
||||||
<attribute name="id" attributeType="UUID" usesScalarValueType="NO"/>
|
<attribute name="id" attributeType="UUID" usesScalarValueType="NO"/>
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
<attribute name="dateAdded" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
<attribute name="dateAdded" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
<attribute name="desc" optional="YES" attributeType="String" spotlightIndexingEnabled="YES"/>
|
<attribute name="desc" optional="YES" attributeType="String" spotlightIndexingEnabled="YES"/>
|
||||||
<attribute name="favorite" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
<attribute name="favorite" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="hint" optional="YES" attributeType="String"/>
|
||||||
<attribute name="id" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
|
<attribute name="id" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
|
||||||
<attribute name="lastSeenOn" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
<attribute name="lastSeenOn" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
<attribute name="name" optional="YES" attributeType="String" spotlightIndexingEnabled="YES"/>
|
<attribute name="name" optional="YES" attributeType="String" spotlightIndexingEnabled="YES"/>
|
||||||
|
|||||||
@@ -16,74 +16,97 @@ struct AnkiView: View {
|
|||||||
@State var flashcards: [Flashcard] = []
|
@State var flashcards: [Flashcard] = []
|
||||||
@State var soonestFlashcards: [Flashcard] = []
|
@State var soonestFlashcards: [Flashcard] = []
|
||||||
@State var showDescription = false
|
@State var showDescription = false
|
||||||
|
@State var decksToDisplay = Set<Deck>()
|
||||||
|
@State var deckViewVisible: Bool = false
|
||||||
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
GeometryReader { geometry in
|
||||||
if !flashcards.isEmpty && flashcards.first != nil {
|
VStack {
|
||||||
GeometryReader { geometry in
|
HStack {
|
||||||
|
Button {
|
||||||
|
self.deckViewVisible = true
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "rectangle.stack.fill")
|
||||||
|
.padding([.leading, .top])
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
if !flashcards.isEmpty && flashcards.first != nil {
|
||||||
VStack {
|
VStack {
|
||||||
if flashcards.first != nil {
|
if flashcards.first != nil {
|
||||||
FlashCardView(flashcard: flashcards.first!, showDescription: $showDescription)
|
FlashCardView(flashcard: flashcards.first!, showDescription: $showDescription)
|
||||||
}
|
}
|
||||||
if showDescription && flashcards.first != nil {
|
if showDescription && flashcards.first != nil {
|
||||||
// Text("How did you do?")
|
|
||||||
// .font(.subheadline)
|
|
||||||
// .foregroundStyle(.gray)
|
|
||||||
ButtonHStackView(flashcard: flashcards.first!, geometry: geometry, reload: refreshFlashcards, showDescription: $showDescription)
|
ButtonHStackView(flashcard: flashcards.first!, geometry: geometry, reload: refreshFlashcards, showDescription: $showDescription)
|
||||||
.padding([.bottom, .trailing, .leading])
|
.padding([.bottom, .trailing, .leading])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
if !soonestFlashcards.isEmpty {
|
||||||
if !soonestFlashcards.isEmpty {
|
Group {
|
||||||
Group {
|
Text("Next flashcard in: \(timeRemaining.convertDurationSecondsToCountdown())")
|
||||||
Text("Next flashcard in: \(timeRemaining.convertDurationSecondsToCountdown())")
|
.foregroundStyle(.black)
|
||||||
|
.padding()
|
||||||
|
.frame(maxWidth: .infinity - 50)
|
||||||
|
.background(.yellow)
|
||||||
|
.clipShape(.buttonBorder)
|
||||||
|
.padding(.vertical, 50)
|
||||||
|
.padding(.horizontal)
|
||||||
|
.onReceive(timer) { time in
|
||||||
|
if timeRemaining > 1 {
|
||||||
|
timeRemaining -= 1
|
||||||
|
}
|
||||||
|
if timeRemaining <= 3 {
|
||||||
|
refreshFlashcards()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.background(.gray.opacity(0.3))
|
||||||
|
.clipShape(.buttonBorder)
|
||||||
|
.padding(.horizontal)
|
||||||
|
}
|
||||||
|
.frame(maxHeight: .infinity)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Text("No flashcards available")
|
||||||
.foregroundStyle(.black)
|
.foregroundStyle(.black)
|
||||||
.padding()
|
.padding()
|
||||||
.frame(maxWidth: .infinity - 50)
|
// .frame(maxWidth: .infinity - 50)
|
||||||
.background(.yellow)
|
.background(.yellow)
|
||||||
.clipShape(.buttonBorder)
|
.clipShape(.buttonBorder)
|
||||||
.padding(.vertical, 50)
|
.padding(.vertical, 50)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.onReceive(timer) { time in
|
|
||||||
if timeRemaining > 1 {
|
|
||||||
timeRemaining -= 1
|
|
||||||
}
|
|
||||||
if timeRemaining <= 3 {
|
|
||||||
refreshFlashcards()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.background(.gray.opacity(0.3))
|
|
||||||
.clipShape(.buttonBorder)
|
|
||||||
.padding(.horizontal)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
Text("No flashcards available")
|
|
||||||
.foregroundStyle(.black)
|
|
||||||
.padding()
|
|
||||||
// .frame(maxWidth: .infinity - 50)
|
|
||||||
.background(.yellow)
|
|
||||||
.clipShape(.buttonBorder)
|
|
||||||
.padding(.vertical, 50)
|
|
||||||
.padding(.horizontal)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
refreshFlashcards()
|
refreshFlashcards()
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: self.$deckViewVisible) {
|
||||||
|
DeckSelectView(selection: $decksToDisplay, active: $deckViewVisible)
|
||||||
|
}
|
||||||
|
.onChange(of: deckViewVisible) {
|
||||||
|
refreshFlashcards()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func refreshFlashcards() {
|
func refreshFlashcards() {
|
||||||
let requestAllFlashcards = NSFetchRequest<Flashcard>(entityName: "Flashcard")
|
let requestAllFlashcards = NSFetchRequest<Flashcard>(entityName: "Flashcard")
|
||||||
requestAllFlashcards.predicate = NSCompoundPredicate(type: .or, subpredicates: [
|
var predicateAllFlashcards = NSCompoundPredicate(type: .or, subpredicates: [
|
||||||
NSCompoundPredicate(type: .and, subpredicates: [
|
NSCompoundPredicate(type: .and, subpredicates: [
|
||||||
NSPredicate(format: "%K != nil", "lastSeenOn"),
|
NSPredicate(format: "%K != nil", "lastSeenOn"),
|
||||||
NSPredicate(format: "lastSeenOn + nextSpacedRepetitionMilestone < %@", Date() as CVarArg)
|
NSPredicate(format: "lastSeenOn + nextSpacedRepetitionMilestone < %@", Date() as CVarArg)
|
||||||
]),
|
]),
|
||||||
NSPredicate(format: "lastSeenOn == nil")
|
NSPredicate(format: "lastSeenOn == nil")
|
||||||
])
|
])
|
||||||
|
if !self.decksToDisplay.isEmpty {
|
||||||
|
predicateAllFlashcards = NSCompoundPredicate(type: .and, subpredicates: [
|
||||||
|
predicateAllFlashcards,
|
||||||
|
NSPredicate(format: "deck IN %@", decksToDisplay)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
requestAllFlashcards.predicate = predicateAllFlashcards
|
||||||
requestAllFlashcards.sortDescriptors = [
|
requestAllFlashcards.sortDescriptors = [
|
||||||
NSSortDescriptor(key: "nextSpacedRepetitionMilestone", ascending: false),
|
NSSortDescriptor(key: "nextSpacedRepetitionMilestone", ascending: false),
|
||||||
NSSortDescriptor(key: "lastSeenOn", ascending: true)
|
NSSortDescriptor(key: "lastSeenOn", ascending: true)
|
||||||
@@ -97,13 +120,16 @@ struct AnkiView: View {
|
|||||||
|
|
||||||
|
|
||||||
let requestSoonestFlashcards = NSFetchRequest<Flashcard>(entityName: "Flashcard")
|
let requestSoonestFlashcards = NSFetchRequest<Flashcard>(entityName: "Flashcard")
|
||||||
requestSoonestFlashcards.predicate = NSPredicate(format: "%K != nil", "lastSeenOn")
|
var predicateSoonestFlashcards = NSPredicate(format: "%K != nil", "lastSeenOn")
|
||||||
|
if !self.decksToDisplay.isEmpty {
|
||||||
|
predicateSoonestFlashcards = NSCompoundPredicate(type: .and, subpredicates: [
|
||||||
|
predicateSoonestFlashcards,
|
||||||
|
NSPredicate(format: "deck IN %@", decksToDisplay)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
requestSoonestFlashcards.predicate = predicateSoonestFlashcards
|
||||||
do {
|
do {
|
||||||
soonestFlashcards = try moc.fetch(requestSoonestFlashcards)
|
soonestFlashcards = try moc.fetch(requestSoonestFlashcards)
|
||||||
// print("This is soonest flashcards")
|
|
||||||
// for flashcard in soonestFlashcards {
|
|
||||||
// print("\(flashcard.name ?? "") is \(Int(flashcard.lastSeenOn!.addSpacedRepetitionMilestone(milestone:flashcard.getSpacedRepetitionMilestone()).timeIntervalSinceNow.rounded()))")
|
|
||||||
// }
|
|
||||||
} catch {
|
} catch {
|
||||||
print("Something went wrong while fetching latest flashcard")
|
print("Something went wrong while fetching latest flashcard")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,16 @@ struct AddDeckView: View {
|
|||||||
@Binding var isShowing: Bool
|
@Binding var isShowing: Bool
|
||||||
@Environment(\.managedObjectContext) var moc
|
@Environment(\.managedObjectContext) var moc
|
||||||
@State var name: String = ""
|
@State var name: String = ""
|
||||||
|
@State var deck: Deck?
|
||||||
|
var edit: Bool
|
||||||
|
|
||||||
|
init(isShowing: Binding<Bool>, deck: Deck? = nil) {
|
||||||
|
self._isShowing = isShowing
|
||||||
|
self._name = State(initialValue: deck?.name ?? "")
|
||||||
|
self.deck = deck
|
||||||
|
self.edit = deck != nil
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
List {
|
List {
|
||||||
@@ -27,30 +37,36 @@ struct AddDeckView: View {
|
|||||||
}
|
}
|
||||||
ToolbarItemGroup(placement: .topBarTrailing) {
|
ToolbarItemGroup(placement: .topBarTrailing) {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
let deck = Deck(context: moc)
|
if let existingDeck = deck {
|
||||||
deck.id = UUID()
|
existingDeck.name = name
|
||||||
deck.name = name
|
} else {
|
||||||
deck.dateAdded = Date()
|
let currentDeck = Deck(context: moc)
|
||||||
|
currentDeck.id = UUID()
|
||||||
|
currentDeck.dateAdded = Date()
|
||||||
|
currentDeck.name = name
|
||||||
|
}
|
||||||
do {
|
do {
|
||||||
try moc.save()
|
try moc.save()
|
||||||
self.isShowing = false
|
self.isShowing = false
|
||||||
} catch {
|
} catch {
|
||||||
print("Something went wrong while saving the deck")
|
print("Something went wrong while saving the deck")
|
||||||
}
|
}
|
||||||
}, label: {
|
}, label: {
|
||||||
Text("Create")
|
Text(edit ? "Edit": "Create")
|
||||||
.bold()
|
.bold()
|
||||||
})
|
})
|
||||||
.disabled(name.isEmpty)
|
.disabled(name.isEmpty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle("Add Deck")
|
.navigationTitle(edit ? "Edit Deck" : "Add Deck")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
@State var isShowing = true
|
@State var isShowing = true
|
||||||
return AddDeckView(isShowing: $isShowing)
|
let deck = Deck(context: DataController.preview.container.viewContext)
|
||||||
|
deck.id = UUID()
|
||||||
|
return AddDeckView(isShowing: $isShowing, deck: deck)
|
||||||
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,15 +11,37 @@ struct DeckListView: View {
|
|||||||
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "dateAdded", ascending: false)]) var decks: FetchedResults<Deck>
|
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "dateAdded", ascending: false)]) var decks: FetchedResults<Deck>
|
||||||
@State var addDeck = false
|
@State var addDeck = false
|
||||||
@Environment(\.managedObjectContext) var moc
|
@Environment(\.managedObjectContext) var moc
|
||||||
@State var addFlashcard = false
|
@State var editDeck: Bool = false
|
||||||
|
@State var deckToEdit: Deck?
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
List {
|
List {
|
||||||
|
Button(action: {
|
||||||
|
self.addDeck = true
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "plus.circle.fill")
|
||||||
|
Text("Add new deck")
|
||||||
|
}
|
||||||
|
}
|
||||||
ForEach(decks) { deck in
|
ForEach(decks) { deck in
|
||||||
NavigationLink {
|
HStack {
|
||||||
FlashCardListView(deck: deck)
|
Button {
|
||||||
} label: {
|
deckToEdit = deck
|
||||||
Text(deck.name ?? "Unknown deck name")
|
editDeck = true
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "pencil")
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.foregroundStyle(.blue)
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
|
||||||
|
NavigationLink {
|
||||||
|
FlashCardListView(deck: deck)
|
||||||
|
} label: {
|
||||||
|
Text(deck.name ?? "Unknown deck name")
|
||||||
|
}
|
||||||
|
.contentShape(Rectangle())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onDelete(perform: { offsets in
|
.onDelete(perform: { offsets in
|
||||||
@@ -37,19 +59,19 @@ struct DeckListView: View {
|
|||||||
}
|
}
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItemGroup(placement: .topBarTrailing) {
|
ToolbarItemGroup(placement: .topBarTrailing) {
|
||||||
Button(action: {
|
EditButton()
|
||||||
self.addDeck = true
|
|
||||||
}) {
|
|
||||||
Image(systemName: "plus")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle("All decks")
|
.navigationTitle("All decks")
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: Binding(get: {editDeck}, set: {editDeck = $0})) {
|
||||||
|
AddDeckView(isShowing: $editDeck, deck: deckToEdit)
|
||||||
|
}
|
||||||
.sheet(isPresented: $addDeck, content: {
|
.sheet(isPresented: $addDeck, content: {
|
||||||
AddDeckView(isShowing: $addDeck)
|
AddDeckView(isShowing: $addDeck)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
|
|||||||
27
WordAX/Views/Deck/DeckRowView.swift
Normal file
27
WordAX/Views/Deck/DeckRowView.swift
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// DeckRowView.swift
|
||||||
|
// WordAX
|
||||||
|
//
|
||||||
|
// Created by Oliver Hnát on 04.05.2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct DeckRowView: View {
|
||||||
|
var deck: Deck
|
||||||
|
var selected: Bool = false
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
Text(deck.name ?? "Unknown")
|
||||||
|
Spacer()
|
||||||
|
if selected {
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
let deck = try? DataController.preview.viewContext.fetch(Deck.fetchRequest()).first
|
||||||
|
return DeckRowView(deck: deck!)
|
||||||
|
}
|
||||||
40
WordAX/Views/Deck/DeckSelectView.swift
Normal file
40
WordAX/Views/Deck/DeckSelectView.swift
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// DeckSelectView.swift
|
||||||
|
// WordAX
|
||||||
|
//
|
||||||
|
// Created by Oliver Hnát on 04.05.2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct DeckSelectView: View {
|
||||||
|
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "name", ascending: true)]) var decks: FetchedResults<Deck>
|
||||||
|
@Binding var selection: Set<Deck>
|
||||||
|
@Binding var active: Bool
|
||||||
|
var body: some View {
|
||||||
|
NavigationStack {
|
||||||
|
List(decks, id:\.self, selection: $selection) { deck in
|
||||||
|
DeckRowView(deck: deck)
|
||||||
|
}
|
||||||
|
.environment(\.editMode, .constant(EditMode.active))
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItemGroup(placement: .topBarTrailing) {
|
||||||
|
Button(action: {
|
||||||
|
self.active = false
|
||||||
|
}, label: {
|
||||||
|
Text("Done")
|
||||||
|
.bold()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationTitle("Select Decks to display")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
@State var active = true
|
||||||
|
@State var decksToDisplay = Set<Deck>()
|
||||||
|
return DeckSelectView(selection: $decksToDisplay, active: $active)
|
||||||
|
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
||||||
|
}
|
||||||
@@ -16,6 +16,9 @@ struct AddFlashCardView: View {
|
|||||||
@FetchRequest(sortDescriptors: []) var decks: FetchedResults<Deck>
|
@FetchRequest(sortDescriptors: []) var decks: FetchedResults<Deck>
|
||||||
@State var selectedDeck: Deck?
|
@State var selectedDeck: Deck?
|
||||||
@State var createDisabled: Bool = true
|
@State var createDisabled: Bool = true
|
||||||
|
@State var flashcard: Flashcard
|
||||||
|
@State var hint: String = ""
|
||||||
|
var edit: Bool = false
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
List {
|
List {
|
||||||
@@ -23,6 +26,10 @@ struct AddFlashCardView: View {
|
|||||||
TextField("Name", text: $text)
|
TextField("Name", text: $text)
|
||||||
.focused($focus)
|
.focused($focus)
|
||||||
TextField("Description", text: $description, axis: .vertical)
|
TextField("Description", text: $description, axis: .vertical)
|
||||||
|
TextField("Hint", text: $hint, axis: .vertical)
|
||||||
|
.lineLimit(3, reservesSpace: true)
|
||||||
|
}
|
||||||
|
Section(header: Text("Deck details")) {
|
||||||
Picker("Deck", selection: $selectedDeck) {
|
Picker("Deck", selection: $selectedDeck) {
|
||||||
ForEach(decks) { deck in
|
ForEach(decks) { deck in
|
||||||
Text(deck.name ?? "Unknown deck name")
|
Text(deck.name ?? "Unknown deck name")
|
||||||
@@ -54,7 +61,7 @@ struct AddFlashCardView: View {
|
|||||||
self.createFlashcard()
|
self.createFlashcard()
|
||||||
self.isShowing = false
|
self.isShowing = false
|
||||||
}, label: {
|
}, label: {
|
||||||
Text("Create")
|
Text(edit ? "Save" : "Create")
|
||||||
.bold()
|
.bold()
|
||||||
})
|
})
|
||||||
.disabled(text.count == 0 || description.count == 0 || selectedDeck == nil)
|
.disabled(text.count == 0 || description.count == 0 || selectedDeck == nil)
|
||||||
@@ -65,15 +72,16 @@ struct AddFlashCardView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func createFlashcard() {
|
private func createFlashcard() {
|
||||||
let flashcard = Flashcard(context: moc)
|
|
||||||
flashcard.id = UUID()
|
|
||||||
flashcard.name = self.text
|
flashcard.name = self.text
|
||||||
flashcard.desc = self.description
|
flashcard.desc = self.description
|
||||||
flashcard.nextSpacedRepetitionMilestone = 0
|
|
||||||
flashcard.lastSeenOn = nil
|
|
||||||
flashcard.shownCount = 0
|
|
||||||
flashcard.dateAdded = Date()
|
|
||||||
flashcard.deck = selectedDeck
|
flashcard.deck = selectedDeck
|
||||||
|
flashcard.hint = self.hint
|
||||||
|
if !edit {
|
||||||
|
flashcard.nextSpacedRepetitionMilestone = 0
|
||||||
|
flashcard.lastSeenOn = nil
|
||||||
|
flashcard.shownCount = 0
|
||||||
|
flashcard.dateAdded = Date()
|
||||||
|
}
|
||||||
try? moc.save()
|
try? moc.save()
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -81,6 +89,8 @@ struct AddFlashCardView: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
@State var isShowing = true
|
@State var isShowing = true
|
||||||
return AddFlashCardView(isShowing: $isShowing)
|
let flashcard = Flashcard(context: DataController.preview.container.viewContext)
|
||||||
|
flashcard.id = UUID()
|
||||||
|
return AddFlashCardView(isShowing: $isShowing, flashcard: flashcard)
|
||||||
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import SwiftUI
|
|||||||
|
|
||||||
struct FlashCardListRowView: View {
|
struct FlashCardListRowView: View {
|
||||||
@State var flashcard: Flashcard
|
@State var flashcard: Flashcard
|
||||||
@State private var refresh: UUID = UUID()
|
var refresh: () -> ()
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
Group {
|
Group {
|
||||||
@@ -31,9 +31,8 @@ struct FlashCardListRowView: View {
|
|||||||
} catch {
|
} catch {
|
||||||
print("Something went wrong while saving favorite cards, please try again")
|
print("Something went wrong while saving favorite cards, please try again")
|
||||||
}
|
}
|
||||||
refresh = UUID()
|
refresh()
|
||||||
}
|
}
|
||||||
.id(refresh)
|
|
||||||
.padding(.trailing)
|
.padding(.trailing)
|
||||||
VStack {
|
VStack {
|
||||||
Text(flashcard.name ?? "Unknown")
|
Text(flashcard.name ?? "Unknown")
|
||||||
@@ -52,12 +51,14 @@ struct FlashCardListRowView: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
let flashcard = try? DataController.preview.viewContext.fetch(Flashcard.fetchRequest()).first
|
let flashcard = try? DataController.preview.viewContext.fetch(Flashcard.fetchRequest()).first
|
||||||
|
func reloadPage() {
|
||||||
|
}
|
||||||
return Group {
|
return Group {
|
||||||
FlashCardListRowView(flashcard: flashcard!)
|
FlashCardListRowView(flashcard: flashcard!, refresh: reloadPage)
|
||||||
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
||||||
FlashCardListRowView(flashcard: flashcard!)
|
FlashCardListRowView(flashcard: flashcard!, refresh: reloadPage)
|
||||||
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
||||||
FlashCardListRowView(flashcard: flashcard!)
|
FlashCardListRowView(flashcard: flashcard!, refresh: reloadPage)
|
||||||
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,44 +15,50 @@ struct FlashCardListView: View {
|
|||||||
var deck: Deck?
|
var deck: Deck?
|
||||||
@Environment(\.managedObjectContext) var moc
|
@Environment(\.managedObjectContext) var moc
|
||||||
|
|
||||||
|
private struct AddButton: View {
|
||||||
|
@Binding var addFlashcard: Bool
|
||||||
|
var text: String
|
||||||
|
var body: some View {
|
||||||
|
Button(action: {
|
||||||
|
self.addFlashcard = true
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "plus.circle.fill")
|
||||||
|
.padding(.trailing)
|
||||||
|
Text(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
Group {
|
List {
|
||||||
if !flashcards.isEmpty {
|
AddButton(addFlashcard: $addFlashcard, text: "Add new Flashcard")
|
||||||
List {
|
.frame(maxHeight: geometry.size.height / 10)
|
||||||
ForEach(flashcards) { flashcard in
|
ForEach(flashcards) { flashcard in
|
||||||
NavigationLink {
|
NavigationLink {
|
||||||
FlashCardView(flashcard: flashcard, showDescription: $showDescription)
|
FlashCardView(flashcard: flashcard, showDescription: $showDescription)
|
||||||
} label: {
|
} label: {
|
||||||
FlashCardListRowView(flashcard: flashcard)
|
FlashCardListRowView(flashcard: flashcard, refresh: refreshFlashcards)
|
||||||
}
|
|
||||||
}
|
|
||||||
.onDelete(perform: { offsets in
|
|
||||||
for index in offsets {
|
|
||||||
let flashcard = flashcards[index]
|
|
||||||
moc.delete(flashcard)
|
|
||||||
flashcards.remove(at: index)
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
try moc.save()
|
|
||||||
} catch {
|
|
||||||
print("Something went wrong while deleting an object")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Group {
|
|
||||||
Text("You currently don't have any flashcards. To add flashcards, either click at the '+' button at the top or you can download them from the store (coming soon)")
|
|
||||||
.padding()
|
|
||||||
.background(.purple)
|
|
||||||
.clipShape(.buttonBorder)
|
|
||||||
}
|
|
||||||
.frame(maxHeight: .infinity)
|
|
||||||
.padding(.horizontal)
|
|
||||||
}
|
}
|
||||||
|
.onDelete(perform: { offsets in
|
||||||
|
for index in offsets {
|
||||||
|
let flashcard = flashcards[index]
|
||||||
|
moc.delete(flashcard)
|
||||||
|
flashcards.remove(at: index)
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try moc.save()
|
||||||
|
} catch {
|
||||||
|
print("Something went wrong while deleting an object")
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
.environment(\.defaultMinListRowHeight, geometry.size.height / 12)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
refreshFlashcards()
|
refreshFlashcards()
|
||||||
}
|
}
|
||||||
@@ -64,20 +70,22 @@ struct FlashCardListView: View {
|
|||||||
.navigationBarTitle(deck?.name ?? "All Flashcards", displayMode: deck != nil ? .inline : .automatic)
|
.navigationBarTitle(deck?.name ?? "All Flashcards", displayMode: deck != nil ? .inline : .automatic)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItemGroup(placement: .topBarTrailing) {
|
ToolbarItemGroup(placement: .topBarTrailing) {
|
||||||
Button(action: {
|
EditButton()
|
||||||
self.addFlashcard = true
|
|
||||||
}) {
|
|
||||||
Image(systemName: "plus")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $addFlashcard, content: {
|
.sheet(isPresented: $addFlashcard, content: {
|
||||||
AddFlashCardView(isShowing: $addFlashcard, selectedDeck: deck)
|
AddFlashCardView(isShowing: $addFlashcard, selectedDeck: deck, flashcard: createFlashcard())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func createFlashcard() -> Flashcard {
|
||||||
|
let flashcard = Flashcard(context:moc)
|
||||||
|
flashcard.id = UUID()
|
||||||
|
return flashcard
|
||||||
|
}
|
||||||
|
|
||||||
private func refreshFlashcards() {
|
private func refreshFlashcards() {
|
||||||
let request = NSFetchRequest<Flashcard>(entityName: "Flashcard")
|
let request = NSFetchRequest<Flashcard>(entityName: "Flashcard")
|
||||||
request.sortDescriptors = [NSSortDescriptor(key: "favorite", ascending: false), NSSortDescriptor(key: "dateAdded", ascending: false)]
|
request.sortDescriptors = [NSSortDescriptor(key: "favorite", ascending: false), NSSortDescriptor(key: "dateAdded", ascending: false)]
|
||||||
@@ -87,13 +95,12 @@ struct FlashCardListView: View {
|
|||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
flashcards = try moc.fetch(request)
|
flashcards = try moc.fetch(request)
|
||||||
print(flashcards)
|
|
||||||
} catch {
|
} catch {
|
||||||
print("Something went wrong while fetching the flashcards")
|
print("Something went wrong while fetching the flashcards")
|
||||||
flashcards = []
|
flashcards = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
|
|||||||
@@ -13,11 +13,13 @@ struct FlashCardView: View {
|
|||||||
var flashcard: Flashcard
|
var flashcard: Flashcard
|
||||||
@Binding var showDescription: Bool
|
@Binding var showDescription: Bool
|
||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
@State var editFlashcard: Bool = false
|
||||||
|
@State var showHint: Bool = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let flashcardText = Text(flashcard.name ?? "Unknown")
|
let flashcardText = Text(flashcard.name ?? "Unknown")
|
||||||
.font(.title)
|
.font(.title)
|
||||||
|
.textSelection(.enabled)
|
||||||
.bold()
|
.bold()
|
||||||
VStack {
|
VStack {
|
||||||
// TODO: Figure out if this and create/edit menu could be more similar?
|
// TODO: Figure out if this and create/edit menu could be more similar?
|
||||||
@@ -32,7 +34,6 @@ struct FlashCardView: View {
|
|||||||
.padding(.bottom)
|
.padding(.bottom)
|
||||||
}
|
}
|
||||||
flashcardText
|
flashcardText
|
||||||
.textSelection(.enabled)
|
|
||||||
Divider()
|
Divider()
|
||||||
.background(colorScheme == .light ? Color.black : Color.white)
|
.background(colorScheme == .light ? Color.black : Color.white)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
@@ -41,6 +42,21 @@ struct FlashCardView: View {
|
|||||||
} else {
|
} else {
|
||||||
flashcardText
|
flashcardText
|
||||||
}
|
}
|
||||||
|
if !showDescription && flashcard.hint != nil {
|
||||||
|
if showHint {
|
||||||
|
Text((flashcard.hint != nil) ? "Hint: \(flashcard.hint ?? "")" : "")
|
||||||
|
.padding()
|
||||||
|
.font(.footnote)
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
showHint.toggle()
|
||||||
|
} label: {
|
||||||
|
Text(showHint ? "Hide Hint" : "Show Hint")
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
// .disabled(flashcard.hint == nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.padding([.horizontal, .top])
|
.padding([.horizontal, .top])
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
@@ -48,11 +64,21 @@ struct FlashCardView: View {
|
|||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
self.showDescription = true
|
self.showDescription = true
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: $editFlashcard) {
|
||||||
|
AddFlashCardView(text: flashcard.name ?? "", description: flashcard.desc ?? "", isShowing: $editFlashcard, selectedDeck: flashcard.deck, flashcard: flashcard, edit: true)
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
Button {
|
||||||
|
self.editFlashcard = true
|
||||||
|
} label: {
|
||||||
|
Text("Edit")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
@State var showDescription = true
|
@State var showDescription = false
|
||||||
let flashcard = try? DataController.preview.viewContext.fetch(Flashcard.fetchRequest()).first
|
let flashcard = try? DataController.preview.viewContext.fetch(Flashcard.fetchRequest()).first
|
||||||
return FlashCardView(flashcard: flashcard!, showDescription: $showDescription)
|
return FlashCardView(flashcard: flashcard!, showDescription: $showDescription)
|
||||||
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
.environment(\.managedObjectContext, DataController.preview.container.viewContext)
|
||||||
|
|||||||
Reference in New Issue
Block a user