diff --git a/VocabularyTrainer/Helper.swift b/VocabularyTrainer/Helper.swift index ae3a791..e6ced62 100644 --- a/VocabularyTrainer/Helper.swift +++ b/VocabularyTrainer/Helper.swift @@ -177,12 +177,18 @@ class ExportImport { return nil } - static func importLanguageFiles(_ files: [URL]) { + static func importLanguageFiles(_ files: [URL], presentingViewController: HomeViewController) { for file in files { debugPrint(file.lastPathComponent) - let rawCsvImport = importLanguageFile(language: file.lastPathComponent) - let importedCsvAsDicts = csv(data: rawCsvImport) - updateUserDefFromImports(imports: importedCsvAsDicts, language: file.deletingPathExtension().lastPathComponent) +// let rawCsvImport = importLanguageFile(language: file.lastPathComponent) + var rawStringImport = "" + do { + rawStringImport = try String(contentsOf: file, encoding: .utf8) + } catch { let error = error + print(error) + } + let importedCsvAsDicts = csv(data: rawStringImport) + updateUserDefFromImports(imports: importedCsvAsDicts, language: file.deletingPathExtension().lastPathComponent, presentingViewController: presentingViewController) } } @@ -203,20 +209,36 @@ class ExportImport { return result } - static func updateUserDefFromImports(imports: LanguageImport, language: String) { + static func updateUserDefFromImports(imports: LanguageImport, language: String, presentingViewController: HomeViewController) { let languageVocabProgressKey = "\(language)Progress" - - UserDefaults.standard.set(imports.vocabularies, forKey: language) - UserDefaults.standard.set(imports.progresses, forKey: languageVocabProgressKey) - + if var savedLanguages = UserDefaults.standard.array(forKey: UserDefaultKeys.languages) as? [String] { // Append language if not found if !savedLanguages.contains(language) { savedLanguages.append(language) - } - - UserDefaults.standard.set(savedLanguages, forKey: UserDefaultKeys.languages) + UserDefaults.standard.set(savedLanguages, forKey: UserDefaultKeys.languages) + UserDefaults.standard.set(imports.vocabularies, forKey: language) + UserDefaults.standard.set(imports.progresses, forKey: languageVocabProgressKey) + presentingViewController.applyCollectionViewChanges() + } else { + let message = String(format: NSLocalizedString("alert_import_language_existing_message", comment: "Warning message when importing an already existing language"), language) + let title = NSLocalizedString("alert_import_language_existing_title", comment: "Title for already existing language warning") + let alert = UIAlertController( + title: title, + message: message, + preferredStyle: .alert) + + // add the actions (buttons) + alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "Cancel button title"), style: UIAlertAction.Style.cancel, handler: nil)) + alert.addAction(UIAlertAction(title: NSLocalizedString("home_import_button_title", comment: "Import button title"), style: UIAlertAction.Style.default, handler: { _ in + UserDefaults.standard.set(savedLanguages, forKey: UserDefaultKeys.languages) + UserDefaults.standard.set(imports.vocabularies, forKey: language) + UserDefaults.standard.set(imports.progresses, forKey: languageVocabProgressKey) + presentingViewController.applyCollectionViewChanges() + })) + presentingViewController.present(alert, animated: true) + } } else { UserDefaults.standard.set([language], forKey: UserDefaultKeys.languages) } @@ -232,7 +254,11 @@ class ExportImport { let columns = row.components(separatedBy: ";") vocabDict[columns[0]] = columns[1] vocabProgr[columns[0]] = (columns[2] as NSString).floatValue - datesAdded[columns[0]] = VocabularyDateFormatter.dateFormatter.date(from: columns[3]) + var date: Date? = Date() + if columns.indices.contains(3) { + date = VocabularyDateFormatter.dateFormatter.date(from: columns[3]) + } + datesAdded[columns[0]] = date } let result = LanguageImport.init(vocabularies: vocabDict, progresses: vocabProgr, datesAdded: datesAdded) diff --git a/VocabularyTrainer/Home Screen/ViewController/HomeViewController.swift b/VocabularyTrainer/Home Screen/ViewController/HomeViewController.swift index 4dbd9a9..2a79d3e 100644 --- a/VocabularyTrainer/Home Screen/ViewController/HomeViewController.swift +++ b/VocabularyTrainer/Home Screen/ViewController/HomeViewController.swift @@ -7,6 +7,7 @@ // import UIKit +import UniformTypeIdentifiers /// The home screen, showing tiles for each saved language in a waterfall style layout. final class HomeViewController: UIViewController { @@ -44,9 +45,10 @@ final class HomeViewController: UIViewController { let editAction = UIAccessibilityCustomAction(name: HomeViewModel.Strings.editButtonTitle, target: self, selector: #selector(editButtonAction)) - let importAction = UIAccessibilityCustomAction(name: HomeViewModel.Strings.importButtonTitle, - target: self, - selector: #selector(tappedImport)) + let importAction = UIAccessibilityCustomAction(name: HomeViewModel.Strings.importButtonTitle) { _ in + self.selectFiles() + return true + } let exportAction = UIAccessibilityCustomAction(name: HomeViewModel.Strings.exportButtonTitle, target: self, selector: #selector(tappedExport)) @@ -178,7 +180,7 @@ final class HomeViewController: UIViewController { } /// Applies changes of data source. - private func applyCollectionViewChanges() { + func applyCollectionViewChanges() { var snap = datasource.snapshot() if !snap.sectionIdentifiers.isEmpty { snap.deleteSections([0]) @@ -193,7 +195,7 @@ final class HomeViewController: UIViewController { navigationItem.leftBarButtonItem = navbarLogo let importButton = UIBarButtonItem( customView: UIButton.iconButton(type: .importButton) { [weak self] in - self?.tappedImport() + self?.selectFiles() } ) let exportButton = UIBarButtonItem( @@ -279,34 +281,14 @@ extension HomeViewController: UICollectionViewDelegate { extension HomeViewController { - @objc - private func tappedImport() { - guard let files = ExportImport.getAllLanguageFileUrls() else { return } - - if files.isEmpty { - let message = NSLocalizedString("emptyMessage", comment: "emptyMessage") - let alert = UIAlertController( - title: NSLocalizedString("No language files found", - comment: "No language files found"), - message: NSLocalizedString(message, comment: message), - preferredStyle: UIAlertController.Style.alert) - - alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.cancel, handler: nil)) - self.present(alert, animated: true, completion: nil) - errorHapticFeedback() - } else { - ExportImport.importLanguageFiles(files) - applyCollectionViewChanges() - successHapticFeedback() - } - } - - @objc - private func tappedExport() { + @objc private func tappedExport() { if let selectedLanguage = selectedLanguage { let words = ExportImport.exportAsCsvToDocuments(language: selectedLanguage) - let ac = UIActivityViewController(activityItems: [words], applicationActivities: nil) + + guard let cacheURL = saveStringAsCSVToCacheDirectory(words, fileName: selectedLanguage) else { return } + + let ac = UIActivityViewController(activityItems: [cacheURL], applicationActivities: nil) present(ac, animated: true) successHapticFeedback() } else { @@ -334,4 +316,38 @@ extension HomeViewController { let generator = UINotificationFeedbackGenerator() generator.notificationOccurred(.error) } + + private func saveStringAsCSVToCacheDirectory(_ inputString: String, fileName: String) -> URL? { + // Get the cache directory URL + if let cacheDirectoryURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first { + // Create a URL for the CSV file + let csvFileURL = cacheDirectoryURL.appendingPathComponent(fileName).appendingPathExtension("csv") + + do { + // Write the inputString to the CSV file + try inputString.write(to: csvFileURL, atomically: true, encoding: .utf8) + return csvFileURL // Return the URL to the saved CSV file + } catch { + print("Error saving CSV file: \(error)") + } + } + + return nil + } +} + +extension HomeViewController: UIDocumentPickerDelegate { + func selectFiles() { + let types = UTType.types(tag: "csv", + tagClass: UTTagClass.filenameExtension, + conformingTo: nil) + let documentPickerController = UIDocumentPickerViewController( + forOpeningContentTypes: types) + documentPickerController.delegate = self + self.present(documentPickerController, animated: true, completion: nil) + } + + func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + ExportImport.importLanguageFiles(urls, presentingViewController: self) + } } diff --git a/VocabularyTrainer/Localizable/de.lproj/Localizable.strings b/VocabularyTrainer/Localizable/de.lproj/Localizable.strings index 11d4a94..ac04bc5 100644 --- a/VocabularyTrainer/Localizable/de.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/de.lproj/Localizable.strings @@ -70,7 +70,9 @@ "home_import_button_title" = "Importieren"; "home_export_button_title" = "Exportieren"; "emptyMessage" = "Es konnten keine Sprachdateien für die App gefunden werden. Um eine Vorlage für eine Sprachdatei zu erhalten, erstelle eine neue Sprache in der App und exportiere diese."; -"nextWord" = "Nächstes wort"; +"nextWord" = "Nächstes Wort"; "emptyLanguage" = "Du hast noch keine Sprachen zum Üben ausgewählt! \n Tippe auf die + Schaltfläche, um deine Lernreise zu beginnen."; "emptyWord" = "Du hast noch keine Wörter zum Üben ausgewählt! \n Tippe auf die Bearbeiten-Schaltfläche, um neue Wörter hinzuzufügen."; "addedLanguage" = "Sprache hinzugefügt"; +"alert_import_language_existing_message" = "Du hast bereits eine Sprache mit dem Namen %@. Diese wird beim Import überschrieben.\Bist du sicher, dass Du fortfahren möchtest?"; +"alert_import_language_existing_title" = "Bereits vorhanden"; diff --git a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings index 5f58516..eac243e 100644 --- a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings @@ -77,3 +77,5 @@ "emptyLanguage" = "You don't have any languages to practice, yet! \n Tap the + button to start your learning journey."; "emptyWord" = "You don't have any words to practice, yet! \n Tap the edit button to add new words."; "addedLanguage" = "Added Language"; +"alert_import_language_existing_message" = "You already have a language called %@. This will be overwritten when importing.\nAre you sure you want to proceed?"; +"alert_import_language_existing_title" = "Already existing"; diff --git a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings index a465269..82588b0 100644 --- a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings @@ -74,3 +74,5 @@ "emptyLanguage" = "आपके पास अभी तक कोई भाषाएँ अभ्यास करने के लिए उपलब्ध नहीं हैं! \n + बटन दबाकर अपनी सीखने की यात्रा शुरू करें।"; "emptyWord" = "आपके पास अभी तक कोई शब्द अभ्यास करने के लिए नहीं हैं! \n नए शब्द जोड़ने के लिए संपादित बटन दबाएं।"; "addedLanguage" = "भाषा जोड़ी गई"; +"alert_import_language_existing_message" = "आपके पास पहले से ही एक भाषा है जिसका नाम %@ है। इसे आयात करते समय यह ओवरराइट हो जाएगा।\nक्या आप निश्चित ही आगे बढ़ना चाहते हो?"; +"alert_import_language_existing_title" = "पहले से मौजूद है"; diff --git a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings index c951497..ef21897 100644 --- a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings @@ -73,3 +73,5 @@ "emptyLanguage" = "Je hebt nog geen talen om te oefenen! \n Tik op de + knop om aan je leerreis te beginnen."; "emptyWord" = "Je hebt nog geen woorden om te oefenen! \n Tik op de bewerk-knop om nieuwe woorden toe te voegen."; "addedLanguage" = "Taal toegevoegd"; +"alert_import_language_existing_message" = "Je hebt al een taal met de naam %@. Dit wordt overschreven bij importeren.\nWeet je zeker dat je wilt doorgaan?"; +"alert_import_language_existing_title" = "Al reeds aanwezig"; diff --git a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings index bc1b8e1..88b0181 100644 --- a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings @@ -76,3 +76,6 @@ "emptyLanguage" = "Você não tem nenhum idioma para praticar, ainda! \n Toque no botão + para começar sua jornada de aprendizado."; "emptyWord" = "Você não tem nenhuma palavra para praticar, ainda! \n Toque no botão editar para adicionar novas palavras."; "addedLanguage" = "Idioma adicionado"; +"home_export_button_title" = "Export"; +"alert_import_language_existing_message" = "Você já tem um idioma chamado %@. Isso será sobrescrito ao importar.\nVocê tem certeza que quer prosseguir?"; +"alert_import_language_existing_title" = "Já existente";