From c253938cb9b52e1e757adb9e94fb5e6cde816365 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Fri, 23 Feb 2024 14:17:03 +0100 Subject: [PATCH 01/15] Added navigation and tab views --- WordAX.xcodeproj/project.pbxproj | 24 +++++++++++++++--- WordAX/AnkiView.swift | 18 ++++++++++++++ WordAX/ContentView.swift | 24 ------------------ WordAX/MainView.swift | 42 ++++++++++++++++++++++++++++++++ WordAX/SettingsView.swift | 18 ++++++++++++++ WordAX/WordAX.swift | 8 ++++++ WordAX/WordAXModel.swift | 8 ++++++ WordAX/WordAXModelView.swift | 8 ++++++ 8 files changed, 122 insertions(+), 28 deletions(-) create mode 100644 WordAX/AnkiView.swift delete mode 100644 WordAX/ContentView.swift create mode 100644 WordAX/MainView.swift create mode 100644 WordAX/SettingsView.swift create mode 100644 WordAX/WordAX.swift create mode 100644 WordAX/WordAXModel.swift create mode 100644 WordAX/WordAXModelView.swift diff --git a/WordAX.xcodeproj/project.pbxproj b/WordAX.xcodeproj/project.pbxproj index e65cbac..cf6985b 100644 --- a/WordAX.xcodeproj/project.pbxproj +++ b/WordAX.xcodeproj/project.pbxproj @@ -7,16 +7,24 @@ objects = { /* Begin PBXBuildFile section */ + 6C8184FE2B88C9580033CF46 /* WordAX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8184FD2B88C9580033CF46 /* WordAX.swift */; }; + 6C8185002B88C9660033CF46 /* WordAXModelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8184FF2B88C9660033CF46 /* WordAXModelView.swift */; }; + 6C8185022B88C9FB0033CF46 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185012B88C9FB0033CF46 /* SettingsView.swift */; }; + 6C8185042B88CA210033CF46 /* AnkiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185032B88CA210033CF46 /* AnkiView.swift */; }; 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439512B83541D004C3543 /* WordAXApp.swift */; }; - 6CF439542B83541D004C3543 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439532B83541D004C3543 /* ContentView.swift */; }; + 6CF439542B83541D004C3543 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439532B83541D004C3543 /* MainView.swift */; }; 6CF439562B83541E004C3543 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439552B83541E004C3543 /* Assets.xcassets */; }; 6CF439592B83541E004C3543 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439582B83541E004C3543 /* Preview Assets.xcassets */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6C8184FD2B88C9580033CF46 /* WordAX.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAX.swift; sourceTree = ""; }; + 6C8184FF2B88C9660033CF46 /* WordAXModelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAXModelView.swift; sourceTree = ""; }; + 6C8185012B88C9FB0033CF46 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + 6C8185032B88CA210033CF46 /* AnkiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnkiView.swift; sourceTree = ""; }; 6CF4394E2B83541D004C3543 /* WordAX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WordAX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6CF439512B83541D004C3543 /* WordAXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAXApp.swift; sourceTree = ""; }; - 6CF439532B83541D004C3543 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 6CF439532B83541D004C3543 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 6CF439552B83541E004C3543 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 6CF439582B83541E004C3543 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -52,7 +60,11 @@ isa = PBXGroup; children = ( 6CF439512B83541D004C3543 /* WordAXApp.swift */, - 6CF439532B83541D004C3543 /* ContentView.swift */, + 6CF439532B83541D004C3543 /* MainView.swift */, + 6C8185012B88C9FB0033CF46 /* SettingsView.swift */, + 6C8185032B88CA210033CF46 /* AnkiView.swift */, + 6C8184FD2B88C9580033CF46 /* WordAX.swift */, + 6C8184FF2B88C9660033CF46 /* WordAXModelView.swift */, 6CF439552B83541E004C3543 /* Assets.xcassets */, 6CF439572B83541E004C3543 /* Preview Content */, ); @@ -137,8 +149,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6CF439542B83541D004C3543 /* ContentView.swift in Sources */, + 6C8185022B88C9FB0033CF46 /* SettingsView.swift in Sources */, + 6CF439542B83541D004C3543 /* MainView.swift in Sources */, + 6C8185002B88C9660033CF46 /* WordAXModelView.swift in Sources */, + 6C8185042B88CA210033CF46 /* AnkiView.swift in Sources */, 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */, + 6C8184FE2B88C9580033CF46 /* WordAX.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WordAX/AnkiView.swift b/WordAX/AnkiView.swift new file mode 100644 index 0000000..d784c6e --- /dev/null +++ b/WordAX/AnkiView.swift @@ -0,0 +1,18 @@ +// +// AnkiView.swift +// WordAX +// +// Created by Oliver Hnát on 23.02.2024. +// + +import SwiftUI + +struct AnkiView: View { + var body: some View { + Text("This is Anki View") + } +} + +#Preview { + AnkiView() +} diff --git a/WordAX/ContentView.swift b/WordAX/ContentView.swift deleted file mode 100644 index 75540a9..0000000 --- a/WordAX/ContentView.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ContentView.swift -// WordAX -// -// Created by Oliver Hnát on 19.02.2024. -// - -import SwiftUI - -struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundStyle(.tint) - Text("Hello, world!") - } - .padding() - } -} - -#Preview { - ContentView() -} diff --git a/WordAX/MainView.swift b/WordAX/MainView.swift new file mode 100644 index 0000000..eae77ba --- /dev/null +++ b/WordAX/MainView.swift @@ -0,0 +1,42 @@ +// +// ContentView.swift +// WordAX +// +// Created by Oliver Hnát on 19.02.2024. +// + +import SwiftUI + +struct MainView: View { + @State var selectedTab = "Anki" + init() { + UITabBar.appearance().backgroundColor = UIColor.systemGray5 + } + var body: some View { + ZStack { + TabView(selection: $selectedTab) { + Group { + AnkiView() + .tag("Anki") + .tabItem { + Image(systemName: "star") + Text("Anki") + } + SettingsView() + .tag("Settings") + .tabItem { + Image(systemName: "gear") + Text("Settings") + } + } + .toolbar(.visible, for: .tabBar) + .toolbarBackground(Color.yellow, for: .tabBar) + } + } + + } +} + +#Preview { + MainView() +} diff --git a/WordAX/SettingsView.swift b/WordAX/SettingsView.swift new file mode 100644 index 0000000..1d26cd3 --- /dev/null +++ b/WordAX/SettingsView.swift @@ -0,0 +1,18 @@ +// +// SettingsView.swift +// WordAX +// +// Created by Oliver Hnát on 23.02.2024. +// + +import SwiftUI + +struct SettingsView: View { + var body: some View { + Text("This is settings") + } +} + +#Preview { + SettingsView() +} diff --git a/WordAX/WordAX.swift b/WordAX/WordAX.swift new file mode 100644 index 0000000..1637ea0 --- /dev/null +++ b/WordAX/WordAX.swift @@ -0,0 +1,8 @@ +// +// WordAX.swift +// WordAX +// +// Created by Oliver Hnát on 23.02.2024. +// + +import Foundation diff --git a/WordAX/WordAXModel.swift b/WordAX/WordAXModel.swift new file mode 100644 index 0000000..8a41561 --- /dev/null +++ b/WordAX/WordAXModel.swift @@ -0,0 +1,8 @@ +// +// WordAXModel.swift +// WordAX +// +// Created by Oliver Hnát on 23.02.2024. +// + +import Foundation diff --git a/WordAX/WordAXModelView.swift b/WordAX/WordAXModelView.swift new file mode 100644 index 0000000..972e181 --- /dev/null +++ b/WordAX/WordAXModelView.swift @@ -0,0 +1,8 @@ +// +// WordAXModelView.swift +// WordAX +// +// Created by Oliver Hnát on 23.02.2024. +// + +import Foundation From 5f474ca9cdcbbc491a160a04c94aa0202228911e Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Fri, 23 Feb 2024 14:17:35 +0100 Subject: [PATCH 02/15] Add environment object to all views and delete unused code from MainView --- WordAX/AnkiView.swift | 2 ++ WordAX/MainView.swift | 4 ++-- WordAX/SettingsView.swift | 1 + WordAX/WordAXApp.swift | 4 +++- WordAX/WordAXModelView.swift | 6 ++++++ 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/WordAX/AnkiView.swift b/WordAX/AnkiView.swift index d784c6e..3d3772e 100644 --- a/WordAX/AnkiView.swift +++ b/WordAX/AnkiView.swift @@ -8,6 +8,7 @@ import SwiftUI struct AnkiView: View { + @EnvironmentObject var model: WordAXModelView var body: some View { Text("This is Anki View") } @@ -15,4 +16,5 @@ struct AnkiView: View { #Preview { AnkiView() + .environmentObject(WordAXModelView()) } diff --git a/WordAX/MainView.swift b/WordAX/MainView.swift index eae77ba..f70e448 100644 --- a/WordAX/MainView.swift +++ b/WordAX/MainView.swift @@ -29,9 +29,8 @@ struct MainView: View { Text("Settings") } } - .toolbar(.visible, for: .tabBar) - .toolbarBackground(Color.yellow, for: .tabBar) } + } } @@ -39,4 +38,5 @@ struct MainView: View { #Preview { MainView() + .environmentObject(WordAXModelView()) } diff --git a/WordAX/SettingsView.swift b/WordAX/SettingsView.swift index 1d26cd3..a2f82f3 100644 --- a/WordAX/SettingsView.swift +++ b/WordAX/SettingsView.swift @@ -15,4 +15,5 @@ struct SettingsView: View { #Preview { SettingsView() + .environmentObject(WordAXModelView()) } diff --git a/WordAX/WordAXApp.swift b/WordAX/WordAXApp.swift index 14002ce..da4c172 100644 --- a/WordAX/WordAXApp.swift +++ b/WordAX/WordAXApp.swift @@ -9,9 +9,11 @@ import SwiftUI @main struct WordAXApp: App { + @StateObject var model = WordAXModelView() var body: some Scene { WindowGroup { - ContentView() + MainView() + .environmentObject(model) } } } diff --git a/WordAX/WordAXModelView.swift b/WordAX/WordAXModelView.swift index 972e181..ebb0ca9 100644 --- a/WordAX/WordAXModelView.swift +++ b/WordAX/WordAXModelView.swift @@ -6,3 +6,9 @@ // import Foundation + +class WordAXModelView: ObservableObject { + init() { + + } +} From 5b383f6258b13906b4d879228355a8ecc0d1d76d Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Sat, 24 Feb 2024 17:40:16 +0100 Subject: [PATCH 03/15] Add basic backend for showing words --- .../xcshareddata/xcschemes/WordAX.xcscheme | 77 +++++++++++++++++++ .../xcschemes/xcschememanagement.plist | 8 ++ WordAX/WordAX.swift | 59 ++++++++++++++ WordAX/WordAXModelView.swift | 55 +++++++++++++ 4 files changed, 199 insertions(+) create mode 100644 WordAX.xcodeproj/xcshareddata/xcschemes/WordAX.xcscheme diff --git a/WordAX.xcodeproj/xcshareddata/xcschemes/WordAX.xcscheme b/WordAX.xcodeproj/xcshareddata/xcschemes/WordAX.xcscheme new file mode 100644 index 0000000..8ec4807 --- /dev/null +++ b/WordAX.xcodeproj/xcshareddata/xcschemes/WordAX.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WordAX.xcodeproj/xcuserdata/oliverhnat.xcuserdatad/xcschemes/xcschememanagement.plist b/WordAX.xcodeproj/xcuserdata/oliverhnat.xcuserdatad/xcschemes/xcschememanagement.plist index 6f9e193..b73851d 100644 --- a/WordAX.xcodeproj/xcuserdata/oliverhnat.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/WordAX.xcodeproj/xcuserdata/oliverhnat.xcuserdatad/xcschemes/xcschememanagement.plist @@ -10,5 +10,13 @@ 0 + SuppressBuildableAutocreation + + 6CF4394D2B83541D004C3543 + + primary + + + diff --git a/WordAX/WordAX.swift b/WordAX/WordAX.swift index 1637ea0..a768be2 100644 --- a/WordAX/WordAX.swift +++ b/WordAX/WordAX.swift @@ -6,3 +6,62 @@ // import Foundation + +struct WordAX { + struct Word: Identifiable { + var id: Int + var name: String + var description: String + var shown: Bool + var nextSpacedRepetitionMilestone: SpacedRepetitionMilestoneEnum? + var displayOn: Date? + } + enum FrequencyEnum: Int { + case Daily = 1 + case Weekly = 7 + case BiWeekly = 14 + case Monthly = 30 + } + + enum SpacedRepetitionMilestoneEnum: Int, CaseIterable { + case OneDay = 1 + case OneWeek = 7 + case TwoWeeks = 14 + case OneMonth = 30 + case TwoMonths = 60 + case FiveMonths = 150 + case OneYear = 365 + + static var allCasesSorted: [SpacedRepetitionMilestoneEnum] { + allCases.sorted {$0.rawValue < $1.rawValue } + } + } + + struct Settings { + var frequency: FrequencyEnum = .Daily + var lastShownNew: Date? + } + + private mutating func setNextSpacedRepetitionMilestone(word: Word) { + if word.nextSpacedRepetitionMilestone != nil { + let current = SpacedRepetitionMilestoneEnum.allCasesSorted.firstIndex(of: word.nextSpacedRepetitionMilestone!) ?? SpacedRepetitionMilestoneEnum.allCases.count + let index = words.firstIndex(where:{$0.id == word.id}) ?? nil + if current + 1 < SpacedRepetitionMilestoneEnum.allCases.count && index != nil { + words[index!].nextSpacedRepetitionMilestone = SpacedRepetitionMilestoneEnum.allCasesSorted[current + 1] + } else if index != nil { + words[index!].nextSpacedRepetitionMilestone = nil + } + } + } + + var words: [Word] = [] + var settings: Settings + + init() { + self.words = [] + self.settings = Settings() + self.words.append(Word(id: 0, name: "Magnificent", description: "When something is awesome", shown: false)) + self.words.append(Word(id: 1, name: "Mesmerising", description: "When something is beautiful", shown: false)) + } + +} diff --git a/WordAX/WordAXModelView.swift b/WordAX/WordAXModelView.swift index ebb0ca9..8851a00 100644 --- a/WordAX/WordAXModelView.swift +++ b/WordAX/WordAXModelView.swift @@ -8,7 +8,62 @@ import Foundation class WordAXModelView: ObservableObject { + @Published private var model: WordAX + typealias Word = WordAX.Word init() { + model = WordAX() + } + + public func getWordToDisplay() -> Word? { + let words = model.words + if words.count > 0 { + // if today is the date they're supposed to be shown + let displayToday = words.filter({ $0.displayOn != nil && $0.displayOn!.isToday()}) + if displayToday.count > 0 { + return displayToday.first! + } + + // first word ever shown + let shownWords = words.filter({ $0.shown }) + if shownWords.count == 0 { + return words.first! + } + // if today is the day to show a new word + let settings = model.settings + if shownWords.count == 0 || + settings.lastShownNew == nil || + settings.lastShownNew!.addingTimeInterval(TimeInterval(settings.frequency.rawValue * 24 * 60 * 60)).isAfterToday() { + return words.first! + } + } + // otherwise show nothing + return nil + } +} + + +extension Date { + private func getOnlyDate(date: Date) -> DateComponents { + Calendar.current.dateComponents([.day, .month, .year], from: date) + } + func isSameAs(_ date: Date) -> Bool { + let selfDate = getOnlyDate(date: self) + let paramDate = getOnlyDate(date: date) + return selfDate.day == paramDate.day && selfDate.month == paramDate.month && selfDate.year == paramDate.year + } + + func isToday() -> Bool { + self.isSameAs(Date()) + } + + func isAfter(_ date: Date) -> Bool { + let selfDate = getOnlyDate(date: self) + let paramDate = getOnlyDate(date: date) + return selfDate.year! > paramDate.year! || selfDate.month! > paramDate.month! || selfDate.day! > paramDate.day! + } + + func isAfterToday() -> Bool { + self.isAfter(Date()) } } From 83deb094252e001cb3dc56d14ede5ad7b6a9e5b3 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Sat, 24 Feb 2024 18:39:33 +0100 Subject: [PATCH 04/15] Add WordView, fix some functions, add basic implementation of AnkiView --- WordAX.xcodeproj/project.pbxproj | 4 ++++ WordAX/AnkiView.swift | 9 ++++++- WordAX/WordAX.swift | 18 +++++++++++--- WordAX/WordAXModelView.swift | 13 +++++++++-- WordAX/WordView.swift | 40 ++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 WordAX/WordView.swift diff --git a/WordAX.xcodeproj/project.pbxproj b/WordAX.xcodeproj/project.pbxproj index cf6985b..76767c3 100644 --- a/WordAX.xcodeproj/project.pbxproj +++ b/WordAX.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 6C8185002B88C9660033CF46 /* WordAXModelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8184FF2B88C9660033CF46 /* WordAXModelView.swift */; }; 6C8185022B88C9FB0033CF46 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185012B88C9FB0033CF46 /* SettingsView.swift */; }; 6C8185042B88CA210033CF46 /* AnkiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185032B88CA210033CF46 /* AnkiView.swift */; }; + 6C8185062B8A537F0033CF46 /* WordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185052B8A537F0033CF46 /* WordView.swift */; }; 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439512B83541D004C3543 /* WordAXApp.swift */; }; 6CF439542B83541D004C3543 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439532B83541D004C3543 /* MainView.swift */; }; 6CF439562B83541E004C3543 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439552B83541E004C3543 /* Assets.xcassets */; }; @@ -22,6 +23,7 @@ 6C8184FF2B88C9660033CF46 /* WordAXModelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAXModelView.swift; sourceTree = ""; }; 6C8185012B88C9FB0033CF46 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 6C8185032B88CA210033CF46 /* AnkiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnkiView.swift; sourceTree = ""; }; + 6C8185052B8A537F0033CF46 /* WordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordView.swift; sourceTree = ""; }; 6CF4394E2B83541D004C3543 /* WordAX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WordAX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6CF439512B83541D004C3543 /* WordAXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAXApp.swift; sourceTree = ""; }; 6CF439532B83541D004C3543 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -63,6 +65,7 @@ 6CF439532B83541D004C3543 /* MainView.swift */, 6C8185012B88C9FB0033CF46 /* SettingsView.swift */, 6C8185032B88CA210033CF46 /* AnkiView.swift */, + 6C8185052B8A537F0033CF46 /* WordView.swift */, 6C8184FD2B88C9580033CF46 /* WordAX.swift */, 6C8184FF2B88C9660033CF46 /* WordAXModelView.swift */, 6CF439552B83541E004C3543 /* Assets.xcassets */, @@ -151,6 +154,7 @@ files = ( 6C8185022B88C9FB0033CF46 /* SettingsView.swift in Sources */, 6CF439542B83541D004C3543 /* MainView.swift in Sources */, + 6C8185062B8A537F0033CF46 /* WordView.swift in Sources */, 6C8185002B88C9660033CF46 /* WordAXModelView.swift in Sources */, 6C8185042B88CA210033CF46 /* AnkiView.swift in Sources */, 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */, diff --git a/WordAX/AnkiView.swift b/WordAX/AnkiView.swift index 3d3772e..cfd594e 100644 --- a/WordAX/AnkiView.swift +++ b/WordAX/AnkiView.swift @@ -9,8 +9,15 @@ import SwiftUI struct AnkiView: View { @EnvironmentObject var model: WordAXModelView + var word: WordAX.Word? { + model.getWordToDisplay() + } var body: some View { - Text("This is Anki View") + if word != nil { + WordView(word: word!) + } else { + Text("There is no word to display, come back later") + } } } diff --git a/WordAX/WordAX.swift b/WordAX/WordAX.swift index a768be2..3342746 100644 --- a/WordAX/WordAX.swift +++ b/WordAX/WordAX.swift @@ -14,7 +14,7 @@ struct WordAX { var description: String var shown: Bool var nextSpacedRepetitionMilestone: SpacedRepetitionMilestoneEnum? - var displayOn: Date? + var lastSeenOn: Date? } enum FrequencyEnum: Int { case Daily = 1 @@ -35,11 +35,21 @@ struct WordAX { static var allCasesSorted: [SpacedRepetitionMilestoneEnum] { allCases.sorted {$0.rawValue < $1.rawValue } } + + func getNext() -> SpacedRepetitionMilestoneEnum? { + let sorted = WordAX.SpacedRepetitionMilestoneEnum.allCasesSorted + let milestoneIndex = sorted.firstIndex(where: {$0.rawValue == self.rawValue})! + if milestoneIndex < WordAX.SpacedRepetitionMilestoneEnum.allCasesSorted.count { + return sorted[milestoneIndex + 1] + } + return nil + } } struct Settings { var frequency: FrequencyEnum = .Daily var lastShownNew: Date? + var dateFormatter: DateFormatter } private mutating func setNextSpacedRepetitionMilestone(word: Word) { @@ -59,8 +69,10 @@ struct WordAX { init() { self.words = [] - self.settings = Settings() - self.words.append(Word(id: 0, name: "Magnificent", description: "When something is awesome", shown: false)) + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "dd/mm/YYYY" + self.settings = Settings(dateFormatter: dateFormatter) + self.words.append(Word(id: 0, name: "Magnificent", description: "When something is awesome. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.", shown: false)) self.words.append(Word(id: 1, name: "Mesmerising", description: "When something is beautiful", shown: false)) } diff --git a/WordAX/WordAXModelView.swift b/WordAX/WordAXModelView.swift index 8851a00..727a440 100644 --- a/WordAX/WordAXModelView.swift +++ b/WordAX/WordAXModelView.swift @@ -14,12 +14,17 @@ class WordAXModelView: ObservableObject { model = WordAX() } + public func getDateFormatter() -> DateFormatter { + model.settings.dateFormatter + } + public func getWordToDisplay() -> Word? { let words = model.words if words.count > 0 { // if today is the date they're supposed to be shown - let displayToday = words.filter({ $0.displayOn != nil && $0.displayOn!.isToday()}) + + let displayToday = words.filter({ $0.lastSeenOn != nil && $0.lastSeenOn!.add}) if displayToday.count > 0 { return displayToday.first! } @@ -33,7 +38,7 @@ class WordAXModelView: ObservableObject { let settings = model.settings if shownWords.count == 0 || settings.lastShownNew == nil || - settings.lastShownNew!.addingTimeInterval(TimeInterval(settings.frequency.rawValue * 24 * 60 * 60)).isAfterToday() { + settings.lastShownNew!.addFrequency(frequency: settings.frequency).isAfterToday() { return words.first! } } @@ -63,6 +68,10 @@ extension Date { return selfDate.year! > paramDate.year! || selfDate.month! > paramDate.month! || selfDate.day! > paramDate.day! } + func addFrequency(frequency: WordAX.FrequencyEnum) -> Date { + self.addingTimeInterval(TimeInterval(frequency.rawValue * 24 * 60 * 60)) + } + func isAfterToday() -> Bool { self.isAfter(Date()) } diff --git a/WordAX/WordView.swift b/WordAX/WordView.swift new file mode 100644 index 0000000..1ef89d9 --- /dev/null +++ b/WordAX/WordView.swift @@ -0,0 +1,40 @@ +// +// WordView.swift +// WordAX +// +// Created by Oliver Hnát on 24.02.2024. +// + +import SwiftUI +import UIKit + +struct WordView: View { + var word: WordAX.Word + var showDescription: Bool = true + @EnvironmentObject var model: WordAXModelView + @Environment(\.colorScheme) var colorScheme + + var body: some View { + VStack { + Text(word.name) + .font(.title) + .bold() + if word.shown && word.lastSeenOn != nil { + Text(model.getDateFormatter().string(from: word.lastSeenOn!)) + } + if showDescription { + Divider() + .background(colorScheme == .light ? Color.black : Color.white) + .padding(.horizontal) + Text(word.description) + .multilineTextAlignment(.center) + } + } + .padding([.horizontal, .top]) + } +} + +#Preview { + WordView(word: WordAXModelView().getWordToDisplay()!) + .environmentObject(WordAXModelView()) +} From c81eb49364661016b030760ea53df4ee5d2bf0b3 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Sun, 25 Feb 2024 11:17:11 +0100 Subject: [PATCH 05/15] OnClick anywhere on the screen of the word, the description appears --- WordAX/WordAXModelView.swift | 10 +++++++++- WordAX/WordView.swift | 7 ++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/WordAX/WordAXModelView.swift b/WordAX/WordAXModelView.swift index 727a440..c2ac620 100644 --- a/WordAX/WordAXModelView.swift +++ b/WordAX/WordAXModelView.swift @@ -24,7 +24,7 @@ class WordAXModelView: ObservableObject { if words.count > 0 { // if today is the date they're supposed to be shown - let displayToday = words.filter({ $0.lastSeenOn != nil && $0.lastSeenOn!.add}) + let displayToday = words.filter({ $0.lastSeenOn != nil && $0.lastSeenOn!.addSpacedRepetitionMilestone(milestone: $0.nextSpacedRepetitionMilestone!).isAfterTodayOrToday()}) if displayToday.count > 0 { return displayToday.first! } @@ -72,7 +72,15 @@ extension Date { self.addingTimeInterval(TimeInterval(frequency.rawValue * 24 * 60 * 60)) } + func addSpacedRepetitionMilestone(milestone: WordAX.SpacedRepetitionMilestoneEnum) -> Date { + self.addingTimeInterval(TimeInterval(milestone.rawValue * 24 * 60 * 60)) + } + func isAfterToday() -> Bool { self.isAfter(Date()) } + + func isAfterTodayOrToday() -> Bool { + self.isAfterToday() || self.isToday() + } } diff --git a/WordAX/WordView.swift b/WordAX/WordView.swift index 1ef89d9..9c4f5db 100644 --- a/WordAX/WordView.swift +++ b/WordAX/WordView.swift @@ -10,7 +10,7 @@ import UIKit struct WordView: View { var word: WordAX.Word - var showDescription: Bool = true + @State var showDescription: Bool = false @EnvironmentObject var model: WordAXModelView @Environment(\.colorScheme) var colorScheme @@ -31,6 +31,11 @@ struct WordView: View { } } .padding([.horizontal, .top]) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .contentShape(Rectangle()) + .onTapGesture { + self.showDescription = true + } } } From 2bebe1e16785e2e5ba10040e728dd1761b22d121 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Sun, 25 Feb 2024 11:42:45 +0100 Subject: [PATCH 06/15] Make the text selectable (for copying and lookup), after description is shown --- WordAX/WordView.swift | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/WordAX/WordView.swift b/WordAX/WordView.swift index 9c4f5db..de7dbf4 100644 --- a/WordAX/WordView.swift +++ b/WordAX/WordView.swift @@ -14,20 +14,26 @@ struct WordView: View { @EnvironmentObject var model: WordAXModelView @Environment(\.colorScheme) var colorScheme + var body: some View { + let wordText = Text(word.name) + .font(.title) + .bold() + VStack { - Text(word.name) - .font(.title) - .bold() if word.shown && word.lastSeenOn != nil { Text(model.getDateFormatter().string(from: word.lastSeenOn!)) } if showDescription { + wordText + .textSelection(.enabled) Divider() .background(colorScheme == .light ? Color.black : Color.white) .padding(.horizontal) Text(word.description) .multilineTextAlignment(.center) + } else { + wordText } } .padding([.horizontal, .top]) From 69ffe49e8a52b79c611740159a8e2d92b90a5464 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Sun, 25 Feb 2024 14:47:52 +0100 Subject: [PATCH 07/15] Add buttons for light and dark mode, fix functions for setting/getting milestone --- WordAX.xcodeproj/project.pbxproj | 4 +++ WordAX/AnkiView.swift | 16 ++++++++++- WordAX/NextRepetitionButtonView.swift | 39 +++++++++++++++++++++++++++ WordAX/WordAX.swift | 16 ++++++++--- WordAX/WordAXModelView.swift | 4 +++ WordAX/WordView.swift | 6 ++--- 6 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 WordAX/NextRepetitionButtonView.swift diff --git a/WordAX.xcodeproj/project.pbxproj b/WordAX.xcodeproj/project.pbxproj index 76767c3..75a78d0 100644 --- a/WordAX.xcodeproj/project.pbxproj +++ b/WordAX.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 6C8185022B88C9FB0033CF46 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185012B88C9FB0033CF46 /* SettingsView.swift */; }; 6C8185042B88CA210033CF46 /* AnkiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185032B88CA210033CF46 /* AnkiView.swift */; }; 6C8185062B8A537F0033CF46 /* WordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185052B8A537F0033CF46 /* WordView.swift */; }; + 6C8185082B8B523E0033CF46 /* NextRepetitionButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */; }; 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439512B83541D004C3543 /* WordAXApp.swift */; }; 6CF439542B83541D004C3543 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439532B83541D004C3543 /* MainView.swift */; }; 6CF439562B83541E004C3543 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439552B83541E004C3543 /* Assets.xcassets */; }; @@ -24,6 +25,7 @@ 6C8185012B88C9FB0033CF46 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 6C8185032B88CA210033CF46 /* AnkiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnkiView.swift; sourceTree = ""; }; 6C8185052B8A537F0033CF46 /* WordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordView.swift; sourceTree = ""; }; + 6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextRepetitionButtonView.swift; sourceTree = ""; }; 6CF4394E2B83541D004C3543 /* WordAX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WordAX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6CF439512B83541D004C3543 /* WordAXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAXApp.swift; sourceTree = ""; }; 6CF439532B83541D004C3543 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -66,6 +68,7 @@ 6C8185012B88C9FB0033CF46 /* SettingsView.swift */, 6C8185032B88CA210033CF46 /* AnkiView.swift */, 6C8185052B8A537F0033CF46 /* WordView.swift */, + 6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */, 6C8184FD2B88C9580033CF46 /* WordAX.swift */, 6C8184FF2B88C9660033CF46 /* WordAXModelView.swift */, 6CF439552B83541E004C3543 /* Assets.xcassets */, @@ -154,6 +157,7 @@ files = ( 6C8185022B88C9FB0033CF46 /* SettingsView.swift in Sources */, 6CF439542B83541D004C3543 /* MainView.swift in Sources */, + 6C8185082B8B523E0033CF46 /* NextRepetitionButtonView.swift in Sources */, 6C8185062B8A537F0033CF46 /* WordView.swift in Sources */, 6C8185002B88C9660033CF46 /* WordAXModelView.swift in Sources */, 6C8185042B88CA210033CF46 /* AnkiView.swift in Sources */, diff --git a/WordAX/AnkiView.swift b/WordAX/AnkiView.swift index cfd594e..88041ce 100644 --- a/WordAX/AnkiView.swift +++ b/WordAX/AnkiView.swift @@ -9,12 +9,26 @@ import SwiftUI struct AnkiView: View { @EnvironmentObject var model: WordAXModelView + @State var showDescription = true var word: WordAX.Word? { model.getWordToDisplay() } var body: some View { if word != nil { - WordView(word: word!) + VStack { + WordView(word: word!, showDescription: $showDescription) + if showDescription { + Text("How did you do?") + .font(.subheadline) + .foregroundStyle(.gray) + HStack { + NextRepetitionButtonView(buttonText: "Poor", nextMilestone: word!.nextSpacedRepetitionMilestone, wordId: word!.id) + NextRepetitionButtonView(buttonText: "Good", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone), wordId: word!.id) + NextRepetitionButtonView(buttonText: "Excellent", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone)), wordId: word!.id) + } + .padding(.bottom) + } + } } else { Text("There is no word to display, come back later") } diff --git a/WordAX/NextRepetitionButtonView.swift b/WordAX/NextRepetitionButtonView.swift new file mode 100644 index 0000000..a86f307 --- /dev/null +++ b/WordAX/NextRepetitionButtonView.swift @@ -0,0 +1,39 @@ +// +// NextRepetitionButtonView.swift +// WordAX +// +// Created by Oliver Hnát on 25.02.2024. +// + +import SwiftUI + +struct NextRepetitionButtonView: View { + let buttonText: String + let nextMilestone: WordAX.SpacedRepetitionMilestoneEnum? + let wordId: Int + @EnvironmentObject var model: WordAXModelView + @Environment(\.colorScheme) var colorScheme + var body: some View { + Button(action: { + model.setSpacedRepetitionMilestone(wordId: wordId, milestone: nextMilestone) + }) { + Text(buttonText) + .padding() + .foregroundColor(colorScheme == .light ? .black : .white) + .background(colorScheme == .light ? .cyan : .darkCyan) + .clipShape(RoundedRectangle(cornerRadius: 50)) + } + } +} + +extension ShapeStyle where Self == Color { + // color darker version of cyan from hex palette + public static var darkCyan: Color { + Color(red: 34/255, green: 121/255, blue: 161/255) + } +} + +#Preview { + NextRepetitionButtonView(buttonText: "Excellent", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, wordId: 0) + .environmentObject(WordAXModelView()) +} diff --git a/WordAX/WordAX.swift b/WordAX/WordAX.swift index 3342746..2d3506d 100644 --- a/WordAX/WordAX.swift +++ b/WordAX/WordAX.swift @@ -36,9 +36,12 @@ struct WordAX { allCases.sorted {$0.rawValue < $1.rawValue } } - func getNext() -> SpacedRepetitionMilestoneEnum? { + static func getNext(milestone: SpacedRepetitionMilestoneEnum?) -> SpacedRepetitionMilestoneEnum? { + if milestone == nil { + return SpacedRepetitionMilestoneEnum.OneDay + } let sorted = WordAX.SpacedRepetitionMilestoneEnum.allCasesSorted - let milestoneIndex = sorted.firstIndex(where: {$0.rawValue == self.rawValue})! + let milestoneIndex = sorted.firstIndex(where: {$0.rawValue == milestone!.rawValue})! if milestoneIndex < WordAX.SpacedRepetitionMilestoneEnum.allCasesSorted.count { return sorted[milestoneIndex + 1] } @@ -52,7 +55,7 @@ struct WordAX { var dateFormatter: DateFormatter } - private mutating func setNextSpacedRepetitionMilestone(word: Word) { + public mutating func setNextSpacedRepetitionMilestone(word: Word) { if word.nextSpacedRepetitionMilestone != nil { let current = SpacedRepetitionMilestoneEnum.allCasesSorted.firstIndex(of: word.nextSpacedRepetitionMilestone!) ?? SpacedRepetitionMilestoneEnum.allCases.count let index = words.firstIndex(where:{$0.id == word.id}) ?? nil @@ -64,6 +67,13 @@ struct WordAX { } } + public mutating func setSpacedRepetitionMilestone(wordId: Int, milestone: SpacedRepetitionMilestoneEnum?) { + let index = words.firstIndex(where:{$0.id == wordId}) ?? nil + if index != nil { + words[index!].nextSpacedRepetitionMilestone = milestone + } + } + var words: [Word] = [] var settings: Settings diff --git a/WordAX/WordAXModelView.swift b/WordAX/WordAXModelView.swift index c2ac620..68ab606 100644 --- a/WordAX/WordAXModelView.swift +++ b/WordAX/WordAXModelView.swift @@ -45,6 +45,10 @@ class WordAXModelView: ObservableObject { // otherwise show nothing return nil } + + public func setSpacedRepetitionMilestone(wordId: Int, milestone: WordAX.SpacedRepetitionMilestoneEnum?) { + model.setSpacedRepetitionMilestone(wordId: wordId, milestone: milestone) + } } diff --git a/WordAX/WordView.swift b/WordAX/WordView.swift index de7dbf4..6b91ce7 100644 --- a/WordAX/WordView.swift +++ b/WordAX/WordView.swift @@ -10,7 +10,7 @@ import UIKit struct WordView: View { var word: WordAX.Word - @State var showDescription: Bool = false + @Binding var showDescription: Bool @EnvironmentObject var model: WordAXModelView @Environment(\.colorScheme) var colorScheme @@ -19,7 +19,6 @@ struct WordView: View { let wordText = Text(word.name) .font(.title) .bold() - VStack { if word.shown && word.lastSeenOn != nil { Text(model.getDateFormatter().string(from: word.lastSeenOn!)) @@ -46,6 +45,7 @@ struct WordView: View { } #Preview { - WordView(word: WordAXModelView().getWordToDisplay()!) + @State var showDescription = false + return WordView(word: WordAXModelView().getWordToDisplay()!, showDescription: $showDescription) .environmentObject(WordAXModelView()) } From 0ffb96cf9cc1a471f853db446af193a37023bdb2 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Sun, 25 Feb 2024 17:34:12 +0100 Subject: [PATCH 08/15] Make the app more stable --- WordAX/AnkiView.swift | 14 ++++----- WordAX/NextRepetitionButtonView.swift | 7 +++-- WordAX/WordAX.swift | 17 +++++++++-- WordAX/WordAXModelView.swift | 44 ++++++++++++++++++--------- WordAX/WordView.swift | 3 +- 5 files changed, 58 insertions(+), 27 deletions(-) diff --git a/WordAX/AnkiView.swift b/WordAX/AnkiView.swift index 88041ce..0704837 100644 --- a/WordAX/AnkiView.swift +++ b/WordAX/AnkiView.swift @@ -9,7 +9,7 @@ import SwiftUI struct AnkiView: View { @EnvironmentObject var model: WordAXModelView - @State var showDescription = true + @State var showDescription = false var word: WordAX.Word? { model.getWordToDisplay() } @@ -18,13 +18,13 @@ struct AnkiView: View { VStack { WordView(word: word!, showDescription: $showDescription) if showDescription { - Text("How did you do?") - .font(.subheadline) - .foregroundStyle(.gray) +// Text("How did you do?") +// .font(.subheadline) +// .foregroundStyle(.gray) HStack { - NextRepetitionButtonView(buttonText: "Poor", nextMilestone: word!.nextSpacedRepetitionMilestone, wordId: word!.id) - NextRepetitionButtonView(buttonText: "Good", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone), wordId: word!.id) - NextRepetitionButtonView(buttonText: "Excellent", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone)), wordId: word!.id) + NextRepetitionButtonView(buttonText: "Easy", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone)), wordId: word!.id, showDescription: $showDescription) + NextRepetitionButtonView(buttonText: "Medium", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone), wordId: word!.id, showDescription: $showDescription) + NextRepetitionButtonView(buttonText: "Hard/Wrong", nextMilestone: word!.nextSpacedRepetitionMilestone, wordId: word!.id, showDescription: $showDescription) } .padding(.bottom) } diff --git a/WordAX/NextRepetitionButtonView.swift b/WordAX/NextRepetitionButtonView.swift index a86f307..05f4c5b 100644 --- a/WordAX/NextRepetitionButtonView.swift +++ b/WordAX/NextRepetitionButtonView.swift @@ -11,11 +11,13 @@ struct NextRepetitionButtonView: View { let buttonText: String let nextMilestone: WordAX.SpacedRepetitionMilestoneEnum? let wordId: Int + @Binding var showDescription: Bool @EnvironmentObject var model: WordAXModelView @Environment(\.colorScheme) var colorScheme var body: some View { Button(action: { - model.setSpacedRepetitionMilestone(wordId: wordId, milestone: nextMilestone) + model.ankiButtonClicked(wordId: wordId, milestone: nextMilestone) + self.showDescription = false }) { Text(buttonText) .padding() @@ -34,6 +36,7 @@ extension ShapeStyle where Self == Color { } #Preview { - NextRepetitionButtonView(buttonText: "Excellent", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, wordId: 0) + @State var showDescription = false + return NextRepetitionButtonView(buttonText: "Excellent", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, wordId: 0, showDescription: $showDescription) .environmentObject(WordAXModelView()) } diff --git a/WordAX/WordAX.swift b/WordAX/WordAX.swift index 2d3506d..2963456 100644 --- a/WordAX/WordAX.swift +++ b/WordAX/WordAX.swift @@ -8,13 +8,14 @@ import Foundation struct WordAX { - struct Word: Identifiable { + struct Word: Identifiable, Hashable { var id: Int var name: String var description: String var shown: Bool var nextSpacedRepetitionMilestone: SpacedRepetitionMilestoneEnum? var lastSeenOn: Date? + var shownCount: Int = 0 } enum FrequencyEnum: Int { case Daily = 1 @@ -71,16 +72,28 @@ struct WordAX { let index = words.firstIndex(where:{$0.id == wordId}) ?? nil if index != nil { words[index!].nextSpacedRepetitionMilestone = milestone + if !words[index!].shown { + words[index!].shown = true + } + words[index!].lastSeenOn = Date() } } + public mutating func wordShown(wordId: Int) { + let index = words.firstIndex(where:{$0.id == wordId}) ?? nil + if index != nil { + words[index!].shownCount += 1 + } + + } + var words: [Word] = [] var settings: Settings init() { self.words = [] let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "dd/mm/YYYY" + dateFormatter.dateFormat = "dd/MM/YYYY" self.settings = Settings(dateFormatter: dateFormatter) self.words.append(Word(id: 0, name: "Magnificent", description: "When something is awesome. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.", shown: false)) self.words.append(Word(id: 1, name: "Mesmerising", description: "When something is beautiful", shown: false)) diff --git a/WordAX/WordAXModelView.swift b/WordAX/WordAXModelView.swift index 68ab606..b74eb5c 100644 --- a/WordAX/WordAXModelView.swift +++ b/WordAX/WordAXModelView.swift @@ -22,32 +22,36 @@ class WordAXModelView: ObservableObject { let words = model.words if words.count > 0 { + let notShownWords = words.filter({!$0.shown}) + if notShownWords.count == 0 { + return nil + } // if today is the date they're supposed to be shown - - let displayToday = words.filter({ $0.lastSeenOn != nil && $0.lastSeenOn!.addSpacedRepetitionMilestone(milestone: $0.nextSpacedRepetitionMilestone!).isAfterTodayOrToday()}) + let displayToday = words.filter({ $0.lastSeenOn != nil && $0.lastSeenOn!.addSpacedRepetitionMilestone(milestone: $0.nextSpacedRepetitionMilestone!).isBeforeTodayOrToday()}) if displayToday.count > 0 { return displayToday.first! } // first word ever shown - let shownWords = words.filter({ $0.shown }) - if shownWords.count == 0 { - return words.first! - } +// let shownWords = words.filter({ $0.shown }) +// if shownWords.count == 0 { + return notShownWords.sorted(by: {$0.id < $1.id}).first +// } // if today is the day to show a new word - let settings = model.settings - if shownWords.count == 0 || - settings.lastShownNew == nil || - settings.lastShownNew!.addFrequency(frequency: settings.frequency).isAfterToday() { - return words.first! - } +// let settings = model.settings +// if shownWords.count == 0 || +// settings.lastShownNew == nil || +// settings.lastShownNew!.addFrequency(frequency: settings.frequency).isAfterToday() { +// return words.first! +// } } // otherwise show nothing return nil } - public func setSpacedRepetitionMilestone(wordId: Int, milestone: WordAX.SpacedRepetitionMilestoneEnum?) { + public func ankiButtonClicked(wordId: Int, milestone: WordAX.SpacedRepetitionMilestoneEnum?) { model.setSpacedRepetitionMilestone(wordId: wordId, milestone: milestone) + model.wordShown(wordId: wordId) } } @@ -72,6 +76,12 @@ extension Date { return selfDate.year! > paramDate.year! || selfDate.month! > paramDate.month! || selfDate.day! > paramDate.day! } + func isBefore(_ date: Date) -> Bool { + let selfDate = getOnlyDate(date: self) + let paramDate = getOnlyDate(date: date) + return selfDate.year! < paramDate.year! || selfDate.month! < paramDate.month! || selfDate.day! < paramDate.day! + } + func addFrequency(frequency: WordAX.FrequencyEnum) -> Date { self.addingTimeInterval(TimeInterval(frequency.rawValue * 24 * 60 * 60)) } @@ -84,7 +94,11 @@ extension Date { self.isAfter(Date()) } - func isAfterTodayOrToday() -> Bool { - self.isAfterToday() || self.isToday() + func isBeforeToday() -> Bool { + self.isBefore(Date()) + } + + func isBeforeTodayOrToday() -> Bool { + self.isBeforeToday() || self.isToday() } } diff --git a/WordAX/WordView.swift b/WordAX/WordView.swift index 6b91ce7..2146386 100644 --- a/WordAX/WordView.swift +++ b/WordAX/WordView.swift @@ -21,7 +21,8 @@ struct WordView: View { .bold() VStack { if word.shown && word.lastSeenOn != nil { - Text(model.getDateFormatter().string(from: word.lastSeenOn!)) + Text("Last seen: " + model.getDateFormatter().string(from: word.lastSeenOn!)) + .font(.subheadline) } if showDescription { wordText From bfe46bb6ba33fe36bcbe96f57da1a1459419b0ca Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Sun, 25 Feb 2024 17:41:53 +0100 Subject: [PATCH 09/15] Quick fix (last version wasn't stable) --- WordAX/WordAXModelView.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/WordAX/WordAXModelView.swift b/WordAX/WordAXModelView.swift index b74eb5c..1622ae2 100644 --- a/WordAX/WordAXModelView.swift +++ b/WordAX/WordAXModelView.swift @@ -27,12 +27,12 @@ class WordAXModelView: ObservableObject { return nil } // if today is the date they're supposed to be shown - let displayToday = words.filter({ $0.lastSeenOn != nil && $0.lastSeenOn!.addSpacedRepetitionMilestone(milestone: $0.nextSpacedRepetitionMilestone!).isBeforeTodayOrToday()}) + + let displayToday = words.filter({ $0.lastSeenOn != nil && $0.lastSeenOn!.addSpacedRepetitionMilestone(milestone: $0.nextSpacedRepetitionMilestone).isBeforeTodayOrToday()}) if displayToday.count > 0 { return displayToday.first! } - // first word ever shown // let shownWords = words.filter({ $0.shown }) // if shownWords.count == 0 { return notShownWords.sorted(by: {$0.id < $1.id}).first @@ -86,8 +86,11 @@ extension Date { self.addingTimeInterval(TimeInterval(frequency.rawValue * 24 * 60 * 60)) } - func addSpacedRepetitionMilestone(milestone: WordAX.SpacedRepetitionMilestoneEnum) -> Date { - self.addingTimeInterval(TimeInterval(milestone.rawValue * 24 * 60 * 60)) + func addSpacedRepetitionMilestone(milestone: WordAX.SpacedRepetitionMilestoneEnum?) -> Date { + if milestone == nil { + return self + } + return self.addingTimeInterval(TimeInterval(milestone!.rawValue * 24 * 60 * 60)) } func isAfterToday() -> Bool { From 405e1179442a12cc680301d797ae4b0b4dfc2b5a Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Sun, 25 Feb 2024 17:45:36 +0100 Subject: [PATCH 10/15] Introduced WordListView --- WordAX.xcodeproj/project.pbxproj | 4 ++++ WordAX/MainView.swift | 6 ++++++ WordAX/WordListView.swift | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 WordAX/WordListView.swift diff --git a/WordAX.xcodeproj/project.pbxproj b/WordAX.xcodeproj/project.pbxproj index 75a78d0..ab1d0e8 100644 --- a/WordAX.xcodeproj/project.pbxproj +++ b/WordAX.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 6C8185042B88CA210033CF46 /* AnkiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185032B88CA210033CF46 /* AnkiView.swift */; }; 6C8185062B8A537F0033CF46 /* WordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185052B8A537F0033CF46 /* WordView.swift */; }; 6C8185082B8B523E0033CF46 /* NextRepetitionButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */; }; + 6C81850A2B8BA5740033CF46 /* WordListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185092B8BA5740033CF46 /* WordListView.swift */; }; 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439512B83541D004C3543 /* WordAXApp.swift */; }; 6CF439542B83541D004C3543 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439532B83541D004C3543 /* MainView.swift */; }; 6CF439562B83541E004C3543 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439552B83541E004C3543 /* Assets.xcassets */; }; @@ -26,6 +27,7 @@ 6C8185032B88CA210033CF46 /* AnkiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnkiView.swift; sourceTree = ""; }; 6C8185052B8A537F0033CF46 /* WordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordView.swift; sourceTree = ""; }; 6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextRepetitionButtonView.swift; sourceTree = ""; }; + 6C8185092B8BA5740033CF46 /* WordListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordListView.swift; sourceTree = ""; }; 6CF4394E2B83541D004C3543 /* WordAX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WordAX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6CF439512B83541D004C3543 /* WordAXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAXApp.swift; sourceTree = ""; }; 6CF439532B83541D004C3543 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -65,6 +67,7 @@ children = ( 6CF439512B83541D004C3543 /* WordAXApp.swift */, 6CF439532B83541D004C3543 /* MainView.swift */, + 6C8185092B8BA5740033CF46 /* WordListView.swift */, 6C8185012B88C9FB0033CF46 /* SettingsView.swift */, 6C8185032B88CA210033CF46 /* AnkiView.swift */, 6C8185052B8A537F0033CF46 /* WordView.swift */, @@ -159,6 +162,7 @@ 6CF439542B83541D004C3543 /* MainView.swift in Sources */, 6C8185082B8B523E0033CF46 /* NextRepetitionButtonView.swift in Sources */, 6C8185062B8A537F0033CF46 /* WordView.swift in Sources */, + 6C81850A2B8BA5740033CF46 /* WordListView.swift in Sources */, 6C8185002B88C9660033CF46 /* WordAXModelView.swift in Sources */, 6C8185042B88CA210033CF46 /* AnkiView.swift in Sources */, 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */, diff --git a/WordAX/MainView.swift b/WordAX/MainView.swift index f70e448..bf18e34 100644 --- a/WordAX/MainView.swift +++ b/WordAX/MainView.swift @@ -22,6 +22,12 @@ struct MainView: View { Image(systemName: "star") Text("Anki") } + WordListView() + .tag("Word List") + .tabItem { + Image(systemName: "list.bullet") + Text("Word List") + } SettingsView() .tag("Settings") .tabItem { diff --git a/WordAX/WordListView.swift b/WordAX/WordListView.swift new file mode 100644 index 0000000..6eab054 --- /dev/null +++ b/WordAX/WordListView.swift @@ -0,0 +1,18 @@ +// +// AllWordsView.swift +// WordAX +// +// Created by Oliver Hnát on 25.02.2024. +// + +import SwiftUI + +struct WordListView: View { + var body: some View { + Text("This is going to be a list of words") + } +} + +#Preview { + WordListView() +} From 286714b69a0c1b5238ee3b1ef0eea9e8decc65f7 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Sun, 25 Feb 2024 18:42:00 +0100 Subject: [PATCH 11/15] Create row for list of words --- WordAX.xcodeproj/project.pbxproj | 4 +++ WordAX/WordListRowView.swift | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 WordAX/WordListRowView.swift diff --git a/WordAX.xcodeproj/project.pbxproj b/WordAX.xcodeproj/project.pbxproj index ab1d0e8..a20fdab 100644 --- a/WordAX.xcodeproj/project.pbxproj +++ b/WordAX.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 6C8185062B8A537F0033CF46 /* WordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185052B8A537F0033CF46 /* WordView.swift */; }; 6C8185082B8B523E0033CF46 /* NextRepetitionButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */; }; 6C81850A2B8BA5740033CF46 /* WordListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8185092B8BA5740033CF46 /* WordListView.swift */; }; + 6C81850C2B8BA6BC0033CF46 /* WordListRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C81850B2B8BA6BC0033CF46 /* WordListRowView.swift */; }; 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439512B83541D004C3543 /* WordAXApp.swift */; }; 6CF439542B83541D004C3543 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439532B83541D004C3543 /* MainView.swift */; }; 6CF439562B83541E004C3543 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439552B83541E004C3543 /* Assets.xcassets */; }; @@ -28,6 +29,7 @@ 6C8185052B8A537F0033CF46 /* WordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordView.swift; sourceTree = ""; }; 6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextRepetitionButtonView.swift; sourceTree = ""; }; 6C8185092B8BA5740033CF46 /* WordListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordListView.swift; sourceTree = ""; }; + 6C81850B2B8BA6BC0033CF46 /* WordListRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordListRowView.swift; sourceTree = ""; }; 6CF4394E2B83541D004C3543 /* WordAX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WordAX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6CF439512B83541D004C3543 /* WordAXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAXApp.swift; sourceTree = ""; }; 6CF439532B83541D004C3543 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -68,6 +70,7 @@ 6CF439512B83541D004C3543 /* WordAXApp.swift */, 6CF439532B83541D004C3543 /* MainView.swift */, 6C8185092B8BA5740033CF46 /* WordListView.swift */, + 6C81850B2B8BA6BC0033CF46 /* WordListRowView.swift */, 6C8185012B88C9FB0033CF46 /* SettingsView.swift */, 6C8185032B88CA210033CF46 /* AnkiView.swift */, 6C8185052B8A537F0033CF46 /* WordView.swift */, @@ -167,6 +170,7 @@ 6C8185042B88CA210033CF46 /* AnkiView.swift in Sources */, 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */, 6C8184FE2B88C9580033CF46 /* WordAX.swift in Sources */, + 6C81850C2B8BA6BC0033CF46 /* WordListRowView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WordAX/WordListRowView.swift b/WordAX/WordListRowView.swift new file mode 100644 index 0000000..361f6d9 --- /dev/null +++ b/WordAX/WordListRowView.swift @@ -0,0 +1,57 @@ +// +// WordListRowView.swift +// WordAX +// +// Created by Oliver Hnát on 25.02.2024. +// + +import SwiftUI + +struct WordListRowView: View { + @EnvironmentObject var model: WordAXModelView + var word: WordAX.Word + @State var favorite = true + var body: some View { + HStack { + Group { + if favorite { + Image(systemName: "star") + } else { + ZStack { + Image(systemName: "star.fill") + .foregroundStyle(.yellow) + Image(systemName: "star") + .opacity(0.4) + } + } + } + .onTapGesture { + self.favorite = !self.favorite + } + .padding(.trailing) + VStack { + Text(word.name) + .bold() + .font(.system(size: 19)) + .multilineTextAlignment(.leading) + .frame(maxWidth: .infinity, alignment: .leading) + Text(word.description) + .multilineTextAlignment(.leading) + .frame(maxWidth: .infinity, alignment: .leading) + .lineLimit(1) + } + } + + } +} + +#Preview { + Group { + WordListRowView(word: WordAX.Word(id: 0, name: "Mesmerizing", description: "Some very long description like Lorem Ipsum which I'm to lazy to copy", shown: false, nextSpacedRepetitionMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, lastSeenOn: Date(), shownCount: 1)) + .environmentObject(WordAXModelView()) + WordListRowView(word: WordAX.Word(id: 0, name: "Mesmerizing", description: "Some very long description like Lorem Ipsum which I'm to lazy to copy", shown: false, nextSpacedRepetitionMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, lastSeenOn: Date(), shownCount: 1)) + .environmentObject(WordAXModelView()) + WordListRowView(word: WordAX.Word(id: 0, name: "Mesmerizing", description: "Some very long description like Lorem Ipsum which I'm to lazy to copy", shown: false, nextSpacedRepetitionMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, lastSeenOn: Date(), shownCount: 1)) + .environmentObject(WordAXModelView()) + } +} From b38827070d5d898520432d3a9bbb5b6bd0b0f846 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Sun, 25 Feb 2024 18:46:26 +0100 Subject: [PATCH 12/15] Implement WordListView --- WordAX/WordAXModelView.swift | 4 ++++ WordAX/WordListView.swift | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/WordAX/WordAXModelView.swift b/WordAX/WordAXModelView.swift index 1622ae2..aa3910b 100644 --- a/WordAX/WordAXModelView.swift +++ b/WordAX/WordAXModelView.swift @@ -14,6 +14,10 @@ class WordAXModelView: ObservableObject { model = WordAX() } + public var words: [Word] { + model.words + } + public func getDateFormatter() -> DateFormatter { model.settings.dateFormatter } diff --git a/WordAX/WordListView.swift b/WordAX/WordListView.swift index 6eab054..dfc7219 100644 --- a/WordAX/WordListView.swift +++ b/WordAX/WordListView.swift @@ -8,11 +8,25 @@ import SwiftUI struct WordListView: View { + @EnvironmentObject var model: WordAXModelView + @State var showDescription = true var body: some View { - Text("This is going to be a list of words") + NavigationSplitView { + List(model.words) { word in + NavigationLink { + WordView(word: word, showDescription: $showDescription) + } label: { + WordListRowView(word: word) + } + } + .navigationTitle("Word List") + } detail: { + Text("Select word to get details about") + } } } #Preview { WordListView() + .environmentObject(WordAXModelView()) } From 94772d6b481ac61f6769ff867752d74805267e22 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Mon, 26 Feb 2024 20:56:20 +0100 Subject: [PATCH 13/15] Fixed allignment issues --- WordAX/AnkiView.swift | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/WordAX/AnkiView.swift b/WordAX/AnkiView.swift index 0704837..43baf20 100644 --- a/WordAX/AnkiView.swift +++ b/WordAX/AnkiView.swift @@ -21,12 +21,14 @@ struct AnkiView: View { // Text("How did you do?") // .font(.subheadline) // .foregroundStyle(.gray) - HStack { - NextRepetitionButtonView(buttonText: "Easy", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone)), wordId: word!.id, showDescription: $showDescription) - NextRepetitionButtonView(buttonText: "Medium", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone), wordId: word!.id, showDescription: $showDescription) - NextRepetitionButtonView(buttonText: "Hard/Wrong", nextMilestone: word!.nextSpacedRepetitionMilestone, wordId: word!.id, showDescription: $showDescription) - } - .padding(.bottom) + HStack(alignment: .center) { + NextRepetitionButtonView(buttonText: "Novice", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone)), wordId: word!.id, showDescription: $showDescription) + // .padding(.leading) + NextRepetitionButtonView(buttonText: "Expert", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone), wordId: word!.id, showDescription: $showDescription) + NextRepetitionButtonView(buttonText: "Master", nextMilestone: word!.nextSpacedRepetitionMilestone, wordId: word!.id, showDescription: $showDescription) + // .padding(.trailing) + } + .padding([.bottom, .trailing, .leading]) } } } else { From c0c4afc94632eb3dc7017d59fc60a6a62ba977a7 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Fri, 5 Apr 2024 19:45:26 +0200 Subject: [PATCH 14/15] Update button size, add time that's added --- WordAX/AnkiView.swift | 45 ++++++++++++++++++++------- WordAX/NextRepetitionButtonView.swift | 40 +++++++++++++++--------- 2 files changed, 59 insertions(+), 26 deletions(-) diff --git a/WordAX/AnkiView.swift b/WordAX/AnkiView.swift index 43baf20..6eb269a 100644 --- a/WordAX/AnkiView.swift +++ b/WordAX/AnkiView.swift @@ -9,26 +9,47 @@ import SwiftUI struct AnkiView: View { @EnvironmentObject var model: WordAXModelView - @State var showDescription = false + @State var showDescription = true var word: WordAX.Word? { model.getWordToDisplay() } var body: some View { if word != nil { - VStack { - WordView(word: word!, showDescription: $showDescription) - if showDescription { -// Text("How did you do?") -// .font(.subheadline) -// .foregroundStyle(.gray) + GeometryReader { geometry in + VStack { + WordView(word: word!, showDescription: $showDescription) + if showDescription { + // Text("How did you do?") + // .font(.subheadline) + // .foregroundStyle(.gray) HStack(alignment: .center) { - NextRepetitionButtonView(buttonText: "Novice", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone)), wordId: word!.id, showDescription: $showDescription) - // .padding(.leading) - NextRepetitionButtonView(buttonText: "Expert", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone), wordId: word!.id, showDescription: $showDescription) - NextRepetitionButtonView(buttonText: "Master", nextMilestone: word!.nextSpacedRepetitionMilestone, wordId: word!.id, showDescription: $showDescription) - // .padding(.trailing) + NextRepetitionButtonView( + buttonText: "Easy", + nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone)), + wordId: word!.id, + width: geometry.size.width, + color: .green, + geometry: geometry, + showDescription: $showDescription) + NextRepetitionButtonView( + buttonText: "Normal", + nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone), + wordId: word!.id, + width:geometry.size.width, + color: .orange, + geometry: geometry, + showDescription: $showDescription) + NextRepetitionButtonView( + buttonText: "Hard", + nextMilestone: word!.nextSpacedRepetitionMilestone, + wordId: word!.id, + width: geometry.size.width, + color: .red, + geometry: geometry, + showDescription: $showDescription) } .padding([.bottom, .trailing, .leading]) + } } } } else { diff --git a/WordAX/NextRepetitionButtonView.swift b/WordAX/NextRepetitionButtonView.swift index 05f4c5b..54b8878 100644 --- a/WordAX/NextRepetitionButtonView.swift +++ b/WordAX/NextRepetitionButtonView.swift @@ -11,20 +11,32 @@ struct NextRepetitionButtonView: View { let buttonText: String let nextMilestone: WordAX.SpacedRepetitionMilestoneEnum? let wordId: Int + let width: CGFloat + let color: Color + let geometry: GeometryProxy + let newText: String = "1h" +// { colorScheme == .light ? .cyan : .darkCyan } @Binding var showDescription: Bool @EnvironmentObject var model: WordAXModelView @Environment(\.colorScheme) var colorScheme var body: some View { - Button(action: { - model.ankiButtonClicked(wordId: wordId, milestone: nextMilestone) - self.showDescription = false - }) { - Text(buttonText) - .padding() + Button(action: { + model.ankiButtonClicked(wordId: wordId, milestone: nextMilestone) + self.showDescription = false + }) { + VStack { + Text(buttonText) + Text(">" + newText) + .font(.footnote) + .bold() + } + .padding(.vertical, geometry.size.height / 80) .foregroundColor(colorScheme == .light ? .black : .white) - .background(colorScheme == .light ? .cyan : .darkCyan) - .clipShape(RoundedRectangle(cornerRadius: 50)) - } + .frame(maxWidth: width) + } + .background(color) + .buttonStyle(.plain) + .clipShape(RoundedRectangle(cornerRadius: 10)) } } @@ -35,8 +47,8 @@ extension ShapeStyle where Self == Color { } } -#Preview { - @State var showDescription = false - return NextRepetitionButtonView(buttonText: "Excellent", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, wordId: 0, showDescription: $showDescription) - .environmentObject(WordAXModelView()) -} +//#Preview { +// @State var showDescription = false +// return NextRepetitionButtonView(buttonText: "Excellent", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, wordId: 0, showDescription: $showDescription) +// .environmentObject(WordAXModelView()) +//} From 147c6715c34ba3118ece52ed3ea48b96a102591e Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Fri, 5 Apr 2024 19:49:43 +0200 Subject: [PATCH 15/15] Changed the button time --- WordAX/AnkiView.swift | 40 +++++++++++++++------------ WordAX/NextRepetitionButtonView.swift | 4 +-- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/WordAX/AnkiView.swift b/WordAX/AnkiView.swift index 6eb269a..f5f7011 100644 --- a/WordAX/AnkiView.swift +++ b/WordAX/AnkiView.swift @@ -23,6 +23,26 @@ struct AnkiView: View { // .font(.subheadline) // .foregroundStyle(.gray) HStack(alignment: .center) { + NextRepetitionButtonView( + buttonText: "Wrong", + nextMilestone: word!.nextSpacedRepetitionMilestone, + wordId: word!.id, + width: geometry.size.width, + color: .red, + geometry: geometry, + timeText: "1m", + showDescription: $showDescription + ) + NextRepetitionButtonView( + buttonText: "Correct", + nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone), + wordId: word!.id, + width:geometry.size.width, + color: .orange, + geometry: geometry, + timeText: "10m", + showDescription: $showDescription + ) NextRepetitionButtonView( buttonText: "Easy", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone)), @@ -30,23 +50,9 @@ struct AnkiView: View { width: geometry.size.width, color: .green, geometry: geometry, - showDescription: $showDescription) - NextRepetitionButtonView( - buttonText: "Normal", - nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: word!.nextSpacedRepetitionMilestone), - wordId: word!.id, - width:geometry.size.width, - color: .orange, - geometry: geometry, - showDescription: $showDescription) - NextRepetitionButtonView( - buttonText: "Hard", - nextMilestone: word!.nextSpacedRepetitionMilestone, - wordId: word!.id, - width: geometry.size.width, - color: .red, - geometry: geometry, - showDescription: $showDescription) + timeText: "1h", + showDescription: $showDescription + ) } .padding([.bottom, .trailing, .leading]) } diff --git a/WordAX/NextRepetitionButtonView.swift b/WordAX/NextRepetitionButtonView.swift index 54b8878..c79475b 100644 --- a/WordAX/NextRepetitionButtonView.swift +++ b/WordAX/NextRepetitionButtonView.swift @@ -14,7 +14,7 @@ struct NextRepetitionButtonView: View { let width: CGFloat let color: Color let geometry: GeometryProxy - let newText: String = "1h" + let timeText: String // { colorScheme == .light ? .cyan : .darkCyan } @Binding var showDescription: Bool @EnvironmentObject var model: WordAXModelView @@ -26,7 +26,7 @@ struct NextRepetitionButtonView: View { }) { VStack { Text(buttonText) - Text(">" + newText) + Text(">" + timeText) .font(.footnote) .bold() }