diff --git a/Toki Trainer.xcodeproj/project.pbxproj b/Toki Trainer.xcodeproj/project.pbxproj index 26fbafc..0765984 100644 --- a/Toki Trainer.xcodeproj/project.pbxproj +++ b/Toki Trainer.xcodeproj/project.pbxproj @@ -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 */; }; + E1A8B364290B905600B53385 /* ViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A8B363290B905600B53385 /* ViewExtensions.swift */; }; E1D79AE328EC396200A104BF /* DictionaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D79AE228EC396200A104BF /* DictionaryView.swift */; }; E1D79AE528F1914600A104BF /* TranslatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D79AE428F1914600A104BF /* TranslatorView.swift */; }; E1D79AE728F1925400A104BF /* TokiWordsListEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D79AE628F1925400A104BF /* TokiWordsListEntryView.swift */; }; @@ -104,6 +105,7 @@ 7E943A2C273211C300E7DDF4 /* Toki_Trainer.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Toki_Trainer.xcdatamodel; sourceTree = ""; }; 7EBAE6A9273D65FD00BCFA09 /* toki-lessons.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "toki-lessons.json"; sourceTree = ""; }; 7EF546152737B8FA00537AE6 /* FlashCardResultsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardResultsView.swift; sourceTree = ""; }; + E1A8B363290B905600B53385 /* ViewExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewExtensions.swift; sourceTree = ""; }; E1D79AE228EC396200A104BF /* DictionaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryView.swift; sourceTree = ""; }; E1D79AE428F1914600A104BF /* TranslatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslatorView.swift; sourceTree = ""; }; E1D79AE628F1925400A104BF /* TokiWordsListEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokiWordsListEntryView.swift; sourceTree = ""; }; @@ -217,6 +219,7 @@ 7E943A1F273211C200E7DDF4 /* Toki Trainer */ = { isa = PBXGroup; children = ( + E1A8B362290B903B00B53385 /* Extensions */, 7E44978E275C495E0016B6DC /* Toki Trainer.entitlements */, 7E28111E273302890063DC78 /* JSON Data */, 7E281113273302530063DC78 /* ViewModels */, @@ -239,6 +242,14 @@ path = "Preview Content"; sourceTree = ""; }; + E1A8B362290B903B00B53385 /* Extensions */ = { + isa = PBXGroup; + children = ( + E1A8B363290B905600B53385 /* ViewExtensions.swift */, + ); + path = Extensions; + sourceTree = ""; + }; E1D79AE828F1947F00A104BF /* WordListViews */ = { isa = PBXGroup; children = ( @@ -394,6 +405,7 @@ 7E716B4227398CDF009E2CF6 /* FlashCardLessonsView.swift in Sources */, 7E2811172733027F0063DC78 /* TokiDictionary.swift in Sources */, E1D79AE728F1925400A104BF /* TokiWordsListEntryView.swift in Sources */, + E1A8B364290B905600B53385 /* ViewExtensions.swift in Sources */, 7E71E6ED2735D70C007CFF72 /* FlashCardView.swift in Sources */, 7E943A21273211C200E7DDF4 /* Toki_TrainerApp.swift in Sources */, 7E716B462739B968009E2CF6 /* FlashCardLessonResultsView.swift in Sources */, @@ -420,7 +432,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = W9ASV855X5; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "Toki Trainer Widgets/Info.plist"; @@ -431,7 +443,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.1; PRODUCT_BUNDLE_IDENTIFIER = "info.maddie.Toki-Trainer.Toki-Trainer-Widgets"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -447,7 +459,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = W9ASV855X5; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "Toki Trainer Widgets/Info.plist"; @@ -458,7 +470,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.1; PRODUCT_BUNDLE_IDENTIFIER = "info.maddie.Toki-Trainer.Toki-Trainer-Widgets"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -592,7 +604,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = "Toki Trainer/Toki Trainer.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"Toki Trainer/Preview Content\""; DEVELOPMENT_TEAM = W9ASV855X5; ENABLE_PREVIEWS = YES; @@ -623,7 +635,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = "Toki Trainer/Toki Trainer.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"Toki Trainer/Preview Content\""; DEVELOPMENT_TEAM = W9ASV855X5; ENABLE_PREVIEWS = YES; diff --git a/Toki Trainer/Extensions/ViewExtensions.swift b/Toki Trainer/Extensions/ViewExtensions.swift new file mode 100644 index 0000000..2fbe019 --- /dev/null +++ b/Toki Trainer/Extensions/ViewExtensions.swift @@ -0,0 +1,15 @@ +// +// ViewExtensions.swift +// Toki Trainer +// +// Created by maddiefuzz on 10/28/22. +// + +import SwiftUI + +extension View { + func hideKeyboard() { + let resign = #selector(UIResponder.resignFirstResponder) + UIApplication.shared.sendAction(resign, to: nil, from: nil, for: nil) + } +} diff --git a/Toki Trainer/ViewModels/TokiDictionaryViewModel.swift b/Toki Trainer/ViewModels/TokiDictionaryViewModel.swift index 2ccbb02..b92d4d0 100644 --- a/Toki Trainer/ViewModels/TokiDictionaryViewModel.swift +++ b/Toki Trainer/ViewModels/TokiDictionaryViewModel.swift @@ -52,11 +52,21 @@ class TokiDictionaryViewModel: ObservableObject { entryMatch = true } - // Check if any part of the word definitions match in English, even partially + // Check if any part of the word definitions match in English, even partially, but + // only by prefix (if one of the definition words matches the beginning of the word with + // the search term) for definition in value.definitions { - if definition.definition.contains(input) { - entryMatch = true + let capturePattern = #"(\w+)"# + let captures = self.searchStringForRegex(string: definition.definition, regex: capturePattern) + for capture in captures { + if capture.hasPrefix(input) { + entryMatch = true + } } + // Commented out, less strict matching that will match on any substring match +// if definition.definition.contains(input) { +// entryMatch = true +// } } // Add to dictionary diff --git a/Toki Trainer/Views/WordListViews/DictionaryView.swift b/Toki Trainer/Views/WordListViews/DictionaryView.swift index 84453a2..66bc615 100644 --- a/Toki Trainer/Views/WordListViews/DictionaryView.swift +++ b/Toki Trainer/Views/WordListViews/DictionaryView.swift @@ -7,11 +7,19 @@ import SwiftUI +enum SearchMode { + case Dictionary + case Definitions +} + struct DictionaryView: View { @ObservedObject var tokiDictViewModel = TokiDictionaryViewModel() @State private var tokiInput: String = "" @State private var selectedPartOfSpeech: String? + @State var searchMode: SearchMode = .Dictionary + + @FocusState private var searchInputIsForuced: Bool var body: some View { VStack { @@ -21,8 +29,22 @@ struct DictionaryView: View { .disableAutocorrection(true) .padding(8) .onSubmit { - tokiDictViewModel.filterDictionary(tokiInput) + filterByInput() + //tokiDictViewModel.filterDictionaryEnglishMode(tokiInput) } + Picker("Language", selection: $searchMode) { + Text("Dictionary").tag(SearchMode.Dictionary) + Text("Definitions").tag(SearchMode.Definitions) + } + .pickerStyle(SegmentedPickerStyle()) + .onTapGesture { + if self.searchMode == SearchMode.Dictionary { + self.searchMode = SearchMode.Definitions + } else { + self.searchMode = SearchMode.Dictionary + } + filterByInput() + } List(tokiDictViewModel.dictionary, id: \.word) { entry in TokiWordsListEntryView(entry: entry, selectedPartOfSpeech: $selectedPartOfSpeech) } @@ -30,12 +52,25 @@ struct DictionaryView: View { PartsOfSpeechView(selectedPartOfSpeech: selectedPOS) } .onChange(of: tokiInput) { newValue in - tokiDictViewModel.filterDictionaryEnglishMode(newValue) + filterByInput() + //tokiDictViewModel.filterDictionaryEnglishMode(newValue) } } + .onTapGesture { + hideKeyboard() + } + } + + func filterByInput() { + if self.searchMode == SearchMode.Dictionary { + tokiDictViewModel.filterDictionary(tokiInput) + } else { + tokiDictViewModel.filterDictionaryEnglishMode(tokiInput) + } } } + struct DictionaryView_Previews: PreviewProvider { static var previews: some View { diff --git a/Toki Trainer/Views/WordListViews/TranslatorView.swift b/Toki Trainer/Views/WordListViews/TranslatorView.swift index a0199b3..64f78e9 100644 --- a/Toki Trainer/Views/WordListViews/TranslatorView.swift +++ b/Toki Trainer/Views/WordListViews/TranslatorView.swift @@ -53,6 +53,9 @@ struct TranslatorView: View { .onChange(of: tokiInput) { newValue in tokiDictViewModel.translatePhrase(newValue) } + .onTapGesture { + hideKeyboard() + } } func changeTranslationDirection() {