Merge branch 'main' of github.com:olinpin/WordAX
This commit is contained in:
		| @@ -7,16 +7,32 @@ | |||||||
| 	objects = { | 	objects = { | ||||||
|  |  | ||||||
| /* Begin PBXBuildFile section */ | /* 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 */; }; | 		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 */; }; | 		6CF439562B83541E004C3543 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439552B83541E004C3543 /* Assets.xcassets */; }; | ||||||
| 		6CF439592B83541E004C3543 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439582B83541E004C3543 /* Preview Assets.xcassets */; }; | 		6CF439592B83541E004C3543 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439582B83541E004C3543 /* Preview Assets.xcassets */; }; | ||||||
| /* End PBXBuildFile section */ | /* End PBXBuildFile section */ | ||||||
|  |  | ||||||
| /* Begin PBXFileReference 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; }; | 		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>"; }; | 		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>"; }; | 		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>"; }; | 		6CF439582B83541E004C3543 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; }; | ||||||
| /* End PBXFileReference section */ | /* End PBXFileReference section */ | ||||||
| @@ -52,7 +68,15 @@ | |||||||
| 			isa = PBXGroup; | 			isa = PBXGroup; | ||||||
| 			children = ( | 			children = ( | ||||||
| 				6CF439512B83541D004C3543 /* WordAXApp.swift */, | 				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 */, | 				6CF439552B83541E004C3543 /* Assets.xcassets */, | ||||||
| 				6CF439572B83541E004C3543 /* Preview Content */, | 				6CF439572B83541E004C3543 /* Preview Content */, | ||||||
| 			); | 			); | ||||||
| @@ -137,8 +161,16 @@ | |||||||
| 			isa = PBXSourcesBuildPhase; | 			isa = PBXSourcesBuildPhase; | ||||||
| 			buildActionMask = 2147483647; | 			buildActionMask = 2147483647; | ||||||
| 			files = ( | 			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 */, | 				6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */, | ||||||
|  | 				6C8184FE2B88C9580033CF46 /* WordAX.swift in Sources */, | ||||||
|  | 				6C81850C2B8BA6BC0033CF46 /* WordListRowView.swift in Sources */, | ||||||
| 			); | 			); | ||||||
| 			runOnlyForDeploymentPostprocessing = 0; | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
| 		}; | 		}; | ||||||
|   | |||||||
							
								
								
									
										77
									
								
								WordAX.xcodeproj/xcshareddata/xcschemes/WordAX.xcscheme
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								WordAX.xcodeproj/xcshareddata/xcschemes/WordAX.xcscheme
									
									
									
									
									
										Normal 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> | ||||||
| @@ -10,5 +10,13 @@ | |||||||
| 			<integer>0</integer> | 			<integer>0</integer> | ||||||
| 		</dict> | 		</dict> | ||||||
| 	</dict> | 	</dict> | ||||||
|  | 	<key>SuppressBuildableAutocreation</key> | ||||||
|  | 	<dict> | ||||||
|  | 		<key>6CF4394D2B83541D004C3543</key> | ||||||
|  | 		<dict> | ||||||
|  | 			<key>primary</key> | ||||||
|  | 			<true/> | ||||||
|  | 		</dict> | ||||||
|  | 	</dict> | ||||||
| </dict> | </dict> | ||||||
| </plist> | </plist> | ||||||
|   | |||||||
							
								
								
									
										70
									
								
								WordAX/AnkiView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								WordAX/AnkiView.swift
									
									
									
									
									
										Normal 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()) | ||||||
|  | } | ||||||
| @@ -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
									
								
							
							
						
						
									
										48
									
								
								WordAX/MainView.swift
									
									
									
									
									
										Normal 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()) | ||||||
|  | } | ||||||
							
								
								
									
										54
									
								
								WordAX/NextRepetitionButtonView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								WordAX/NextRepetitionButtonView.swift
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										19
									
								
								WordAX/SettingsView.swift
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										102
									
								
								WordAX/WordAX.swift
									
									
									
									
									
										Normal 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)) | ||||||
|  |     } | ||||||
|  |      | ||||||
|  | } | ||||||
| @@ -9,9 +9,11 @@ import SwiftUI | |||||||
|  |  | ||||||
| @main | @main | ||||||
| struct WordAXApp: App { | struct WordAXApp: App { | ||||||
|  |     @StateObject var model = WordAXModelView() | ||||||
|     var body: some Scene { |     var body: some Scene { | ||||||
|         WindowGroup { |         WindowGroup { | ||||||
|             ContentView() |             MainView() | ||||||
|  |                 .environmentObject(model) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								WordAX/WordAXModel.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								WordAX/WordAXModel.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | // | ||||||
|  | //  WordAXModel.swift | ||||||
|  | //  WordAX | ||||||
|  | // | ||||||
|  | //  Created by Oliver Hnát on 23.02.2024. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | import Foundation | ||||||
							
								
								
									
										111
									
								
								WordAX/WordAXModelView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								WordAX/WordAXModelView.swift
									
									
									
									
									
										Normal 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() | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										57
									
								
								WordAX/WordListRowView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								WordAX/WordListRowView.swift
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										32
									
								
								WordAX/WordListView.swift
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										52
									
								
								WordAX/WordView.swift
									
									
									
									
									
										Normal 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()) | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user