Add dictionary view and change how phrase lookup works
This commit is contained in:
		| @@ -42,6 +42,7 @@ | ||||
| 		7E943A2D273211C300E7DDF4 /* Toki_Trainer.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 7E943A2B273211C300E7DDF4 /* Toki_Trainer.xcdatamodeld */; }; | ||||
| 		7EBAE6AA273D65FD00BCFA09 /* toki-lessons.json in Resources */ = {isa = PBXBuildFile; fileRef = 7EBAE6A9273D65FD00BCFA09 /* toki-lessons.json */; }; | ||||
| 		7EF546162737B8FB00537AE6 /* FlashCardResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EF546152737B8FA00537AE6 /* FlashCardResultsView.swift */; }; | ||||
| 		E1D79AE328EC396200A104BF /* DictionaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D79AE228EC396200A104BF /* DictionaryView.swift */; }; | ||||
| /* End PBXBuildFile section */ | ||||
|  | ||||
| /* Begin PBXContainerItemProxy section */ | ||||
| @@ -100,6 +101,7 @@ | ||||
| 		7E943A2C273211C300E7DDF4 /* Toki_Trainer.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Toki_Trainer.xcdatamodel; sourceTree = "<group>"; }; | ||||
| 		7EBAE6A9273D65FD00BCFA09 /* toki-lessons.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "toki-lessons.json"; sourceTree = "<group>"; }; | ||||
| 		7EF546152737B8FA00537AE6 /* FlashCardResultsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardResultsView.swift; sourceTree = "<group>"; }; | ||||
| 		E1D79AE228EC396200A104BF /* DictionaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryView.swift; sourceTree = "<group>"; }; | ||||
| /* End PBXFileReference section */ | ||||
|  | ||||
| /* Begin PBXFrameworksBuildPhase section */ | ||||
| @@ -143,6 +145,7 @@ | ||||
| 				7EF546152737B8FA00537AE6 /* FlashCardResultsView.swift */, | ||||
| 				7E716B4127398CDF009E2CF6 /* FlashCardLessonsView.swift */, | ||||
| 				7E716B452739B968009E2CF6 /* FlashCardLessonResultsView.swift */, | ||||
| 				E1D79AE228EC396200A104BF /* DictionaryView.swift */, | ||||
| 			); | ||||
| 			path = Views; | ||||
| 			sourceTree = "<group>"; | ||||
| @@ -358,6 +361,7 @@ | ||||
| 				7E716B4427398D3D009E2CF6 /* FlashCardLessonsViewModel.swift in Sources */, | ||||
| 				7E2811192733027F0063DC78 /* TokiPartOfSpeech.swift in Sources */, | ||||
| 				7E449780275AA0620016B6DC /* Toki_Trainer_Widgets.intentdefinition in Sources */, | ||||
| 				E1D79AE328EC396200A104BF /* DictionaryView.swift in Sources */, | ||||
| 				7E943A23273211C200E7DDF4 /* ContentView.swift in Sources */, | ||||
| 				7EF546162737B8FB00537AE6 /* FlashCardResultsView.swift in Sources */, | ||||
| 				7E716B4227398CDF009E2CF6 /* FlashCardLessonsView.swift in Sources */, | ||||
|   | ||||
| @@ -17,6 +17,8 @@ class TokiDictionaryViewModel: ObservableObject { | ||||
|     @Published var dictionary: [TokiDictEntry] = [] | ||||
|     @Published var partsOfSpeech: [TokiPartOfSpeech] = [] | ||||
|      | ||||
|     @Published var translatedDictionary: [TokiSubWordListEntry] = [] | ||||
|      | ||||
|     init() { | ||||
|         if let safeDictionary = jsonLoader.loadDictionary() { | ||||
|             dictionary = safeDictionary | ||||
| @@ -30,17 +32,32 @@ class TokiDictionaryViewModel: ObservableObject { | ||||
|      | ||||
|     func filterDictionary(_ input: String) { | ||||
|         dictionary = [] | ||||
|         if(input.isEmpty) { | ||||
|             dictionary = fullDictionary | ||||
|         } else { | ||||
|          | ||||
|         for value in fullDictionary { | ||||
|             if value.word.hasPrefix(input) { | ||||
|                 dictionary.append(value) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     func translatePhrase(_ input: String) { | ||||
|         dictionary = [] | ||||
|         translatedDictionary = [] | ||||
|          | ||||
|         let capturePattern = #"(\w+)"# | ||||
|         let captures = self.searchStringForRegex(string: input, regex: capturePattern) | ||||
|         for capture in captures { | ||||
|                 print(capture) | ||||
|             let translatedWord = TokiSubWordListEntry(capture) | ||||
|             translatedDictionary.append(translatedWord) | ||||
|             for value in fullDictionary { | ||||
|                 if value.word == capture { | ||||
|                     dictionary.append(value) | ||||
|                     } | ||||
|                     translatedWord.subDictionary.removeAll() | ||||
|                     translatedWord.subDictionary.append(value) | ||||
|                     break | ||||
|                 } else if value.word.hasPrefix(capture) { | ||||
|                     dictionary.append(value) | ||||
|                     translatedWord.subDictionary.append(value) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -58,3 +75,12 @@ class TokiDictionaryViewModel: ObservableObject { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| class TokiSubWordListEntry: Identifiable { | ||||
|     let header: String | ||||
|     var subDictionary: [TokiDictEntry] = [] | ||||
|      | ||||
|     init(_ header: String) { | ||||
|         self.header = header | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -19,6 +19,11 @@ struct ContentView: View { | ||||
|      | ||||
|     var body: some View { | ||||
|         TabView { | ||||
|             DictionaryView() | ||||
|                 .tabItem { | ||||
|                     Image(systemName: "book") | ||||
|                     Text("Dictionary") | ||||
|                 } | ||||
|             TranslatorView() | ||||
|                 .tabItem { | ||||
|                     Image(systemName: "message") | ||||
| @@ -46,17 +51,103 @@ struct TranslatorView: View { | ||||
|     @ObservedObject var tokiDictViewModel = TokiDictionaryViewModel() | ||||
|     @State private var selectedPartOfSpeech: String? | ||||
|     @State private var tokiInput: String = "" | ||||
|     @State private var translateToTokiPona: Bool = false | ||||
|      | ||||
|     var body: some View { | ||||
|         VStack { | ||||
|             Button(action: changeTranslationDirection) { | ||||
|                 if translateToTokiPona == true { | ||||
|                     LanguageDirectionView(from: "English", to: "Toki Pona", fromColor: .blue, toColor: .cyan) | ||||
|                 } else { | ||||
|                     LanguageDirectionView(from: "Toki Pona", to: "English", fromColor: .cyan, toColor: .blue) | ||||
|                 } | ||||
|             } | ||||
|             TextField("Enter Toki Pona Word or Phrase", text: $tokiInput) | ||||
|                 .multilineTextAlignment(.center) | ||||
|                 .textInputAutocapitalization(.never) | ||||
|                 .disableAutocorrection(true) | ||||
|                 .padding(8) | ||||
|                 .onSubmit { | ||||
|                     tokiDictViewModel.filterDictionary(tokiInput) | ||||
|                     tokiDictViewModel.translatePhrase(tokiInput) | ||||
|                 } | ||||
|             if tokiInput.count == 0 { | ||||
|                 List(tokiDictViewModel.dictionary, id: \.word) { entry in | ||||
|                     TokiWordsListEntryView(entry: entry, selectedPartOfSpeech: $selectedPartOfSpeech) | ||||
|                 } | ||||
|                 //TokiWordsView(tokiDictViewModel: tokiDictViewModel, selectedPartOfSpeech: selectedPartOfSpeech, tokiInput: $tokiInput) | ||||
|             } else { | ||||
|                 List(tokiDictViewModel.translatedDictionary, id: \.header) { section in | ||||
|                     Section { | ||||
|                         ForEach(section.subDictionary, id: \.word) { entry in | ||||
|                             TokiWordsListEntryView(entry: entry, selectedPartOfSpeech: $selectedPartOfSpeech) | ||||
|                         } | ||||
|                     } header: { | ||||
|                         Text(section.header) | ||||
|                     } | ||||
|                 } | ||||
| //                ForEach(tokiDictViewModel.translatedDictionary) { entry in | ||||
| //                    TokiSectionedWordsView(tokiDictViewModel: tokiDictViewModel, tokiInput: $tokiInput) | ||||
| //                } | ||||
|             } | ||||
|         } | ||||
|         .onChange(of: tokiInput) { newValue in | ||||
|             tokiDictViewModel.translatePhrase(newValue) | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     func changeTranslationDirection() { | ||||
|         translateToTokiPona.toggle() | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct TokiSectionedWordsView: View { | ||||
|     @ObservedObject var tokiDictViewModel: TokiDictionaryViewModel | ||||
|     @Binding var tokiInput: String | ||||
|      | ||||
|     var body: some View { | ||||
|         Section(header: Text(tokiInput)) { | ||||
|             TokiWordsView(tokiDictViewModel: tokiDictViewModel, tokiInput: $tokiInput) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct TokiWordsListEntryView: View { | ||||
|     @State var entry: TokiDictEntry | ||||
|     @Binding var selectedPartOfSpeech: String? | ||||
|      | ||||
|     var body: some View { | ||||
|         VStack(alignment: .leading) { | ||||
|             Text(entry.word) | ||||
|                 .font(.title) | ||||
|             ForEach(entry.definitions, id: \.pos) { definition in | ||||
|                 HStack(alignment: .top) { | ||||
|                     Button(action: { | ||||
|                         self.selectedPartOfSpeech = String(definition.pos) | ||||
|                     }) { | ||||
|                         Text(definition.pos) | ||||
|                             .frame(width: 45, height: 22, alignment: .center) | ||||
|                             .foregroundColor(.black) | ||||
|                             .background(Color(K.posColors[definition.pos]!)) | ||||
|                             .cornerRadius(5.0) | ||||
|                             .padding(4) | ||||
|                     } | ||||
|                     .buttonStyle(BorderlessButtonStyle()) | ||||
|                     Text(definition.definition) | ||||
|                         .fixedSize(horizontal: false, vertical: true) | ||||
|                         .padding(4) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct TokiWordsView: View { | ||||
|     @ObservedObject var tokiDictViewModel: TokiDictionaryViewModel | ||||
|     @State var selectedPartOfSpeech: String? | ||||
|      | ||||
|     @Binding var tokiInput: String | ||||
|      | ||||
|     var body: some View { | ||||
|         List(tokiDictViewModel.dictionary, id: \.word) { entry in | ||||
|             VStack(alignment: .leading) { | ||||
|                 Text(entry.word) | ||||
| @@ -85,10 +176,47 @@ struct TranslatorView: View { | ||||
|             PartsOfSpeechView(selectedPartOfSpeech: selectedPOS, partsOfSpeech: tokiDictViewModel.partsOfSpeech) | ||||
|         } | ||||
|         .onChange(of: tokiInput) { newValue in | ||||
|                 tokiDictViewModel.filterDictionary(newValue) | ||||
|             tokiDictViewModel.translatePhrase(newValue) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct LanguageDirectionView: View { | ||||
|     private var fromText: String = "" | ||||
|     private var toText: String = "" | ||||
|     private var fromColor: Color = .black | ||||
|     private var toColor: Color = .black | ||||
|      | ||||
|     init(from: String, to: String, fromColor: Color, toColor: Color) { | ||||
|         self.fromText = from | ||||
|         self.toText = to | ||||
|         self.fromColor = fromColor | ||||
|         self.toColor = toColor | ||||
|     } | ||||
|      | ||||
|     var body: some View { | ||||
|         HStack { | ||||
|             Text(fromText) | ||||
|                 .bold() | ||||
|                 .multilineTextAlignment(.center) | ||||
|                 .foregroundColor(.white) | ||||
|                 .frame(width: 100) | ||||
|                 .background(fromColor) | ||||
|                 .border(fromColor) | ||||
|                 .cornerRadius(5) | ||||
|             Image(systemName: "chevron.right") | ||||
|             //rforegroundColor(.black) | ||||
|             Text(toText) | ||||
|                 .bold() | ||||
|                 .multilineTextAlignment(.center) | ||||
|                 .foregroundColor(.white) | ||||
|                 .frame(width: 100) | ||||
|                 .background(toColor) | ||||
|                 .border(toColor) | ||||
|                 .cornerRadius(5) | ||||
|         } | ||||
|         .padding(.top, 4) | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										34
									
								
								Toki Trainer/Views/DictionaryView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Toki Trainer/Views/DictionaryView.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| // | ||||
| //  DictionaryView.swift | ||||
| //  Toki Trainer | ||||
| // | ||||
| //  Created by maddiefuzz on 10/4/22. | ||||
| // | ||||
|  | ||||
| import SwiftUI | ||||
|  | ||||
| struct DictionaryView: View { | ||||
|     @ObservedObject var tokiDictViewModel = TokiDictionaryViewModel() | ||||
|      | ||||
|     @State var tokiInput: String = "" | ||||
|     @State var selectedPartOfSpeech: String? | ||||
|      | ||||
|     var body: some View { | ||||
|         VStack { | ||||
|             TextField("Search", text: $tokiInput) | ||||
|                 .multilineTextAlignment(.center) | ||||
|                 .textInputAutocapitalization(.never) | ||||
|                 .disableAutocorrection(true) | ||||
|                 .padding(8) | ||||
|                 .onSubmit { | ||||
|                     tokiDictViewModel.filterDictionary(tokiInput) | ||||
|                 } | ||||
|             List(tokiDictViewModel.dictionary, id: \.word) { entry in | ||||
|                 TokiWordsListEntryView(entry: entry, selectedPartOfSpeech: $selectedPartOfSpeech) | ||||
|             } | ||||
|             .onChange(of: tokiInput) { newValue in | ||||
|                 tokiDictViewModel.filterDictionary(newValue) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user