Merge branch 'main' of github.com:olinpin/WordAX

This commit is contained in:
2024-04-05 23:26:49 +00:00
15 changed files with 677 additions and 29 deletions

View File

@@ -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 = "<group>"; };
6C8184FF2B88C9660033CF46 /* WordAXModelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAXModelView.swift; sourceTree = "<group>"; };
6C8185012B88C9FB0033CF46 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
6C8185032B88CA210033CF46 /* AnkiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnkiView.swift; sourceTree = "<group>"; };
6C8185052B8A537F0033CF46 /* WordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordView.swift; sourceTree = "<group>"; };
6C8185072B8B523D0033CF46 /* NextRepetitionButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextRepetitionButtonView.swift; sourceTree = "<group>"; };
6C8185092B8BA5740033CF46 /* WordListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordListView.swift; sourceTree = "<group>"; };
6C81850B2B8BA6BC0033CF46 /* WordListRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordListRowView.swift; sourceTree = "<group>"; };
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 = "<group>"; };
6CF439532B83541D004C3543 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
6CF439532B83541D004C3543 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
6CF439552B83541E004C3543 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6CF439582B83541E004C3543 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
/* 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;
};

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6CF4394D2B83541D004C3543"
BuildableName = "WordAX.app"
BlueprintName = "WordAX"
ReferencedContainer = "container:WordAX.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6CF4394D2B83541D004C3543"
BuildableName = "WordAX.app"
BlueprintName = "WordAX"
ReferencedContainer = "container:WordAX.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6CF4394D2B83541D004C3543"
BuildableName = "WordAX.app"
BlueprintName = "WordAX"
ReferencedContainer = "container:WordAX.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -10,5 +10,13 @@
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>6CF4394D2B83541D004C3543</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

70
WordAX/AnkiView.swift Normal file
View File

@@ -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())
}

View File

@@ -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()
}

48
WordAX/MainView.swift Normal file
View File

@@ -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())
}

View File

@@ -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())
//}

19
WordAX/SettingsView.swift Normal file
View File

@@ -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())
}

102
WordAX/WordAX.swift Normal file
View File

@@ -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))
}
}

View File

@@ -9,9 +9,11 @@ import SwiftUI
@main
struct WordAXApp: App {
@StateObject var model = WordAXModelView()
var body: some Scene {
WindowGroup {
ContentView()
MainView()
.environmentObject(model)
}
}
}

8
WordAX/WordAXModel.swift Normal file
View File

@@ -0,0 +1,8 @@
//
// WordAXModel.swift
// WordAX
//
// Created by Oliver Hnát on 23.02.2024.
//
import Foundation

View File

@@ -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()
}
}

View File

@@ -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())
}
}

32
WordAX/WordListView.swift Normal file
View File

@@ -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())
}

52
WordAX/WordView.swift Normal file
View File

@@ -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())
}