diff --git a/WordAX.xcodeproj/project.pbxproj b/WordAX.xcodeproj/project.pbxproj index e65cbac..a20fdab 100644 --- a/WordAX.xcodeproj/project.pbxproj +++ b/WordAX.xcodeproj/project.pbxproj @@ -7,16 +7,32 @@ 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 */; }; + 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 /* 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 = ""; }; + 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 /* 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 +68,15 @@ isa = PBXGroup; children = ( 6CF439512B83541D004C3543 /* WordAXApp.swift */, - 6CF439532B83541D004C3543 /* ContentView.swift */, + 6CF439532B83541D004C3543 /* MainView.swift */, + 6C8185092B8BA5740033CF46 /* WordListView.swift */, + 6C81850B2B8BA6BC0033CF46 /* WordListRowView.swift */, + 6C8185012B88C9FB0033CF46 /* SettingsView.swift */, + 6C8185032B88CA210033CF46 /* AnkiView.swift */, + 6C8185052B8A537F0033CF46 /* WordView.swift */, + 6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */, + 6C8184FD2B88C9580033CF46 /* WordAX.swift */, + 6C8184FF2B88C9660033CF46 /* WordAXModelView.swift */, 6CF439552B83541E004C3543 /* Assets.xcassets */, 6CF439572B83541E004C3543 /* Preview Content */, ); @@ -137,8 +161,16 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6CF439542B83541D004C3543 /* ContentView.swift in Sources */, + 6C8185022B88C9FB0033CF46 /* SettingsView.swift in Sources */, + 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 */, + 6C8184FE2B88C9580033CF46 /* WordAX.swift in Sources */, + 6C81850C2B8BA6BC0033CF46 /* WordListRowView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 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/AnkiView.swift b/WordAX/AnkiView.swift new file mode 100644 index 0000000..f5f7011 --- /dev/null +++ b/WordAX/AnkiView.swift @@ -0,0 +1,70 @@ +// +// AnkiView.swift +// WordAX +// +// Created by Oliver Hnát on 23.02.2024. +// + +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 { + 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: "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)), + wordId: word!.id, + width: geometry.size.width, + color: .green, + geometry: geometry, + timeText: "1h", + showDescription: $showDescription + ) + } + .padding([.bottom, .trailing, .leading]) + } + } + } + } else { + Text("There is no word to display, come back later") + } + } +} + +#Preview { + AnkiView() + .environmentObject(WordAXModelView()) +} 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..bf18e34 --- /dev/null +++ b/WordAX/MainView.swift @@ -0,0 +1,48 @@ +// +// 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") + } + WordListView() + .tag("Word List") + .tabItem { + Image(systemName: "list.bullet") + Text("Word List") + } + SettingsView() + .tag("Settings") + .tabItem { + Image(systemName: "gear") + Text("Settings") + } + } + } + + } + + } +} + +#Preview { + MainView() + .environmentObject(WordAXModelView()) +} diff --git a/WordAX/NextRepetitionButtonView.swift b/WordAX/NextRepetitionButtonView.swift new file mode 100644 index 0000000..c79475b --- /dev/null +++ b/WordAX/NextRepetitionButtonView.swift @@ -0,0 +1,54 @@ +// +// 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 + let width: CGFloat + let color: Color + let geometry: GeometryProxy + let timeText: String +// { 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 + }) { + VStack { + Text(buttonText) + Text(">" + timeText) + .font(.footnote) + .bold() + } + .padding(.vertical, geometry.size.height / 80) + .foregroundColor(colorScheme == .light ? .black : .white) + .frame(maxWidth: width) + } + .background(color) + .buttonStyle(.plain) + .clipShape(RoundedRectangle(cornerRadius: 10)) + } +} + +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 { +// @State var showDescription = false +// return NextRepetitionButtonView(buttonText: "Excellent", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, wordId: 0, showDescription: $showDescription) +// .environmentObject(WordAXModelView()) +//} diff --git a/WordAX/SettingsView.swift b/WordAX/SettingsView.swift new file mode 100644 index 0000000..a2f82f3 --- /dev/null +++ b/WordAX/SettingsView.swift @@ -0,0 +1,19 @@ +// +// 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() + .environmentObject(WordAXModelView()) +} diff --git a/WordAX/WordAX.swift b/WordAX/WordAX.swift new file mode 100644 index 0000000..2963456 --- /dev/null +++ b/WordAX/WordAX.swift @@ -0,0 +1,102 @@ +// +// WordAX.swift +// WordAX +// +// Created by Oliver Hnát on 23.02.2024. +// + +import Foundation + +struct WordAX { + 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 + 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 } + } + + static func getNext(milestone: SpacedRepetitionMilestoneEnum?) -> SpacedRepetitionMilestoneEnum? { + if milestone == nil { + return SpacedRepetitionMilestoneEnum.OneDay + } + let sorted = WordAX.SpacedRepetitionMilestoneEnum.allCasesSorted + let milestoneIndex = sorted.firstIndex(where: {$0.rawValue == milestone!.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 + } + + 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 + if current + 1 < SpacedRepetitionMilestoneEnum.allCases.count && index != nil { + words[index!].nextSpacedRepetitionMilestone = SpacedRepetitionMilestoneEnum.allCasesSorted[current + 1] + } else if index != nil { + words[index!].nextSpacedRepetitionMilestone = nil + } + } + } + + public mutating func setSpacedRepetitionMilestone(wordId: Int, milestone: SpacedRepetitionMilestoneEnum?) { + 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" + 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/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/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..aa3910b --- /dev/null +++ b/WordAX/WordAXModelView.swift @@ -0,0 +1,111 @@ +// +// WordAXModelView.swift +// WordAX +// +// Created by Oliver Hnát on 23.02.2024. +// + +import Foundation + +class WordAXModelView: ObservableObject { + @Published private var model: WordAX + typealias Word = WordAX.Word + init() { + model = WordAX() + } + + public var words: [Word] { + model.words + } + + public func getDateFormatter() -> DateFormatter { + model.settings.dateFormatter + } + + public func getWordToDisplay() -> Word? { + 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).isBeforeTodayOrToday()}) + if displayToday.count > 0 { + return displayToday.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! +// } + } + // otherwise show nothing + return nil + } + + public func ankiButtonClicked(wordId: Int, milestone: WordAX.SpacedRepetitionMilestoneEnum?) { + model.setSpacedRepetitionMilestone(wordId: wordId, milestone: milestone) + model.wordShown(wordId: wordId) + } +} + + +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 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)) + } + + func addSpacedRepetitionMilestone(milestone: WordAX.SpacedRepetitionMilestoneEnum?) -> Date { + if milestone == nil { + return self + } + return self.addingTimeInterval(TimeInterval(milestone!.rawValue * 24 * 60 * 60)) + } + + func isAfterToday() -> Bool { + self.isAfter(Date()) + } + + func isBeforeToday() -> Bool { + self.isBefore(Date()) + } + + func isBeforeTodayOrToday() -> Bool { + self.isBeforeToday() || self.isToday() + } +} 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()) + } +} diff --git a/WordAX/WordListView.swift b/WordAX/WordListView.swift new file mode 100644 index 0000000..dfc7219 --- /dev/null +++ b/WordAX/WordListView.swift @@ -0,0 +1,32 @@ +// +// AllWordsView.swift +// WordAX +// +// Created by Oliver Hnát on 25.02.2024. +// + +import SwiftUI + +struct WordListView: View { + @EnvironmentObject var model: WordAXModelView + @State var showDescription = true + var body: some View { + 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()) +} diff --git a/WordAX/WordView.swift b/WordAX/WordView.swift new file mode 100644 index 0000000..2146386 --- /dev/null +++ b/WordAX/WordView.swift @@ -0,0 +1,52 @@ +// +// WordView.swift +// WordAX +// +// Created by Oliver Hnát on 24.02.2024. +// + +import SwiftUI +import UIKit + +struct WordView: View { + var word: WordAX.Word + @Binding var showDescription: Bool + @EnvironmentObject var model: WordAXModelView + @Environment(\.colorScheme) var colorScheme + + + var body: some View { + let wordText = Text(word.name) + .font(.title) + .bold() + VStack { + if word.shown && word.lastSeenOn != nil { + Text("Last seen: " + model.getDateFormatter().string(from: word.lastSeenOn!)) + .font(.subheadline) + } + 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]) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .contentShape(Rectangle()) + .onTapGesture { + self.showDescription = true + } + } +} + +#Preview { + @State var showDescription = false + return WordView(word: WordAXModelView().getWordToDisplay()!, showDescription: $showDescription) + .environmentObject(WordAXModelView()) +}