From 2092655f6fc469f29db258bb686ec5fd49bbc301 Mon Sep 17 00:00:00 2001 From: Mariana Brasil Date: Sat, 4 Feb 2023 22:18:11 -0300 Subject: [PATCH 1/8] WIP --- VocabularyTrainer.xcodeproj/project.pbxproj | 24 +- .../Coordinator/MainCoordinator.swift | 22 +- .../Home Screen/HomeLanguageHeaderView.swift | 9 +- .../Home Screen/HomeViewController.swift | 10 +- .../Home Screen/HomeViewModel.swift | 1 + .../Home Screen/LanguageCellViewModel.swift | 2 +- .../Localizable/en.lproj/Localizable.strings | 2 +- .../Localizable/hi.lproj/Localizable.strings | 2 +- .../pt-BR.lproj/Localizable.strings | 2 +- .../NewLanguage/EmojiChooser.swift | 531 ++++++++---------- .../NewLanguageViewController.swift | 36 +- VocabularyTrainer/Training/TrainingView.swift | 87 +++ .../Training/TrainingViewController.swift | 50 ++ ...er.swift => TrainingViewController1.swift} | 2 +- 14 files changed, 472 insertions(+), 308 deletions(-) create mode 100644 VocabularyTrainer/Training/TrainingView.swift create mode 100644 VocabularyTrainer/Training/TrainingViewController.swift rename VocabularyTrainer/{TrainingViewController.swift => TrainingViewController1.swift} (99%) diff --git a/VocabularyTrainer.xcodeproj/project.pbxproj b/VocabularyTrainer.xcodeproj/project.pbxproj index cbe102f..394f983 100644 --- a/VocabularyTrainer.xcodeproj/project.pbxproj +++ b/VocabularyTrainer.xcodeproj/project.pbxproj @@ -17,12 +17,14 @@ B38C29D4294D45F1006FCDEA /* Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38C29D3294D45F1006FCDEA /* Localizable.swift */; }; B38C29D8294D578C006FCDEA /* UILabel+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38C29D7294D578C006FCDEA /* UILabel+Extensions.swift */; }; B38C29DA294D68B4006FCDEA /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38C29D9294D68B4006FCDEA /* String+Extensions.swift */; }; + B3E01CED298F260F004D86C1 /* TrainingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E01CEC298F260F004D86C1 /* TrainingView.swift */; }; + B3E01CEF298F2A7F004D86C1 /* TrainingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E01CEE298F2A7F004D86C1 /* TrainingViewController.swift */; }; B3E5421D294FB17A0015FD9C /* ModalCloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E5421C294FB17A0015FD9C /* ModalCloseButton.swift */; }; B3E54220294FC3290015FD9C /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E5421F294FC3290015FD9C /* UIView+Extensions.swift */; }; B3E54224294FDBA60015FD9C /* UIAccessibility+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E54223294FDBA60015FD9C /* UIAccessibility+Extensions.swift */; }; CE0012FF2243F21C002F86DE /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0012FE2243F21C002F86DE /* UIViewController+Extensions.swift */; }; CE05F622229F17AF0097E3BB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CE05F624229F17AF0097E3BB /* Localizable.strings */; }; - CE0FE4F82238585A00430FDE /* TrainingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0FE4F72238585A00430FDE /* TrainingViewController.swift */; }; + CE0FE4F82238585A00430FDE /* TrainingViewController1.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0FE4F72238585A00430FDE /* TrainingViewController1.swift */; }; CE2EB8272245406A006B1C6D /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE2EB8262245406A006B1C6D /* Launch Screen.storyboard */; }; CE31ED77290AC49F00AD3300 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE31ED76290AC49F00AD3300 /* AppDelegate.swift */; }; CE31ED79290AC4B100AD3300 /* AddWordDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE31ED78290AC4B100AD3300 /* AddWordDelegate.swift */; }; @@ -79,13 +81,15 @@ B38C29D9294D68B4006FCDEA /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = ""; }; B3BBF4422909F64B004B2125 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = "pt-BR"; path = "pt-BR.lproj/pp.html"; sourceTree = ""; }; B3BBF4432909F653004B2125 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; + B3E01CEC298F260F004D86C1 /* TrainingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingView.swift; sourceTree = ""; }; + B3E01CEE298F2A7F004D86C1 /* TrainingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingViewController.swift; sourceTree = ""; }; B3E5421C294FB17A0015FD9C /* ModalCloseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalCloseButton.swift; sourceTree = ""; }; B3E5421F294FC3290015FD9C /* UIView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = ""; }; B3E54223294FDBA60015FD9C /* UIAccessibility+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAccessibility+Extensions.swift"; sourceTree = ""; }; CE0012FE2243F21C002F86DE /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extensions.swift"; sourceTree = ""; }; CE05F623229F17AF0097E3BB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; CE05F625229F17C40097E3BB /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - CE0FE4F72238585A00430FDE /* TrainingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingViewController.swift; sourceTree = ""; }; + CE0FE4F72238585A00430FDE /* TrainingViewController1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingViewController1.swift; sourceTree = ""; }; CE2EB8262245406A006B1C6D /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; CE31ED76290AC49F00AD3300 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; CE31ED78290AC4B100AD3300 /* AddWordDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddWordDelegate.swift; sourceTree = ""; }; @@ -196,6 +200,15 @@ path = Extensions; sourceTree = ""; }; + B3E01CEB298F25FF004D86C1 /* Training */ = { + isa = PBXGroup; + children = ( + B3E01CEC298F260F004D86C1 /* TrainingView.swift */, + B3E01CEE298F2A7F004D86C1 /* TrainingViewController.swift */, + ); + path = Training; + sourceTree = ""; + }; B3E5421E294FBD160015FD9C /* Components */ = { isa = PBXGroup; children = ( @@ -249,7 +262,8 @@ B38C29DB294D6A70006FCDEA /* Extensions */, B3606D1B294D3D3E009E62E9 /* NewLanguage */, B3657DFE290740F8000D76C8 /* AddWord */, - CE0FE4F72238585A00430FDE /* TrainingViewController.swift */, + CE0FE4F72238585A00430FDE /* TrainingViewController1.swift */, + B3E01CEB298F25FF004D86C1 /* Training */, CE2EB8262245406A006B1C6D /* Launch Screen.storyboard */, B3606D1E294D459E009E62E9 /* Localizable */, CECD6344235E54350060911F /* pp.html */, @@ -478,6 +492,7 @@ 28716F4E290EF54B00EACCA1 /* Coordinator.swift in Sources */, CEF0605829510CD3001D2CEA /* HomeLanguageHeaderView.swift in Sources */, CEF0605529510A27001D2CEA /* LanguageCellViewModel.swift in Sources */, + B3E01CED298F260F004D86C1 /* TrainingView.swift in Sources */, B38C29DA294D68B4006FCDEA /* String+Extensions.swift in Sources */, CE0012FF2243F21C002F86DE /* UIViewController+Extensions.swift in Sources */, B38C29D4294D45F1006FCDEA /* Localizable.swift in Sources */, @@ -485,13 +500,14 @@ CE431526295E08F4000F7FA2 /* CollectionViewCell.swift in Sources */, E37D170B261BCD59006C1F71 /* VocabularyDateFormatter.swift in Sources */, CEF0605329510A27001D2CEA /* HomeViewController.swift in Sources */, + B3E01CEF298F2A7F004D86C1 /* TrainingViewController.swift in Sources */, CEB77943295E503F00D7BF35 /* NewLanguageScreenProtocol.swift in Sources */, CEA8BCC52966108D00E2EAF9 /* AboutViewController.swift in Sources */, CEB77947295E59E800D7BF35 /* EmojiChooser.swift in Sources */, B3E5421D294FB17A0015FD9C /* ModalCloseButton.swift in Sources */, B38C29D8294D578C006FCDEA /* UILabel+Extensions.swift in Sources */, CEB77945295E563200D7BF35 /* UserDefaults+Extensions.swift in Sources */, - CE0FE4F82238585A00430FDE /* TrainingViewController.swift in Sources */, + CE0FE4F82238585A00430FDE /* TrainingViewController1.swift in Sources */, 18943A0A29094F470017E1A2 /* LanguageScreenViewController.swift in Sources */, 28716F4F290EF54B00EACCA1 /* StoryBoarded.swift in Sources */, CE86C5822235C971008A5B73 /* Helper.swift in Sources */, diff --git a/VocabularyTrainer/Coordinator/MainCoordinator.swift b/VocabularyTrainer/Coordinator/MainCoordinator.swift index 113b4b3..11017eb 100644 --- a/VocabularyTrainer/Coordinator/MainCoordinator.swift +++ b/VocabularyTrainer/Coordinator/MainCoordinator.swift @@ -18,12 +18,12 @@ class MainCoordinator: Coordinator { self.navigationController = navigationController } - func start() { -// let homeVC = HomeScreenViewController() - let homeVC = HomeViewController(viewModel: HomeViewModel(coordinator: self)) -// homeVC.coordinator = self - navigationController.pushViewController(homeVC, animated: false) - } + func start() { + // let homeVC = HomeScreenViewController() + let homeVC = HomeViewController(viewModel: HomeViewModel(coordinator: self)) + // homeVC.coordinator = self + navigationController.pushViewController(homeVC, animated: false) + } func navigateToNewLanguageViewController(newLanguageScreenProtocol: NewLanguageScreenProtocol) { let newLanguageVC = NewLanguageViewController(delegate: newLanguageScreenProtocol) @@ -55,11 +55,11 @@ class MainCoordinator: Coordinator { navigationController.pushViewController(addNewWordVC, animated: true) } - func navigateToTrainingViewController(with language: String) { - let trainingVC = TrainingViewController(with: language) - trainingVC.coordinator = self - navigationController.pushViewController(trainingVC, animated: true) - } + func navigateToTrainingViewController(with language: String) { + let trainingVC = TrainingViewController(with: language) + trainingVC.coordinator = self + navigationController.present(trainingVC, animated: true) + } func popVC() { navigationController.popViewController(animated: true) diff --git a/VocabularyTrainer/Home Screen/HomeLanguageHeaderView.swift b/VocabularyTrainer/Home Screen/HomeLanguageHeaderView.swift index fe444a2..2cd4e3a 100644 --- a/VocabularyTrainer/Home Screen/HomeLanguageHeaderView.swift +++ b/VocabularyTrainer/Home Screen/HomeLanguageHeaderView.swift @@ -44,6 +44,7 @@ final class HomeLanguageHeaderView: UIView { button.tintColor = Colors.flippyGreen button.titleLabel?.font = .preferredFont(forTextStyle: .body) button.addAction(.init(handler: { [weak self] _ in self?.delegate?.tappedPracticeButton() }), for: .touchUpInside) + button.isHidden = true return button }() /// Button for editing a language. @@ -53,6 +54,7 @@ final class HomeLanguageHeaderView: UIView { button.setTitle(Strings.editButtonTitle, for: .normal) button.tintColor = .label button.addAction(.init(handler: { [weak self] _ in self?.delegate?.tappedEditButton() }), for: .touchUpInside) + button.isHidden = true return button }() /// Stack view horizontally aligning `practiceButton` and `editButton`. @@ -75,6 +77,11 @@ final class HomeLanguageHeaderView: UIView { required init?(coder: NSCoder) { nil } + func shouldHideHeaderButtons(_ isHidden: Bool) { + practiceButton.isHidden = isHidden + editButton.isHidden = isHidden + } + // MARK: - Setup private func setupUI() { @@ -91,7 +98,7 @@ final class HomeLanguageHeaderView: UIView { titleLabel.topAnchor.constraint(equalTo: topAnchor), titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor), - addLanguageButton.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 8), + addLanguageButton.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor), addLanguageButton.centerYAnchor.constraint(equalTo: titleLabel.centerYAnchor), addLanguageButton.heightAnchor.constraint(equalToConstant: 44), addLanguageButton.widthAnchor.constraint(equalToConstant: 44), diff --git a/VocabularyTrainer/Home Screen/HomeViewController.swift b/VocabularyTrainer/Home Screen/HomeViewController.swift index c3e3325..a28ae1f 100644 --- a/VocabularyTrainer/Home Screen/HomeViewController.swift +++ b/VocabularyTrainer/Home Screen/HomeViewController.swift @@ -36,6 +36,7 @@ final class HomeViewController: UIViewController { collectionView.autoresizingMask = [.flexibleHeight, .flexibleWidth] collectionView.backgroundColor = HomeViewModel.Colors.background collectionView.translatesAutoresizingMaskIntoConstraints = false + collectionView.delegate = self return collectionView }() /// Data source of `collectionView`. @@ -52,7 +53,7 @@ final class HomeViewController: UIViewController { return datasource }() /// Width of leading and trailing margins around `collectionView`. - private let horizontalCollectionViewMargins: CGFloat = 24 + private let horizontalCollectionViewMargins: CGFloat = 16 /// Colored Flippy logo shown at the leading side of the home screen's navbar. private let navbarLogo: UIBarButtonItem = { let label = UILabel() @@ -184,6 +185,13 @@ extension HomeViewController: NewLanguageScreenProtocol { } } +extension HomeViewController: UICollectionViewDelegate { + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + headerView.shouldHideHeaderButtons(false) + } +} + // MARK: - Import / Export // TODO: Move to iCloud Export / Import later diff --git a/VocabularyTrainer/Home Screen/HomeViewModel.swift b/VocabularyTrainer/Home Screen/HomeViewModel.swift index ef859fc..0f3f327 100644 --- a/VocabularyTrainer/Home Screen/HomeViewModel.swift +++ b/VocabularyTrainer/Home Screen/HomeViewModel.swift @@ -74,5 +74,6 @@ final class HomeViewModel { static let title = UIColor.label static let subtitle = UIColor.secondaryLabel static let flippyGreen = UIColor(named: "flippyGreen") + static let selectedCell = UIColor(named: "selectedCell") } } diff --git a/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift b/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift index dbb9b53..6505dcf 100644 --- a/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift +++ b/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift @@ -48,7 +48,7 @@ extension LanguageCellViewModel { enum Strings { static let numberOfWordsTitle = NSLocalizedString( "homescreen_language_subtitle", - value: "Words: %i", + value: "%i words", comment: "Subtitle of a cell on the home screen showing the word count of a language." ) } diff --git a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings index 4ae8154..b4c9259 100644 --- a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings @@ -25,7 +25,7 @@ "new Word" = "new word"; "translation" = "translation"; "Training" = "📖 Training"; -"Training:" = "Training:"; +"Training" = "Training"; "Delete Language" = "🗑 Delete Language"; "export" = "💾 export language"; "New word" = "New word"; diff --git a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings index 3d8cb85..74173bd 100644 --- a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings @@ -22,7 +22,7 @@ "new Word" = "नया शब्द"; "translation" = "अनुवाद"; "Training" = "📖 प्रशिक्षण"; -"Training:" = "प्रशिक्षण:"; +"Training" = "प्रशिक्षण"; "Delete Language" = "🗑 भाषा हटाएं"; "export" = "💾 export language"; "New word" = "नया शब्द"; diff --git a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings index 08ff830..8233349 100644 --- a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings @@ -25,7 +25,7 @@ "new Word" = "nova palavra"; "translation" = "tradução"; "Training" = "📖 Treinar"; -"Training:" = "Treinando:"; +"Training" = "Treinando"; "Delete Language" = "🗑 Excluir idioma"; "export" = "💾 exportar idioma"; "New word" = "Nova palavra"; diff --git a/VocabularyTrainer/NewLanguage/EmojiChooser.swift b/VocabularyTrainer/NewLanguage/EmojiChooser.swift index e8f5abc..6cbdfa7 100644 --- a/VocabularyTrainer/NewLanguage/EmojiChooser.swift +++ b/VocabularyTrainer/NewLanguage/EmojiChooser.swift @@ -12,288 +12,255 @@ enum EmojiChooser { /// Huge set of emoji that look friendly. private static let emojiSet: Set = [ - "😀", - "😃", - "😄", - "😁", - "😆", - "😅", - "🤣", - "😂", - "🙂", - "🙃", - "😉", - "😊", - "😇", - "🥰", - "😍", - "🤩", - "😘", - "😗", - "☺️", - "😚", - "😙", - "🥲", - "😋", - "😛", - "😜", - "🤪", - "😝", - "🤑", - "🤗", - "🍇", - "🍈", - "🍉", - "🍊", - "🍋", - "🍌", - "🍍", - "🥭", - "🍎", - "🍏", - "🍐", - "🍑", - "🍒", - "🍓", - "🫐", - "🥝", - "🍅", - "🫒", - "🥥", - "🥑", - "🍆", - "🥔", - "🥕", - "🌽", - "🌶️", - "🫑", - "🥒", - "🥬", - "🥦", - "🧄", - "🧅", - "🍄", - "🥜", - "🌰", - "🍞", - "🥐", - "🥖", - "🫓", - "🥨", - "🥯", - "🥞", - "🧇", - "🧀", - "🍖", - "🍗", - "🥩", - "🥓", - "🍔", - "🍟", - "🍕", - "🌭", - "🥪", - "🌮", - "🌯", - "🫔", - "🥙", - "🧆", - "🥚", - "🍳", - "🥘", - "🍲", - "🫕", - "🥣", - "🥗", - "🍿", - "🧈", - "🧂", - "🥫", - "🍱", - "🍘", - "🍙", - "🍚", - "🍛", - "🍜", - "🍝", - "🍠", - "🍢", - "🍣", - "🍤", - "🍥", - "🥮", - "🍡", - "🥟", - "🥠", - "🥡", - "🦪", - "🍦", - "🍧", - "🍨", - "🍩", - "🍪", - "🎂", - "🍰", - "🧁", - "🥧", - "🍫", - "🍬", - "🍭", - "🍮", - "🍯", - "🍼", - "🥛", - "☕", - "🫖", - "🍵", - "🍶", - "🍾", - "🍷", - "🍸", - "🍹", - "🍺", - "🍻", - "🥂", - "🥃", - "🫗", - "🥤", - "🧋", - "🧃", - "🧉", - "🧊", - "🥢", - "🍽️", - "🍴", - "🥄", - "🚣", - "🗾", - "🏔️", - "⛰️", - "🌋", - "🗻", - "🏕️", - "🏖️", - "🏜️", - "🏝️", - "🏞️", - "🏟️", - "🏛️", - "🏗️", - "🛖", - "🏘️", - "🏚️", - "🏠", - "🏡", - "🏢", - "🏣", - "🏤", - "🏥", - "🏦", - "🏨", - "🏩", - "🏪", - "🏫", - "🏬", - "🏭", - "🏯", - "🏰", - "💒", - "🗼", - "🗽", - "⛪", - "🕌", - "🛕", - "🕍", - "⛩️", - "🕋", - "⛲", - "⛺", - "🌁", - "🌃", - "🏙️", - "🌄", - "🌅", - "🌆", - "🌇", - "🌉", - "🎠", - "🎡", - "🎢", - "🚂", - "🚃", - "🚄", - "🚅", - "🚆", - "🚇", - "🚈", - "🚉", - "🚊", - "🚝", - "🚞", - "🚋", - "🚌", - "🚍", - "🚎", - "🚐", - "🚑", - "🚒", - "🚓", - "🚔", - "🚕", - "🚖", - "🚗", - "🚘", - "🚙", - "🛻", - "🚚", - "🚛", - "🚜", - "🏎️", - "🏍️", - "🛵", - "🛺", - "🚲", - "🛴", - "🚏", - "🛣️", - "🛤️", - "⛽", - "🚨", - "🚥", - "🚦", - "🚧", - "⚓", - "⛵", - "🚤", - "🛳️", - "⛴️", - "🛥️", - "🚢", - "✈️", - "🛩️", - "🛫", - "🛬", - "🪂", - "💺", - "🚁", - "🚟", - "🚠", - "🚡", - "🛰️", - "🚀", - "🛸", - "🪐", - "🌠", - "🌌", - "⛱️", - "🎆", - "🎇", - "🎑", - "💴", - "💵", - "💶", - "💷", - "🗿" + "🇦🇨", + "🇦🇩", + "🇦🇪", + "🇦🇫", + "🇦🇬", + "🇦🇮", + "🇦🇱", + "🇦🇲", + "🇦🇴", + "🇦🇶", + "🇦🇷", + "🇦🇸", + "🇦🇹", + "🇦🇺", + "🇦🇼", + "🇦🇽", + "🇦🇿", + "🇧🇦", + "🇧🇩", + "🇧🇪", + "🇧🇫", + "🇧🇬", + "🇧🇭", + "🇧🇮", + "🇧🇯", + "🇧🇱", + "🇧🇲", + "🇧🇳", + "🇧🇴", + "🇧🇶", + "🇧🇷", + "🇧🇸", + "🇧🇹", + "🇧🇻", + "🇧🇼", + "🇧🇾", + "🇧🇿", + "🇨🇦", + "🇨🇩", + "🇨🇫", + "🇨🇬", + "🇨🇭", + "🇨🇮", + "🇨🇰", + "🇨🇱", + "🇨🇲", + "🇨🇳", + "🇨🇴", + "🇨🇵", + "🇨🇷", + "🇨🇺", + "🇨🇻", + "🇨🇼", + "🇨🇽", + "🇨🇾", + "🇨🇿", + "🇩🇪", + "🇩🇬", + "🇩🇯", + "🇩🇰", + "🇩🇲", + "🇩🇴", + "🇩🇿", + "🇪🇦", + "🇪🇪", + "🇪🇬", + "🇪🇭", + "🇪🇷", + "🇪🇸", + "🇪🇹", + "🇪🇺", + "🇫🇮", + "🇫🇯", + "🇫🇰", + "🇫🇲", + "🇫🇴", + "🇫🇷", + "🇬🇦", + "🇬🇧", + "🇬🇩", + "🇬🇪", + "🇬🇫", + "🇬🇭", + "🇬🇮", + "🇬🇱", + "🇬🇲", + "🇬🇳", + "🇬🇵", + "🇬🇶", + "🇬🇷", + "🇬🇸", + "🇬🇹", + "🇬🇺", + "🇬🇼", + "🇬🇾", + "🇭🇰", + "🇭🇲", + "🇭🇳", + "🇭🇷", + "🇭🇹", + "🇭🇺", + "🇮🇨", + "🇮🇩", + "🇮🇪", + "🇮🇱", + "🇮🇲", + "🇮🇳", + "🇮🇴", + "🇮🇶", + "🇮🇷", + "🇮🇸", + "🇮🇹", + "🇯🇪", + "🇯🇲", + "🇯🇴", + "🇯🇵", + "🇰🇪", + "🇰🇬", + "🇰🇭", + "🇰🇮", + "🇰🇲", + "🇰🇳", + "🇰🇵", + "🇰🇷", + "🇰🇼", + "🇰🇾", + "🇰🇿", + "🇱🇦", + "🇱🇧", + "🇱🇨", + "🇱🇮", + "🇱🇰", + "🇱🇷", + "🇱🇸", + "🇱🇹", + "🇱🇺", + "🇱🇻", + "🇱🇾", + "🇲🇦", + "🇲🇨", + "🇲🇩", + "🇲🇪", + "🇲🇫", + "🇲🇬", + "🇲🇭", + "🇲🇰", + "🇲🇱", + "🇲🇳", + "🇲🇴", + "🇲🇵", + "🇲🇶", + "🇲🇷", + "🇲🇸", + "🇲🇹", + "🇲🇺", + "🇲🇻", + "🇲🇼", + "🇲🇽", + "🇲🇾", + "🇲🇿", + "🇳🇦", + "🇳🇨", + "🇳🇪", + "🇳🇫", + "🇳🇬", + "🇳🇮", + "🇳🇱", + "🇳🇴", + "🇳🇵", + "🇳🇷", + "🇳🇺", + "🇳🇿", + "🇴🇲", + "🇵🇦", + "🇵🇪", + "🇵🇫", + "🇵🇬", + "🇵🇭", + "🇵🇰", + "🇵🇱", + "🇵🇲", + "🇵🇳", + "🇵🇷", + "🇵🇸", + "🇵🇹", + "🇵🇼", + "🇵🇾", + "🇶🇦", + "🇷🇪", + "🇷🇴", + "🇷🇸", + "🇷🇺", + "🇷🇼", + "🇸🇦", + "🇸🇧", + "🇸🇨", + "🇸🇩", + "🇸🇪", + "🇸🇬", + "🇸🇭", + "🇸🇮", + "🇸🇯", + "🇸🇰", + "🇸🇱", + "🇸🇲", + "🇸🇳", + "🇸🇴", + "🇸🇷", + "🇸🇹", + "🇸🇻", + "🇸🇽", + "🇸🇾", + "🇸🇿", + "🇹🇦", + "🇹🇨", + "🇹🇩", + "🇹🇫", + "🇹🇬", + "🇹🇭", + "🇹🇯", + "🇹🇰", + "🇹🇱", + "🇹🇲", + "🇹🇳", + "🇹🇴", + "🇹🇷", + "🇹🇻", + "🇹🇼", + "🇹🇿", + "🇺🇦", + "🇺🇬", + "🇺🇸", + "🇺🇾", + "🇺🇿", + "🇻🇦", + "🇻🇨", + "🇻🇪", + "🇻🇬", + "🇻🇮", + "🇻🇳", + "🇻🇺", + "🇼🇫", + "🇼🇸", + "🇽🇰", + "🇾🇪", + "🇾🇹", + "🇿🇦", + "🇿🇲", + "🇿🇼" ] /// Randomly chooses an emoji from `emojiSet`. diff --git a/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift b/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift index 7342df1..90f2d96 100644 --- a/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift +++ b/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift @@ -87,13 +87,35 @@ final class NewLanguageViewController: UIViewController { private lazy var randomEmojiLabel: UILabel = { let label = UILabel() + label.isAccessibilityElement = false label.text = randomEmoji - label.font = UIFontMetrics(forTextStyle: .title2).scaledFont(for: .systemFont(ofSize: 30)) + label.font = UIFontMetrics(forTextStyle: .title2).scaledFont(for: .systemFont(ofSize: 50)) label.translatesAutoresizingMaskIntoConstraints = false return label }() - private let randomEmoji: String = EmojiChooser.choose + private lazy var randomButton: UIButton = { + let button = UIButton(frame: .zero, + primaryAction: .init(handler: { [weak self] _ in + self?.randomizeEmoji() + })) + button.backgroundColor = .systemBackground + button.layer.cornerRadius = 10 + button.clipsToBounds = true + let imageConfig = UIImage.SymbolConfiguration(pointSize: 16, weight: .bold, scale: .small) + button.setImage(UIImage(systemName: "arrow.triangle.2.circlepath"), for: .normal) + button.setPreferredSymbolConfiguration(imageConfig, forImageIn: .normal) + button.tintColor = .systemGray + button.isAccessibilityElement = false + return button + }() + + private var randomEmoji: String = EmojiChooser.choose + + private func randomizeEmoji() { + randomEmoji = EmojiChooser.choose + randomEmojiLabel.text = randomEmoji + } // MARK: - Init @@ -121,7 +143,8 @@ final class NewLanguageViewController: UIViewController { textField, feedbackLabel, addButton, - randomEmojiLabel]) + randomEmojiLabel, + randomButton]) setUpConstraints() } @@ -140,7 +163,12 @@ final class NewLanguageViewController: UIViewController { randomEmojiLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 24), randomEmojiLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), - languageLabel.topAnchor.constraint(equalTo: randomEmojiLabel.bottomAnchor, constant: 24), + randomButton.topAnchor.constraint(equalTo: randomEmojiLabel.bottomAnchor, constant: -20), + randomButton.leadingAnchor.constraint(equalTo: randomEmojiLabel.trailingAnchor, constant: -15), + randomButton.heightAnchor.constraint(equalToConstant: 28), + randomButton.widthAnchor.constraint(equalToConstant: 28), + + languageLabel.topAnchor.constraint(equalTo: randomButton.bottomAnchor, constant: 24), languageLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24), languageLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24), diff --git a/VocabularyTrainer/Training/TrainingView.swift b/VocabularyTrainer/Training/TrainingView.swift new file mode 100644 index 0000000..bf66672 --- /dev/null +++ b/VocabularyTrainer/Training/TrainingView.swift @@ -0,0 +1,87 @@ +// +// TrainingView.swift +// VocabularyTrainer +// +// Created by Mariana Brasil on 04/02/23. +// Copyright © 2023 mic. All rights reserved. +// + +import UIKit + +// MARK: - Protocol +protocol TrainingViewDelegate: AnyObject { + func tappedBarButton() + func setWordLabel() +} + +// MARK: - Training View Class + +class TrainingView: UIView { + + // MARK: - Private properties + + weak var delegate: TrainingViewDelegate? + + private lazy var barButton: UIButton = { + let button: UIButton = .init(frame: .zero, + primaryAction: .init(handler: { [weak self] _ in + self?.delegate?.tappedBarButton() + })) + button.layer.cornerRadius = 3 + button.backgroundColor = .systemGray + return button + }() + + private lazy var trainingLanguageLabel: UILabel = { + let label: UILabel = .init() + label.font = UIFontMetrics(forTextStyle: .title2) + .scaledFont(for: .systemFont(ofSize: 20, + weight: .semibold)) + return label + }() + + private lazy var wordLabel: UILabel = { + let label: UILabel = .init() + label.font = UIFontMetrics(forTextStyle: .largeTitle) + .scaledFont(for: .systemFont(ofSize: 32, + weight: .bold)) + return label + }() + + // MARK: - Initializer + + init(selectedLanguage: String) { + super.init(frame: .zero) + setUpUI() + setUpConstraints() + setUpLanguageTrained(selectedLanguage: selectedLanguage) + } + + required init?(coder: NSCoder) { nil } + + // MARK: - Private Methods + + private func setUpUI() { + addSubviews([barButton, + trainingLanguageLabel, + wordLabel]) + } + + private func setUpConstraints() { + NSLayoutConstraint.activate([ + barButton.topAnchor.constraint(equalTo: self.topAnchor, constant: 16), + barButton.centerXAnchor.constraint(equalTo: self.centerXAnchor), + barButton.heightAnchor.constraint(equalToConstant: 5), + barButton.widthAnchor.constraint(equalToConstant: 40), + + trainingLanguageLabel.topAnchor.constraint(equalTo: barButton.bottomAnchor, constant: 36), + trainingLanguageLabel.centerXAnchor.constraint(equalTo: barButton.centerXAnchor) + ]) + } + + private func setUpLanguageTrained(selectedLanguage: String) { + let defaultLabel: String = NSLocalizedString("Training", comment: "Training") + trainingLanguageLabel.text = "\(defaultLabel) \(selectedLanguage)" + } + +} diff --git a/VocabularyTrainer/Training/TrainingViewController.swift b/VocabularyTrainer/Training/TrainingViewController.swift new file mode 100644 index 0000000..640ec17 --- /dev/null +++ b/VocabularyTrainer/Training/TrainingViewController.swift @@ -0,0 +1,50 @@ +// +// TrainingViewController.swift +// VocabularyTrainer +// +// Created by Mariana Brasil on 04/02/23. +// Copyright © 2023 mic. All rights reserved. +// + +import UIKit + +final class TrainingViewController: UIViewController { + + // MARK: - Public properties + + weak var coordinator: MainCoordinator? + + // MARK: - Private properties + + private let selectedLanguage: String + + private lazy var trainingView: UIView = TrainingView(selectedLanguage: selectedLanguage) + + // MARK: - Init + + init(with language: String) { + self.selectedLanguage = language + super.init(nibName: nil, bundle: nil) + setUpUI() + setUpConstraints() + } + + required init?(coder: NSCoder) { nil } + + // MARK: - Private Methods + + private func setUpUI() { + view.addSubview(trainingView) + view.backgroundColor = .systemBackground + trainingView.translatesAutoresizingMaskIntoConstraints = false + } + + private func setUpConstraints() { + NSLayoutConstraint.activate([ + trainingView.topAnchor.constraint(equalTo: view.topAnchor), + trainingView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + trainingView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + trainingView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + } +} diff --git a/VocabularyTrainer/TrainingViewController.swift b/VocabularyTrainer/TrainingViewController1.swift similarity index 99% rename from VocabularyTrainer/TrainingViewController.swift rename to VocabularyTrainer/TrainingViewController1.swift index 99cc47b..8b52f36 100644 --- a/VocabularyTrainer/TrainingViewController.swift +++ b/VocabularyTrainer/TrainingViewController1.swift @@ -8,7 +8,7 @@ import UIKit -class TrainingViewController: UIViewController { +class TrainingViewController1: UIViewController { private let selectedLanguage: String var vocabularies: [String: String]? From a3fabd9de5a4cc309990163a7b55ad0a5d64a711 Mon Sep 17 00:00:00 2001 From: Mariana Brasil Date: Sat, 15 Jul 2023 15:20:19 -0300 Subject: [PATCH 2/8] Fix some bugs and removed emoji of cell --- VocabularyTrainer.xcodeproj/project.pbxproj | 4 - .../Home Screen/CollectionViewCell.swift | 17 +- .../Home Screen/HomeLanguageHeaderView.swift | 5 +- .../Home Screen/HomeViewController.swift | 16 +- .../Home Screen/HomeViewModel.swift | 3 +- .../Home Screen/LanguageCellViewModel.swift | 3 +- .../Localizable/de.lproj/Localizable.strings | 2 +- .../Localizable/en.lproj/Localizable.strings | 2 +- .../Localizable/hi.lproj/Localizable.strings | 2 +- .../Localizable/nl.lproj/Localizable.strings | 2 +- .../pt-BR.lproj/Localizable.strings | 10 +- .../NewLanguage/EmojiChooser.swift | 270 ------------------ .../NewLanguageViewController.swift | 48 +--- VocabularyTrainer/Training/TrainingView.swift | 2 +- 14 files changed, 29 insertions(+), 357 deletions(-) delete mode 100644 VocabularyTrainer/NewLanguage/EmojiChooser.swift diff --git a/VocabularyTrainer.xcodeproj/project.pbxproj b/VocabularyTrainer.xcodeproj/project.pbxproj index 394f983..f056407 100644 --- a/VocabularyTrainer.xcodeproj/project.pbxproj +++ b/VocabularyTrainer.xcodeproj/project.pbxproj @@ -37,7 +37,6 @@ CEA8BCC52966108D00E2EAF9 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA8BCC42966108D00E2EAF9 /* AboutViewController.swift */; }; CEB77943295E503F00D7BF35 /* NewLanguageScreenProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB77942295E503F00D7BF35 /* NewLanguageScreenProtocol.swift */; }; CEB77945295E563200D7BF35 /* UserDefaults+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB77944295E563200D7BF35 /* UserDefaults+Extensions.swift */; }; - CEB77947295E59E800D7BF35 /* EmojiChooser.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB77946295E59E800D7BF35 /* EmojiChooser.swift */; }; CEB77951295F681300D7BF35 /* WaterfallTrueCompositionalLayout in Frameworks */ = {isa = PBXBuildFile; productRef = CEB77950295F681300D7BF35 /* WaterfallTrueCompositionalLayout */; }; CECD6342235E54350060911F /* pp.html in Resources */ = {isa = PBXBuildFile; fileRef = CECD6344235E54350060911F /* pp.html */; }; CEE4988828F572E200B64FCF /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = CEE4988728F572E200B64FCF /* README.md */; }; @@ -110,7 +109,6 @@ CEA8BCC42966108D00E2EAF9 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; }; CEB77942295E503F00D7BF35 /* NewLanguageScreenProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewLanguageScreenProtocol.swift; sourceTree = ""; }; CEB77944295E563200D7BF35 /* UserDefaults+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Extensions.swift"; sourceTree = ""; }; - CEB77946295E59E800D7BF35 /* EmojiChooser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiChooser.swift; sourceTree = ""; }; CECD6343235E54350060911F /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = Base; path = Base.lproj/pp.html; sourceTree = ""; }; CECD6346235E54420060911F /* de */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = de; path = de.lproj/pp.html; sourceTree = ""; }; CEE4988728F572E200B64FCF /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; @@ -163,7 +161,6 @@ isa = PBXGroup; children = ( B3606D1C294D3D55009E62E9 /* NewLanguageViewController.swift */, - CEB77946295E59E800D7BF35 /* EmojiChooser.swift */, ); path = NewLanguage; sourceTree = ""; @@ -503,7 +500,6 @@ B3E01CEF298F2A7F004D86C1 /* TrainingViewController.swift in Sources */, CEB77943295E503F00D7BF35 /* NewLanguageScreenProtocol.swift in Sources */, CEA8BCC52966108D00E2EAF9 /* AboutViewController.swift in Sources */, - CEB77947295E59E800D7BF35 /* EmojiChooser.swift in Sources */, B3E5421D294FB17A0015FD9C /* ModalCloseButton.swift in Sources */, B38C29D8294D578C006FCDEA /* UILabel+Extensions.swift in Sources */, CEB77945295E563200D7BF35 /* UserDefaults+Extensions.swift in Sources */, diff --git a/VocabularyTrainer/Home Screen/CollectionViewCell.swift b/VocabularyTrainer/Home Screen/CollectionViewCell.swift index 9428484..f2711e1 100644 --- a/VocabularyTrainer/Home Screen/CollectionViewCell.swift +++ b/VocabularyTrainer/Home Screen/CollectionViewCell.swift @@ -43,14 +43,6 @@ class CollectionViewCell: UICollectionViewCell { return view }() - private let emojiLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 1 - label.translatesAutoresizingMaskIntoConstraints = false - label.font = .preferredFont(forTextStyle: .headline) - return label - }() - private let background: UIView = { let view = UIView() view.backgroundColor = Colors.cellBackground @@ -77,7 +69,6 @@ class CollectionViewCell: UICollectionViewCell { func configure(with item: LanguageCellViewModel) { titleLabel.text = item.languageName subtitleLabel.text = item.subtitle - emojiLabel.text = item.emoji } private func setUpUI() { @@ -88,18 +79,12 @@ class CollectionViewCell: UICollectionViewCell { labelContainer.addArrangedSubview(titleLabel) labelContainer.addArrangedSubview(subtitleLabel) contentView.addSubview(labelContainer) - contentView.addSubview(emojiLabel) } private func setUpConstraints() { NSLayoutConstraint.activate([ - emojiLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: Dimensions.horizontalMargin), - emojiLabel.trailingAnchor.constraint(equalTo: labelContainer.leadingAnchor, constant: -Dimensions.horizontalMargin), - emojiLabel.centerYAnchor.constraint(equalTo: labelContainer.centerYAnchor), - emojiLabel.heightAnchor.constraint(equalToConstant: Dimensions.imageWidth), - emojiLabel.widthAnchor.constraint(equalToConstant: Dimensions.imageWidth), - labelContainer.topAnchor.constraint(equalTo: contentView.topAnchor, constant: Dimensions.verticalContainerMargin), + labelContainer.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: Dimensions.horizontalMargin * 2), labelContainer.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Dimensions.horizontalMargin), labelContainer.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -Dimensions.verticalContainerMargin) ]) diff --git a/VocabularyTrainer/Home Screen/HomeLanguageHeaderView.swift b/VocabularyTrainer/Home Screen/HomeLanguageHeaderView.swift index 2cd4e3a..0983138 100644 --- a/VocabularyTrainer/Home Screen/HomeLanguageHeaderView.swift +++ b/VocabularyTrainer/Home Screen/HomeLanguageHeaderView.swift @@ -104,9 +104,8 @@ final class HomeLanguageHeaderView: UIView { addLanguageButton.widthAnchor.constraint(equalToConstant: 44), buttonStackView.leadingAnchor.constraint(greaterThanOrEqualTo: addLanguageButton.trailingAnchor, constant: Layout.defaultMargin), - buttonStackView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor), - buttonStackView.trailingAnchor.constraint(equalTo: trailingAnchor), - buttonStackView.bottomAnchor.constraint(equalTo: bottomAnchor) + buttonStackView.topAnchor.constraint(greaterThanOrEqualTo: titleLabel.topAnchor, constant: -5), + buttonStackView.trailingAnchor.constraint(equalTo: trailingAnchor) ]) } } diff --git a/VocabularyTrainer/Home Screen/HomeViewController.swift b/VocabularyTrainer/Home Screen/HomeViewController.swift index a28ae1f..a26d539 100644 --- a/VocabularyTrainer/Home Screen/HomeViewController.swift +++ b/VocabularyTrainer/Home Screen/HomeViewController.swift @@ -30,6 +30,9 @@ final class HomeViewController: UIViewController { viewModel.data.indices.contains(selectedIndexPath.row) else { return nil } return viewModel.data[selectedIndexPath.row].languageName } + /// The last index path selected. + private var selectedLastIndexPath: Int? + /// The collection view showing all the languages. private lazy var collectionView: UICollectionView = { let collectionView = UICollectionView(frame: .zero, collectionViewLayout: .init()) @@ -188,7 +191,14 @@ extension HomeViewController: NewLanguageScreenProtocol { extension HomeViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - headerView.shouldHideHeaderButtons(false) + if selectedLastIndexPath == indexPath.row { + collectionView.deselectItem(at: indexPath, animated: true) + headerView.shouldHideHeaderButtons(true) + selectedLastIndexPath = nil + } else { + headerView.shouldHideHeaderButtons(false) + selectedLastIndexPath = indexPath.row + } } } @@ -201,9 +211,7 @@ extension HomeViewController { guard let files = ExportImport.getAllLanguageFileUrls() else { return } if files.isEmpty { - let message = """ - There were not found any language files for your app.\nFor a template of a language file you may create a new language with some vocabulary inside this app and export it. - """ + let message = NSLocalizedString("emptyMessage", comment: "emptyMessage") let alert = UIAlertController( title: NSLocalizedString("No language files found", comment: "No language files found"), diff --git a/VocabularyTrainer/Home Screen/HomeViewModel.swift b/VocabularyTrainer/Home Screen/HomeViewModel.swift index 0f3f327..6fa40ba 100644 --- a/VocabularyTrainer/Home Screen/HomeViewModel.swift +++ b/VocabularyTrainer/Home Screen/HomeViewModel.swift @@ -22,8 +22,7 @@ final class HomeViewModel { let languageDict = UserDefaults.standard.dictionary(forKey: $0) as? [String: String] let emoji = UserDefaults.standard.languageEmoji(for: $0) ?? "" return LanguageCellViewModel(languageName: $0, - numberOfWords: languageDict?.count ?? 0, - emoji: emoji) + numberOfWords: languageDict?.count ?? 0) } } return retVal diff --git a/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift b/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift index 6505dcf..55f2dbe 100644 --- a/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift +++ b/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift @@ -12,7 +12,6 @@ struct LanguageCellViewModel: Hashable { let id = UUID() let languageName: String let numberOfWords: Int - let emoji: String /// Subtitle containing word counter, // TODO: use plural localization @@ -48,7 +47,7 @@ extension LanguageCellViewModel { enum Strings { static let numberOfWordsTitle = NSLocalizedString( "homescreen_language_subtitle", - value: "%i words", + value: NSLocalizedString("%d words", comment: "%d words"), comment: "Subtitle of a cell on the home screen showing the word count of a language." ) } diff --git a/VocabularyTrainer/Localizable/de.lproj/Localizable.strings b/VocabularyTrainer/Localizable/de.lproj/Localizable.strings index 50cf095..f5dd7df 100644 --- a/VocabularyTrainer/Localizable/de.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/de.lproj/Localizable.strings @@ -51,7 +51,6 @@ "Skip word" = "Wort überspringen"; "search for words" = "Wort suchen"; "Importing language files into the app will overwrite any languages in your app with the same name as the csv-file.\n Do you want to proceed?" = "Auf dem iPhone vorhandene Sprachen mit gleichem Namen wie die zu importierenden csv-Dateien werden beim Importieren überschrieben.\nWillst du die csv-Dateien wirklich importieren?"; -"There were not found any language files for your app.\nFor a template of a language file you may create a new language with some vocabulary inside this app and export it." = "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."; "No language files found" = "Keine Sprachdateien gefunden"; "👍 I was right" = "👍"; "👎 I was wrong" = "👎"; @@ -70,3 +69,4 @@ "home_edit_button_title" = "Bearbeiten"; "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."; diff --git a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings index b4c9259..d9a94bf 100644 --- a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings @@ -52,7 +52,7 @@ "search for words" = "search for words"; "Importing language files into the app will overwrite any languages in your app with the same name as the csv-file.\n Do you want to proceed?" = "Existing languages on your device with the same name as the csv-file you try to import will be overwritten.\n Do you want to proceed?"; -"There were not found any language files for your app.\nFor a template of a language file you may create a new language with some vocabulary inside this app and export it." = "There were not found any language files for your app.\nFor a template of a language file you may create a new language with some vocabulary inside this app and export it."; +"emptyMessage" = "There were not found any language files for your app.\nFor a template of a language file you may create a new language with some vocabulary inside this app and export it."; "No language files found" = "No language files found"; "👍 I was right" = "👍"; "👎 I was wrong" = "👎"; diff --git a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings index 74173bd..3874992 100644 --- a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings @@ -49,7 +49,7 @@ "search for words" = "शब्द खोजें"; "Importing language files into the app will overwrite any languages in your app with the same name as the csv-file.\n Do you want to proceed?" = "आपके device पर उसी नाम वाली मौजूदा भाषाएं, जिसका नाम आप जिस csv file import करने का प्रयास करते हैं, उसे अधिलेखित कर दिया जाएगा।\n क्या आप आगे बढ़ना चाहते हैं?"; -"There were not found any language files for your app.\nFor a template of a language file you may create a new language with some vocabulary inside this app and export it." = "आपके ऐप के लिए कोई भाषा फ़ाइल नहीं मिली। \n किसी भाषा फ़ाइल के template के लिए आप इस app के अंदर कुछ शब्दावली एक नई भाषा बना सकते हैं और इसे export कर सकते हैं।"; +"emptyMessage" = "आपके ऐप के लिए कोई भाषा फ़ाइल नहीं मिली। \n किसी भाषा फ़ाइल के template के लिए आप इस app के अंदर कुछ शब्दावली एक नई भाषा बना सकते हैं और इसे export कर सकते हैं।"; "No language files found" = "कोई भाषा फ़ाइल नहीं मिली"; "👍 I was right" = "👍"; "👎 I was wrong" = "👎"; diff --git a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings index d9e1de1..8b88d0b 100644 --- a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings @@ -50,7 +50,7 @@ "search for words" = "Zoeken naar woorden"; "Importing language files into the app will overwrite any languages in your app with the same name as the csv-file.\n Do you want to proceed?" = "Bestaande talen op je apparaat met dezelfde naam als het csv-file worden overschreven.\n Is dit oke?"; -"There were not found any language files for your app.\nFor a template of a language file you may create a new language with some vocabulary inside this app and export it." = "Geen bestanden met talen gevonden voor deze app.\nOm een template te creeren, kan je een nieuwe taal aanmaken en exporteren."; +"emptyMessage" = "Geen bestanden met talen gevonden voor deze app.\nOm een template te creeren, kan je een nieuwe taal aanmaken en exporteren."; "No language files found" = "Geen taalbestand geselecteerd"; "👍 I was right" = "👍"; "👎 I was wrong" = "👎"; diff --git a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings index 8233349..72ee51c 100644 --- a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings @@ -51,7 +51,7 @@ "Skip word" = "Pular palavra"; "search for words" = "buscar palavras"; "Importing language files into the app will overwrite any languages in your app with the same name as the csv-file.\n Do you want to proceed?" = "Os idiomas existentes no seu aparelho caso possuam o mesmo nome que os arquivos csv-file a serem importados serão sobrescritos.\n Você gostaria de continuar?"; -"There were not found any language files for your app.\nFor a template of a language file you may create a new language with some vocabulary inside this app and export it." = "Não foi encontrado qualquer arquivo de idioma para o seu app.\nPara ter o modelo do arquivo de idioma, você terá que criar um novo idioma com algumas palavras adicionadas dentro do app e exportar."; +"emptyMessage" = "Não foi encontrado qualquer arquivo de idioma para o seu app.\nPara ter o modelo do arquivo de idioma, você terá que criar um novo idioma com algumas palavras adicionadas dentro do app e exportar."; "No language files found" = "Nenhum arquivo de idioma foi encontrado"; "👍 I was right" = "👍"; "👎 I was wrong" = "👎"; @@ -67,8 +67,8 @@ "Your progress and probability configuration for this word will be saved" = "Seu progresso e configuração de probabilidade para essa palavra não será alterado com essa mudança"; "That's wrong 😕" = "Errado 😕"; "That's right! 🤠" = "Acertou! 🤠"; -"home_header_title" = "My Languages"; -"home_practice_button_title" = "Practice"; -"home_edit_button_title" = "Edit"; +"home_header_title" = "Meus Idiomas"; +"home_practice_button_title" = "Praticar"; +"home_edit_button_title" = "Editar"; "home_import_button_title" = "Importar"; -"home_export_button_title" = "Export"; +"home_export_button_title" = "Exportar"; diff --git a/VocabularyTrainer/NewLanguage/EmojiChooser.swift b/VocabularyTrainer/NewLanguage/EmojiChooser.swift deleted file mode 100644 index 6cbdfa7..0000000 --- a/VocabularyTrainer/NewLanguage/EmojiChooser.swift +++ /dev/null @@ -1,270 +0,0 @@ -// -// EmojiChooser.swift -// VocabularyTrainer -// -// Created by skrr on 30.12.22. -// Copyright © 2022 mic. All rights reserved. -// - -import Foundation - -enum EmojiChooser { - - /// Huge set of emoji that look friendly. - private static let emojiSet: Set = [ - "🇦🇨", - "🇦🇩", - "🇦🇪", - "🇦🇫", - "🇦🇬", - "🇦🇮", - "🇦🇱", - "🇦🇲", - "🇦🇴", - "🇦🇶", - "🇦🇷", - "🇦🇸", - "🇦🇹", - "🇦🇺", - "🇦🇼", - "🇦🇽", - "🇦🇿", - "🇧🇦", - "🇧🇩", - "🇧🇪", - "🇧🇫", - "🇧🇬", - "🇧🇭", - "🇧🇮", - "🇧🇯", - "🇧🇱", - "🇧🇲", - "🇧🇳", - "🇧🇴", - "🇧🇶", - "🇧🇷", - "🇧🇸", - "🇧🇹", - "🇧🇻", - "🇧🇼", - "🇧🇾", - "🇧🇿", - "🇨🇦", - "🇨🇩", - "🇨🇫", - "🇨🇬", - "🇨🇭", - "🇨🇮", - "🇨🇰", - "🇨🇱", - "🇨🇲", - "🇨🇳", - "🇨🇴", - "🇨🇵", - "🇨🇷", - "🇨🇺", - "🇨🇻", - "🇨🇼", - "🇨🇽", - "🇨🇾", - "🇨🇿", - "🇩🇪", - "🇩🇬", - "🇩🇯", - "🇩🇰", - "🇩🇲", - "🇩🇴", - "🇩🇿", - "🇪🇦", - "🇪🇪", - "🇪🇬", - "🇪🇭", - "🇪🇷", - "🇪🇸", - "🇪🇹", - "🇪🇺", - "🇫🇮", - "🇫🇯", - "🇫🇰", - "🇫🇲", - "🇫🇴", - "🇫🇷", - "🇬🇦", - "🇬🇧", - "🇬🇩", - "🇬🇪", - "🇬🇫", - "🇬🇭", - "🇬🇮", - "🇬🇱", - "🇬🇲", - "🇬🇳", - "🇬🇵", - "🇬🇶", - "🇬🇷", - "🇬🇸", - "🇬🇹", - "🇬🇺", - "🇬🇼", - "🇬🇾", - "🇭🇰", - "🇭🇲", - "🇭🇳", - "🇭🇷", - "🇭🇹", - "🇭🇺", - "🇮🇨", - "🇮🇩", - "🇮🇪", - "🇮🇱", - "🇮🇲", - "🇮🇳", - "🇮🇴", - "🇮🇶", - "🇮🇷", - "🇮🇸", - "🇮🇹", - "🇯🇪", - "🇯🇲", - "🇯🇴", - "🇯🇵", - "🇰🇪", - "🇰🇬", - "🇰🇭", - "🇰🇮", - "🇰🇲", - "🇰🇳", - "🇰🇵", - "🇰🇷", - "🇰🇼", - "🇰🇾", - "🇰🇿", - "🇱🇦", - "🇱🇧", - "🇱🇨", - "🇱🇮", - "🇱🇰", - "🇱🇷", - "🇱🇸", - "🇱🇹", - "🇱🇺", - "🇱🇻", - "🇱🇾", - "🇲🇦", - "🇲🇨", - "🇲🇩", - "🇲🇪", - "🇲🇫", - "🇲🇬", - "🇲🇭", - "🇲🇰", - "🇲🇱", - "🇲🇳", - "🇲🇴", - "🇲🇵", - "🇲🇶", - "🇲🇷", - "🇲🇸", - "🇲🇹", - "🇲🇺", - "🇲🇻", - "🇲🇼", - "🇲🇽", - "🇲🇾", - "🇲🇿", - "🇳🇦", - "🇳🇨", - "🇳🇪", - "🇳🇫", - "🇳🇬", - "🇳🇮", - "🇳🇱", - "🇳🇴", - "🇳🇵", - "🇳🇷", - "🇳🇺", - "🇳🇿", - "🇴🇲", - "🇵🇦", - "🇵🇪", - "🇵🇫", - "🇵🇬", - "🇵🇭", - "🇵🇰", - "🇵🇱", - "🇵🇲", - "🇵🇳", - "🇵🇷", - "🇵🇸", - "🇵🇹", - "🇵🇼", - "🇵🇾", - "🇶🇦", - "🇷🇪", - "🇷🇴", - "🇷🇸", - "🇷🇺", - "🇷🇼", - "🇸🇦", - "🇸🇧", - "🇸🇨", - "🇸🇩", - "🇸🇪", - "🇸🇬", - "🇸🇭", - "🇸🇮", - "🇸🇯", - "🇸🇰", - "🇸🇱", - "🇸🇲", - "🇸🇳", - "🇸🇴", - "🇸🇷", - "🇸🇹", - "🇸🇻", - "🇸🇽", - "🇸🇾", - "🇸🇿", - "🇹🇦", - "🇹🇨", - "🇹🇩", - "🇹🇫", - "🇹🇬", - "🇹🇭", - "🇹🇯", - "🇹🇰", - "🇹🇱", - "🇹🇲", - "🇹🇳", - "🇹🇴", - "🇹🇷", - "🇹🇻", - "🇹🇼", - "🇹🇿", - "🇺🇦", - "🇺🇬", - "🇺🇸", - "🇺🇾", - "🇺🇿", - "🇻🇦", - "🇻🇨", - "🇻🇪", - "🇻🇬", - "🇻🇮", - "🇻🇳", - "🇻🇺", - "🇼🇫", - "🇼🇸", - "🇽🇰", - "🇾🇪", - "🇾🇹", - "🇿🇦", - "🇿🇲", - "🇿🇼" - ] - - /// Randomly chooses an emoji from `emojiSet`. - static var choose: String { - emojiSet.randomElement() ?? "" - } -} diff --git a/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift b/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift index 90f2d96..56b04d5 100644 --- a/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift +++ b/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift @@ -84,38 +84,6 @@ final class NewLanguageViewController: UIViewController { .filter { $0.lowercased().elementsEqual(newLanguage.lowercased()) } return !matches.isEmpty } - - private lazy var randomEmojiLabel: UILabel = { - let label = UILabel() - label.isAccessibilityElement = false - label.text = randomEmoji - label.font = UIFontMetrics(forTextStyle: .title2).scaledFont(for: .systemFont(ofSize: 50)) - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - private lazy var randomButton: UIButton = { - let button = UIButton(frame: .zero, - primaryAction: .init(handler: { [weak self] _ in - self?.randomizeEmoji() - })) - button.backgroundColor = .systemBackground - button.layer.cornerRadius = 10 - button.clipsToBounds = true - let imageConfig = UIImage.SymbolConfiguration(pointSize: 16, weight: .bold, scale: .small) - button.setImage(UIImage(systemName: "arrow.triangle.2.circlepath"), for: .normal) - button.setPreferredSymbolConfiguration(imageConfig, forImageIn: .normal) - button.tintColor = .systemGray - button.isAccessibilityElement = false - return button - }() - - private var randomEmoji: String = EmojiChooser.choose - - private func randomizeEmoji() { - randomEmoji = EmojiChooser.choose - randomEmojiLabel.text = randomEmoji - } // MARK: - Init @@ -142,9 +110,7 @@ final class NewLanguageViewController: UIViewController { languageLabel, textField, feedbackLabel, - addButton, - randomEmojiLabel, - randomButton]) + addButton]) setUpConstraints() } @@ -160,15 +126,7 @@ final class NewLanguageViewController: UIViewController { titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10), titleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10), - randomEmojiLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 24), - randomEmojiLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), - - randomButton.topAnchor.constraint(equalTo: randomEmojiLabel.bottomAnchor, constant: -20), - randomButton.leadingAnchor.constraint(equalTo: randomEmojiLabel.trailingAnchor, constant: -15), - randomButton.heightAnchor.constraint(equalToConstant: 28), - randomButton.widthAnchor.constraint(equalToConstant: 28), - - languageLabel.topAnchor.constraint(equalTo: randomButton.bottomAnchor, constant: 24), + languageLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 24), languageLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24), languageLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24), @@ -205,8 +163,6 @@ final class NewLanguageViewController: UIViewController { } else { UserDefaults.standard.set([newLanguage], forKey: UserDefaultKeys.languages) } - // TODO: set emoji from to be implemented emoji chooser - UserDefaults.standard.setLanguageEmoji(for: newLanguage, emoji: randomEmoji) successHapticFeedback() delegate.updateLanguageTable(language: newLanguage) dismissView() diff --git a/VocabularyTrainer/Training/TrainingView.swift b/VocabularyTrainer/Training/TrainingView.swift index bf66672..91c83d4 100644 --- a/VocabularyTrainer/Training/TrainingView.swift +++ b/VocabularyTrainer/Training/TrainingView.swift @@ -16,7 +16,7 @@ protocol TrainingViewDelegate: AnyObject { // MARK: - Training View Class -class TrainingView: UIView { +final class TrainingView: UIView { // MARK: - Private properties From 878624b8de36facb7b0d149c86093a8d679e4fc5 Mon Sep 17 00:00:00 2001 From: Mariana Brasil Date: Sat, 15 Jul 2023 16:55:44 -0300 Subject: [PATCH 3/8] Fix bugs + added haptic feedback at home screen + creating the practice screen --- VocabularyTrainer.xcodeproj/project.pbxproj | 12 +- .../Home Screen/HomeViewController.swift | 25 ++++ .../Localizable/Localizable.swift | 2 + .../Localizable/en.lproj/Localizable.strings | 4 +- .../Localizable/nl.lproj/Localizable.strings | 4 +- .../pt-BR.lproj/Localizable.strings | 4 +- .../NewLanguageViewController.swift | 1 + VocabularyTrainer/Training/TrainingView.swift | 119 +++++++++++++++++- .../Training/TrainingViewController.swift | 1 + .../TrainingViewController1.swift | 1 - 10 files changed, 157 insertions(+), 16 deletions(-) diff --git a/VocabularyTrainer.xcodeproj/project.pbxproj b/VocabularyTrainer.xcodeproj/project.pbxproj index f056407..bd9467f 100644 --- a/VocabularyTrainer.xcodeproj/project.pbxproj +++ b/VocabularyTrainer.xcodeproj/project.pbxproj @@ -700,7 +700,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 6T68RPD4WZ; + DEVELOPMENT_TEAM = 972LY7PTVT; INFOPLIST_FILE = VocabularyTrainer/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -708,7 +708,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.3.0; - PRODUCT_BUNDLE_IDENTIFIER = st.mic.VocabularyTrainer; + PRODUCT_BUNDLE_IDENTIFIER = st.mic.VocabularyTrainerr; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; @@ -724,7 +724,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 6T68RPD4WZ; + DEVELOPMENT_TEAM = 972LY7PTVT; INFOPLIST_FILE = VocabularyTrainer/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -732,7 +732,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.3.0; - PRODUCT_BUNDLE_IDENTIFIER = st.mic.VocabularyTrainer; + PRODUCT_BUNDLE_IDENTIFIER = st.mic.VocabularyTrainerr; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; @@ -787,7 +787,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 6T68RPD4WZ; + DEVELOPMENT_TEAM = 972LY7PTVT; INFOPLIST_FILE = VocabularyTrainerUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -807,7 +807,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 6T68RPD4WZ; + DEVELOPMENT_TEAM = 972LY7PTVT; INFOPLIST_FILE = VocabularyTrainerUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/VocabularyTrainer/Home Screen/HomeViewController.swift b/VocabularyTrainer/Home Screen/HomeViewController.swift index a26d539..301328e 100644 --- a/VocabularyTrainer/Home Screen/HomeViewController.swift +++ b/VocabularyTrainer/Home Screen/HomeViewController.swift @@ -99,6 +99,8 @@ final class HomeViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) removeNavigationBarBackground() + selectedLastIndexPath = nil + headerView.shouldHideHeaderButtons(true) } // MARK: - Private Methods @@ -164,11 +166,13 @@ final class HomeViewController: UIViewController { extension HomeViewController: HomeLanguageHeaderViewDelegate { func tappedAddLanguageButton() { viewModel.coordinator?.navigateToNewLanguageViewController(newLanguageScreenProtocol: self) + selectedHapticFeedback() } func tappedPracticeButton() { guard let selectedLanguage = selectedLanguage else { return } viewModel.coordinator?.navigateToTrainingViewController(with: selectedLanguage) + selectedHapticFeedback() } func tappedEditButton() { @@ -179,6 +183,7 @@ extension HomeViewController: HomeLanguageHeaderViewDelegate { completion: { [weak self] in self?.applyCollectionViewChanges() }) + selectedHapticFeedback() } } @@ -199,6 +204,7 @@ extension HomeViewController: UICollectionViewDelegate { headerView.shouldHideHeaderButtons(false) selectedLastIndexPath = indexPath.row } + selectedHapticFeedback() } } @@ -220,9 +226,11 @@ extension HomeViewController { 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() } } @@ -232,6 +240,7 @@ extension HomeViewController { let words = ExportImport.exportAsCsvToDocuments(language: selectedLanguage) let ac = UIActivityViewController(activityItems: [words], applicationActivities: nil) present(ac, animated: true) + successHapticFeedback() } else { let alert = UIAlertController(title: NSLocalizedString("No language selected", comment: "Title for popup when no language was selected"), @@ -239,6 +248,22 @@ extension HomeViewController { preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) present(alert, animated: true, completion: nil) + errorHapticFeedback() } } + + private func selectedHapticFeedback() { + let generator = UISelectionFeedbackGenerator() + generator.selectionChanged() + } + + private func successHapticFeedback() { + let generator = UINotificationFeedbackGenerator() + generator.notificationOccurred(.success) + } + + private func errorHapticFeedback() { + let generator = UINotificationFeedbackGenerator() + generator.notificationOccurred(.error) + } } diff --git a/VocabularyTrainer/Localizable/Localizable.swift b/VocabularyTrainer/Localizable/Localizable.swift index 3dc1824..f6623d1 100644 --- a/VocabularyTrainer/Localizable/Localizable.swift +++ b/VocabularyTrainer/Localizable/Localizable.swift @@ -16,6 +16,8 @@ enum Localizable: String { case language case languageExists case add + case translation + case answer func localize() -> String { return NSLocalizedString(self.rawValue, comment: "") diff --git a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings index d9a94bf..eed0d34 100644 --- a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings @@ -23,7 +23,7 @@ "0 words" = "0 words"; "My words" = "⚙️ Edit"; "new Word" = "new word"; -"translation" = "translation"; +"translation" = "Translation"; "Training" = "📖 Training"; "Training" = "Training"; "Delete Language" = "🗑 Delete Language"; @@ -45,7 +45,7 @@ "You may copy your file to your machine via iTunes:\n iPhone->Filesharing->Flippy->drag csv-files into Finder" = "You may copy your file to your machine via iTunes:\n iPhone->Filesharing->Flippy->drag csv-files into Finder"; "⤵ import" = "⤋ import"; "↑ export" = "⇪ export"; -"answer" = "answer"; +"answer" = "Answer"; "Check" = "Check"; "Take a look" = "Take a look"; "Skip word" = "Skip word"; diff --git a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings index 8b88d0b..f5def52 100644 --- a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings @@ -22,7 +22,7 @@ "0 words" = "0 woorden"; "My words" = "⚙️ Bewerken"; "new Word" = "nieuw woord"; -"translation" = "vertaling"; +"translation" = "Vertaling"; "Training" = "📖 Training"; "Delete Language" = "🗑 Taal verwijderen"; "export" = "💾 Taal exporteren"; @@ -43,7 +43,7 @@ "You may copy your file to your machine via iTunes:\n iPhone->Filesharing->Flippy->drag csv-files into Finder" = "Je kan je taal bestand kopeeren naar je apparaat via iTunes:\n iPhone->Filesharing->Flippy->drag csv-files naar Finder"; "⤵ import" = "⤋ importeren"; "↑ export" = "⇪ exporteren"; -"answer" = "antwoord"; +"answer" = "Antwoord"; "Check" = "Controleer"; "Take a look" = "Neem een kijkje"; "Skip word" = "Woord overslaan"; diff --git a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings index 72ee51c..b321ccb 100644 --- a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings @@ -23,7 +23,7 @@ "0 words" = "0 palavras"; "My words" = "⚙️ Editar"; "new Word" = "nova palavra"; -"translation" = "tradução"; +"translation" = "Tradução"; "Training" = "📖 Treinar"; "Training" = "Treinando"; "Delete Language" = "🗑 Excluir idioma"; @@ -45,7 +45,7 @@ "You may copy your file to your machine via iTunes:\n iPhone->Filesharing->Flippy->drag csv-files into Finder" = "Você pode copiar o arquivo para o seu computador pelo iTunes.\nAcesse: iPhone->Compartilhamento de Arquivos->Flippy->arraste csv-files para o Finder"; "⤵ import" = "⤋ importar"; "↑ export" = "⇪ exportar"; -"answer" = "resposta"; +"answer" = "Resposta"; "Check" = "Confirmar"; "Take a look" = "Espiar"; "Skip word" = "Pular palavra"; diff --git a/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift b/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift index 56b04d5..6415b88 100644 --- a/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift +++ b/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift @@ -99,6 +99,7 @@ final class NewLanguageViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + hideKeyboardWhenTappedAround() } // MARK: - Private Methods diff --git a/VocabularyTrainer/Training/TrainingView.swift b/VocabularyTrainer/Training/TrainingView.swift index 91c83d4..3a22cc4 100644 --- a/VocabularyTrainer/Training/TrainingView.swift +++ b/VocabularyTrainer/Training/TrainingView.swift @@ -22,6 +22,11 @@ final class TrainingView: UIView { weak var delegate: TrainingViewDelegate? + private lazy var vocabularies: [String: String]? = [:] + private lazy var vocabulariesProgresses: [String: Float]? = [:] + private lazy var isKeyShown: Bool? = false + private lazy var currentKey: String? = .init() + private lazy var barButton: UIButton = { let button: UIButton = .init(frame: .zero, primaryAction: .init(handler: { [weak self] _ in @@ -48,6 +53,30 @@ final class TrainingView: UIView { return label }() + private lazy var answerLabel: UILabel = { + let label: UILabel = .init() + label.font = UIFontMetrics(forTextStyle: .headline) + .scaledFont(for: .systemFont(ofSize: 14, + weight: .bold)) + label.text = Localizable.answer.localize() + return label + }() + + private lazy var answerTextField: UITextField = { + let textField = UITextField() + textField.translatesAutoresizingMaskIntoConstraints = false + textField.placeholder = Localizable.translation.localize() + textField.font = .preferredFont(forTextStyle: .body) + textField.backgroundColor = .systemBackground + textField.leftView = UIView(frame: .init(x: 0, + y: 0, + width: 16, + height: textField.frame.height)) + textField.leftViewMode = .always + textField.addTarget(self, action: #selector(textFieldEvent), for: .allEvents) + return textField + }() + // MARK: - Initializer init(selectedLanguage: String) { @@ -55,6 +84,7 @@ final class TrainingView: UIView { setUpUI() setUpConstraints() setUpLanguageTrained(selectedLanguage: selectedLanguage) + setUpTraining() } required init?(coder: NSCoder) { nil } @@ -62,9 +92,12 @@ final class TrainingView: UIView { // MARK: - Private Methods private func setUpUI() { + backgroundColor = UIColor(named: "background") addSubviews([barButton, - trainingLanguageLabel, - wordLabel]) + trainingLanguageLabel, + wordLabel, + answerLabel, + answerTextField]) } private func setUpConstraints() { @@ -75,13 +108,93 @@ final class TrainingView: UIView { barButton.widthAnchor.constraint(equalToConstant: 40), trainingLanguageLabel.topAnchor.constraint(equalTo: barButton.bottomAnchor, constant: 36), - trainingLanguageLabel.centerXAnchor.constraint(equalTo: barButton.centerXAnchor) + trainingLanguageLabel.centerXAnchor.constraint(equalTo: barButton.centerXAnchor), + + wordLabel.topAnchor.constraint(equalTo: trainingLanguageLabel.bottomAnchor, constant: 32), + wordLabel.centerXAnchor.constraint(equalTo: barButton.centerXAnchor), + + answerLabel.topAnchor.constraint(equalTo: wordLabel.bottomAnchor, constant: 20), + answerLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 24), + + answerTextField.topAnchor.constraint(equalTo: answerLabel.bottomAnchor, constant: 4), + answerTextField.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -24), + answerTextField.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 24), + answerTextField.heightAnchor.constraint(equalToConstant: 46) ]) } private func setUpLanguageTrained(selectedLanguage: String) { let defaultLabel: String = NSLocalizedString("Training", comment: "Training") trainingLanguageLabel.text = "\(defaultLabel) \(selectedLanguage)" + + guard let vocabs = UserDefaults.standard.dictionary(forKey: selectedLanguage) as? [String: String] else { + print("no vocabularies found") + return + } + + guard let progresses = UserDefaults.standard.dictionary(forKey: "\(selectedLanguage)Progress") as? [String: Float]? else { + print("no progresses found") + return + } + + vocabularies = vocabs + vocabulariesProgresses = progresses } + private func setUpTraining() { + guard let vocabs = vocabularies else { return } + guard let progresses = vocabulariesProgresses else { return } + + let totalProgress = getTotalProgressFrom(progresses) + + currentKey = pickRandomKeyFrom(vocabs, withProgresses: progresses, totalProgress: totalProgress) + + guard let key = currentKey else { return } + + if (Int.random(in: 0...1) == 0) { + wordLabel.text = key + isKeyShown = true + } else { + wordLabel.text = vocabs[key] + isKeyShown = false + } + } + + private func getTotalProgressFrom(_ vocabulariesProgresses: [String: Float]) -> Float { + var result = Float(0) + for progress in vocabulariesProgresses { + result += progress.value + } + return result + } + + private func pickRandomKeyFrom(_ vocabularies: [String: String], + withProgresses vocabulariesProgresses: [String: Float], + totalProgress: Float) -> String { + let randomThreshold = Float.random(in: 0...totalProgress) + var summedUpProgresses = Float(0) + var resultKey: String = .init() + + for (key, value) in vocabulariesProgresses { + summedUpProgresses += value + if summedUpProgresses > randomThreshold { + resultKey = key + break + } + } + return resultKey + } + + @objc + private func textFieldEvent() { + guard let text = answerTextField.text else { return } + + if text.isEmptyOrWhitespace() { + + } else { + + } + answerTextField.borderStyle = .none + answerTextField.layer.borderWidth = 0 + } } diff --git a/VocabularyTrainer/Training/TrainingViewController.swift b/VocabularyTrainer/Training/TrainingViewController.swift index 640ec17..c595a05 100644 --- a/VocabularyTrainer/Training/TrainingViewController.swift +++ b/VocabularyTrainer/Training/TrainingViewController.swift @@ -27,6 +27,7 @@ final class TrainingViewController: UIViewController { super.init(nibName: nil, bundle: nil) setUpUI() setUpConstraints() + hideKeyboardWhenTappedAround() } required init?(coder: NSCoder) { nil } diff --git a/VocabularyTrainer/TrainingViewController1.swift b/VocabularyTrainer/TrainingViewController1.swift index 8b52f36..9ba147c 100644 --- a/VocabularyTrainer/TrainingViewController1.swift +++ b/VocabularyTrainer/TrainingViewController1.swift @@ -322,7 +322,6 @@ class TrainingViewController1: UIViewController { } func resetAnswerInput() { - UIView.animate(withDuration: 0.2, animations: { self.rightAnswerButton.alpha = 0.0 self.wrongAnswerButton.alpha = 0.0 From 545a5683b67f92a58eb0305214fab9410f176d33 Mon Sep 17 00:00:00 2001 From: Mariana Brasil Date: Sun, 16 Jul 2023 23:34:52 -0300 Subject: [PATCH 4/8] Wip --- .../Components/ModalCloseButton.swift | 1 + .../Home Screen/HomeViewModel.swift | 1 - .../Home Screen/LanguageCellViewModel.swift | 15 ++- .../Localizable/Localizable.swift | 2 + .../Localizable/de.lproj/Localizable.strings | 3 +- .../Localizable/en.lproj/Localizable.strings | 3 +- .../Localizable/hi.lproj/Localizable.strings | 5 +- .../Localizable/nl.lproj/Localizable.strings | 3 +- .../pt-BR.lproj/Localizable.strings | 3 +- .../NewLanguageViewController.swift | 2 +- VocabularyTrainer/Training/TrainingView.swift | 116 ++++++++++++++++-- 11 files changed, 132 insertions(+), 22 deletions(-) diff --git a/VocabularyTrainer/Components/ModalCloseButton.swift b/VocabularyTrainer/Components/ModalCloseButton.swift index 6510749..08a33c5 100644 --- a/VocabularyTrainer/Components/ModalCloseButton.swift +++ b/VocabularyTrainer/Components/ModalCloseButton.swift @@ -24,5 +24,6 @@ final class ModalCloseButton: UIButton { layer.cornerRadius = 3 translatesAutoresizingMaskIntoConstraints = false accessibilityLabel = Localizable.close.localize() + accessibilityTraits = .button } } diff --git a/VocabularyTrainer/Home Screen/HomeViewModel.swift b/VocabularyTrainer/Home Screen/HomeViewModel.swift index 6fa40ba..6022552 100644 --- a/VocabularyTrainer/Home Screen/HomeViewModel.swift +++ b/VocabularyTrainer/Home Screen/HomeViewModel.swift @@ -20,7 +20,6 @@ final class HomeViewModel { if let languages = UserDefaults.standard.array(forKey: UserDefaultKeys.languages) as? [String] { retVal = languages.map { let languageDict = UserDefaults.standard.dictionary(forKey: $0) as? [String: String] - let emoji = UserDefaults.standard.languageEmoji(for: $0) ?? "" return LanguageCellViewModel(languageName: $0, numberOfWords: languageDict?.count ?? 0) } diff --git a/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift b/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift index 55f2dbe..ccb2e45 100644 --- a/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift +++ b/VocabularyTrainer/Home Screen/LanguageCellViewModel.swift @@ -16,8 +16,13 @@ struct LanguageCellViewModel: Hashable { /// Subtitle containing word counter, // TODO: use plural localization var subtitle: String { - String(format: LanguageCellViewModel.Strings.numberOfWordsTitle, - numberOfWords) + if numberOfWords == 1 { + return String(format: LanguageCellViewModel.Strings.numberOfWordTitle, + numberOfWords) + } else { + return String(format: LanguageCellViewModel.Strings.numberOfWordsTitle, + numberOfWords) + } } /// Calculates required height of cell for given `width` based on text to be rendered in the cell. @@ -50,6 +55,12 @@ extension LanguageCellViewModel { value: NSLocalizedString("%d words", comment: "%d words"), comment: "Subtitle of a cell on the home screen showing the word count of a language." ) + + static let numberOfWordTitle = NSLocalizedString( + "homescreen_language_subtitle", + value: NSLocalizedString("%d word", comment: "%d word"), + comment: "Subtitle of a cell on the home screen showing the word count of a language." + ) } enum Colors { diff --git a/VocabularyTrainer/Localizable/Localizable.swift b/VocabularyTrainer/Localizable/Localizable.swift index f6623d1..6ef0a81 100644 --- a/VocabularyTrainer/Localizable/Localizable.swift +++ b/VocabularyTrainer/Localizable/Localizable.swift @@ -18,6 +18,8 @@ enum Localizable: String { case add case translation case answer + case check + case nextWord func localize() -> String { return NSLocalizedString(self.rawValue, comment: "") diff --git a/VocabularyTrainer/Localizable/de.lproj/Localizable.strings b/VocabularyTrainer/Localizable/de.lproj/Localizable.strings index f5dd7df..c153713 100644 --- a/VocabularyTrainer/Localizable/de.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/de.lproj/Localizable.strings @@ -46,7 +46,7 @@ "⤵ import" = "⤋ importieren"; "↑ export" = "⇪ exportieren"; "answer" = "Antwort"; -"Check" = "Prüfen"; +"check" = "Prüfen"; "Take a look" = "Umdrehen"; "Skip word" = "Wort überspringen"; "search for words" = "Wort suchen"; @@ -70,3 +70,4 @@ "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"; diff --git a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings index eed0d34..0b1a0ac 100644 --- a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings @@ -46,7 +46,7 @@ "⤵ import" = "⤋ import"; "↑ export" = "⇪ export"; "answer" = "Answer"; -"Check" = "Check"; +"check" = "Check"; "Take a look" = "Take a look"; "Skip word" = "Skip word"; "search for words" = "search for words"; @@ -73,3 +73,4 @@ "home_edit_button_title" = "Edit"; "home_import_button_title" = "Import"; "home_export_button_title" = "Export"; +"nextWord" = "Next word"; diff --git a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings index 3874992..af5bf38 100644 --- a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings @@ -43,7 +43,7 @@ "⤵ import" = "⤋ import"; "↑ export" = "⇪ export"; "answer" = "उत्तर"; -"Check" = "जांच"; +"check" = "जांच"; "Take a look" = "एक नज़र डालें"; "Skip word" = "शब्द छोड़ें"; "search for words" = "शब्द खोजें"; @@ -66,7 +66,8 @@ "That's wrong 😕" = "यह गलत है 😕"; "That's right! 🤠" = "यह सही है! 🤠"; "home_header_title" = "My Languages"; -"home_practice_button_title" = "Practice"; +"home_practice_button_title" = "प्रशिक्षण"; "home_edit_button_title" = "Edit"; "home_import_button_title" = "Import"; "home_export_button_title" = "Export"; +"nextWord" = "अगला शब्द"; diff --git a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings index f5def52..95a0de5 100644 --- a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings @@ -44,7 +44,7 @@ "⤵ import" = "⤋ importeren"; "↑ export" = "⇪ exporteren"; "answer" = "Antwoord"; -"Check" = "Controleer"; +"check" = "Controleer"; "Take a look" = "Neem een kijkje"; "Skip word" = "Woord overslaan"; "search for words" = "Zoeken naar woorden"; @@ -69,3 +69,4 @@ "home_edit_button_title" = "Edit"; "home_import_button_title" = "Import"; "home_export_button_title" = "Export"; +"nextWord" = "Volgende woord"; diff --git a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings index b321ccb..deb5e1d 100644 --- a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings @@ -46,7 +46,7 @@ "⤵ import" = "⤋ importar"; "↑ export" = "⇪ exportar"; "answer" = "Resposta"; -"Check" = "Confirmar"; +"check" = "Confirmar"; "Take a look" = "Espiar"; "Skip word" = "Pular palavra"; "search for words" = "buscar palavras"; @@ -72,3 +72,4 @@ "home_edit_button_title" = "Editar"; "home_import_button_title" = "Importar"; "home_export_button_title" = "Exportar"; +"nextWord" = "Próxima palavra"; diff --git a/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift b/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift index 6415b88..311e455 100644 --- a/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift +++ b/VocabularyTrainer/NewLanguage/NewLanguageViewController.swift @@ -75,7 +75,7 @@ final class NewLanguageViewController: UIViewController { }() private var hasDuplicates: Bool { - let newLanguage = textField.text ?? "" + let newLanguage: String = textField.text ?? .init() guard let savedLanguages = UserDefaults.standard.array(forKey: UserDefaultKeys.languages) as? [String] else { return false } diff --git a/VocabularyTrainer/Training/TrainingView.swift b/VocabularyTrainer/Training/TrainingView.swift index 3a22cc4..4d46f4d 100644 --- a/VocabularyTrainer/Training/TrainingView.swift +++ b/VocabularyTrainer/Training/TrainingView.swift @@ -26,6 +26,7 @@ final class TrainingView: UIView { private lazy var vocabulariesProgresses: [String: Float]? = [:] private lazy var isKeyShown: Bool? = false private lazy var currentKey: String? = .init() + private lazy var selectedLanguage: String? = .init() private lazy var barButton: UIButton = { let button: UIButton = .init(frame: .zero, @@ -74,9 +75,26 @@ final class TrainingView: UIView { height: textField.frame.height)) textField.leftViewMode = .always textField.addTarget(self, action: #selector(textFieldEvent), for: .allEvents) + textField.autocapitalizationType = .none + textField.autocorrectionType = .no return textField }() + private lazy var checkButton: UIButton = { + let button = UIButton(frame: .zero, + primaryAction: .init(handler: { [weak self] _ in + self?.checkButtonAction() + })) + button.backgroundColor = .systemGray2 + button.layer.cornerRadius = 3 + button.translatesAutoresizingMaskIntoConstraints = false + button.isEnabled = false + button.accessibilityTraits = .button + button.setTitle(Localizable.check.localize(), for: .normal) + button.titleLabel?.font = .preferredFont(forTextStyle: .headline) + return button + }() + // MARK: - Initializer init(selectedLanguage: String) { @@ -97,7 +115,8 @@ final class TrainingView: UIView { trainingLanguageLabel, wordLabel, answerLabel, - answerTextField]) + answerTextField, + checkButton]) } private func setUpConstraints() { @@ -119,7 +138,12 @@ final class TrainingView: UIView { answerTextField.topAnchor.constraint(equalTo: answerLabel.bottomAnchor, constant: 4), answerTextField.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -24), answerTextField.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 24), - answerTextField.heightAnchor.constraint(equalToConstant: 46) + answerTextField.heightAnchor.constraint(equalToConstant: 46), + + checkButton.topAnchor.constraint(equalTo: answerTextField.bottomAnchor, constant: 16), + checkButton.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -24), + checkButton.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 24), + checkButton.heightAnchor.constraint(equalToConstant: 42) ]) } @@ -127,23 +151,21 @@ final class TrainingView: UIView { let defaultLabel: String = NSLocalizedString("Training", comment: "Training") trainingLanguageLabel.text = "\(defaultLabel) \(selectedLanguage)" - guard let vocabs = UserDefaults.standard.dictionary(forKey: selectedLanguage) as? [String: String] else { - print("no vocabularies found") + guard let vocabs = UserDefaults.standard.dictionary(forKey: selectedLanguage) as? [String: String], + let progresses = UserDefaults.standard.dictionary(forKey: "\(selectedLanguage)Progress") as? [String: Float]? else { + // empty case return } - guard let progresses = UserDefaults.standard.dictionary(forKey: "\(selectedLanguage)Progress") as? [String: Float]? else { - print("no progresses found") - return - } vocabularies = vocabs vocabulariesProgresses = progresses + self.selectedLanguage = selectedLanguage } private func setUpTraining() { - guard let vocabs = vocabularies else { return } - guard let progresses = vocabulariesProgresses else { return } + guard let vocabs = vocabularies, + let progresses = vocabulariesProgresses else { return } let totalProgress = getTotalProgressFrom(progresses) @@ -185,16 +207,86 @@ final class TrainingView: UIView { return resultKey } + private func changeWordsProbability(increase: Bool, key: String) { + guard var progresses = vocabulariesProgresses, + let key = currentKey, + let progress = progresses[key] else { return } + + if increase { + progresses[key] = progress+Float(10.0) + } else if (progress-Float(3.0) > 0) { + progresses[key] = progress-Float(3.0) + } else { + progresses[key] = 1.0 + } + UserDefaults.standard.set(progresses, forKey: "\(selectedLanguage)Progress") + } + @objc private func textFieldEvent() { guard let text = answerTextField.text else { return } if text.isEmptyOrWhitespace() { - + checkButton.backgroundColor = .systemGray2 + checkButton.isEnabled = false } else { - + checkButton.backgroundColor = UIColor(named: "greenButton") + checkButton.isEnabled = true } answerTextField.borderStyle = .none answerTextField.layer.borderWidth = 0 } + + @objc func checkButtonAction() { + guard let usersAnswer = answerTextField.text, + let isKey = isKeyShown, + let key = currentKey, + let vocabs = vocabularies else { return } + + let solution: String? = isKey ? vocabs[key] : key + + if !usersAnswer.isEmpty, + usersAnswer.uppercased() == solution?.uppercased() { + rightAnswer(solution: solution, key: key) + } else { + wrongAnswer(key: key) + } + } + + private func rightAnswer(solution: String?, key: String) { + guard let solution = solution else { return } + changeWordsProbability(increase: false, key: key) + + UIView.animate(withDuration: 0.2, animations: { [weak self] in + self?.answerTextField.layer.borderColor = UIColor(named: "greenButton")?.cgColor + self?.answerTextField.layer.borderWidth = 1 + //self.checkInputButton.alpha = 0.0 + //self.takeALookButton.alpha = 0.0 + }, completion: { _ in + self.successHapticFeedback() + }) + answerTextField.text = solution + checkButton.setTitle(Localizable.nextWord.localize(), for: .normal) + debugPrint("AAAAAAA") + } + + private func wrongAnswer(key: String) { + changeWordsProbability(increase: true, key: key) + UIView.animate(withDuration: 0.2, animations: { [weak self] in + self?.answerTextField.layer.borderColor = UIColor(named: "red")?.cgColor + self?.answerTextField.layer.borderWidth = 1 + }) + checkButton.shake() + errorHapticFeedback() + } + + private func successHapticFeedback() { + let generator = UINotificationFeedbackGenerator() + generator.notificationOccurred(.success) + } + + private func errorHapticFeedback() { + let generator = UINotificationFeedbackGenerator() + generator.notificationOccurred(.error) + } } From 1257ba22899b843e0f53c94307744268fce1c43a Mon Sep 17 00:00:00 2001 From: Mariana Brasil Date: Sun, 30 Jul 2023 23:12:53 -0300 Subject: [PATCH 5/8] Added empty state view + building training screen --- VocabularyTrainer.xcodeproj/project.pbxproj | 82 ++++++++++++-- .../SadRobot.imageset/Contents.json | 12 +++ .../SadRobot.imageset/SadRobot.pdf | Bin 0 -> 7674 bytes .../Coordinator/MainCoordinator.swift | 6 ++ .../{ => Model}/LanguageImport.swift | 0 .../NewLanguageScreenProtocol.swift | 0 .../{ => View}/CollectionViewCell.swift | 0 .../Home Screen/View/HomeEmptyView.swift | 74 +++++++++++++ .../{ => View}/HomeLanguageHeaderView.swift | 0 .../AboutViewController.swift | 0 .../HomeViewController.swift | 40 +++++-- .../{ => ViewModel}/HomeViewModel.swift | 0 .../LanguageCellViewModel.swift | 0 .../Localizable/Localizable.swift | 2 + .../Localizable/de.lproj/Localizable.strings | 2 + .../Localizable/en.lproj/Localizable.strings | 2 + .../Localizable/hi.lproj/Localizable.strings | 2 + .../Localizable/nl.lproj/Localizable.strings | 2 + .../pt-BR.lproj/Localizable.strings | 2 + .../Training/View/TrainingEmptyView.swift | 100 ++++++++++++++++++ .../Training/{ => View}/TrainingView.swift | 39 +++++-- .../TrainingViewController.swift | 37 ++++++- 22 files changed, 373 insertions(+), 29 deletions(-) create mode 100644 VocabularyTrainer/Assets.xcassets/SadRobot.imageset/Contents.json create mode 100644 VocabularyTrainer/Assets.xcassets/SadRobot.imageset/SadRobot.pdf rename VocabularyTrainer/Home Screen/{ => Model}/LanguageImport.swift (100%) rename VocabularyTrainer/Home Screen/{ => Protocol}/NewLanguageScreenProtocol.swift (100%) rename VocabularyTrainer/Home Screen/{ => View}/CollectionViewCell.swift (100%) create mode 100644 VocabularyTrainer/Home Screen/View/HomeEmptyView.swift rename VocabularyTrainer/Home Screen/{ => View}/HomeLanguageHeaderView.swift (100%) rename VocabularyTrainer/Home Screen/{ => ViewController}/AboutViewController.swift (100%) rename VocabularyTrainer/Home Screen/{ => ViewController}/HomeViewController.swift (91%) rename VocabularyTrainer/Home Screen/{ => ViewModel}/HomeViewModel.swift (100%) rename VocabularyTrainer/Home Screen/{ => ViewModel}/LanguageCellViewModel.swift (100%) create mode 100644 VocabularyTrainer/Training/View/TrainingEmptyView.swift rename VocabularyTrainer/Training/{ => View}/TrainingView.swift (91%) rename VocabularyTrainer/Training/{ => ViewController}/TrainingViewController.swift (53%) diff --git a/VocabularyTrainer.xcodeproj/project.pbxproj b/VocabularyTrainer.xcodeproj/project.pbxproj index bd9467f..bac48d4 100644 --- a/VocabularyTrainer.xcodeproj/project.pbxproj +++ b/VocabularyTrainer.xcodeproj/project.pbxproj @@ -17,6 +17,8 @@ B38C29D4294D45F1006FCDEA /* Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38C29D3294D45F1006FCDEA /* Localizable.swift */; }; B38C29D8294D578C006FCDEA /* UILabel+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38C29D7294D578C006FCDEA /* UILabel+Extensions.swift */; }; B38C29DA294D68B4006FCDEA /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38C29D9294D68B4006FCDEA /* String+Extensions.swift */; }; + B38FD6BA2A7721DB00DF1043 /* HomeEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38FD6B92A7721DB00DF1043 /* HomeEmptyView.swift */; }; + B38FD6C42A7740E700DF1043 /* TrainingEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38FD6C32A7740E700DF1043 /* TrainingEmptyView.swift */; }; B3E01CED298F260F004D86C1 /* TrainingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E01CEC298F260F004D86C1 /* TrainingView.swift */; }; B3E01CEF298F2A7F004D86C1 /* TrainingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E01CEE298F2A7F004D86C1 /* TrainingViewController.swift */; }; B3E5421D294FB17A0015FD9C /* ModalCloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E5421C294FB17A0015FD9C /* ModalCloseButton.swift */; }; @@ -78,6 +80,8 @@ B38C29D3294D45F1006FCDEA /* Localizable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Localizable.swift; sourceTree = ""; }; B38C29D7294D578C006FCDEA /* UILabel+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Extensions.swift"; sourceTree = ""; }; B38C29D9294D68B4006FCDEA /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = ""; }; + B38FD6B92A7721DB00DF1043 /* HomeEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeEmptyView.swift; sourceTree = ""; }; + B38FD6C32A7740E700DF1043 /* TrainingEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingEmptyView.swift; sourceTree = ""; }; B3BBF4422909F64B004B2125 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = "pt-BR"; path = "pt-BR.lproj/pp.html"; sourceTree = ""; }; B3BBF4432909F653004B2125 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; B3E01CEC298F260F004D86C1 /* TrainingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingView.swift; sourceTree = ""; }; @@ -197,12 +201,73 @@ path = Extensions; sourceTree = ""; }; - B3E01CEB298F25FF004D86C1 /* Training */ = { + B38FD6BB2A77388000DF1043 /* View */ = { + isa = PBXGroup; + children = ( + CE431525295E08F4000F7FA2 /* CollectionViewCell.swift */, + CEF0605729510CD3001D2CEA /* HomeLanguageHeaderView.swift */, + B38FD6B92A7721DB00DF1043 /* HomeEmptyView.swift */, + ); + path = View; + sourceTree = ""; + }; + B38FD6BC2A77388E00DF1043 /* ViewModel */ = { + isa = PBXGroup; + children = ( + CEF0604F29510A26001D2CEA /* HomeViewModel.swift */, + CEF0605029510A26001D2CEA /* LanguageCellViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + B38FD6BD2A77389A00DF1043 /* ViewController */ = { + isa = PBXGroup; + children = ( + CEA8BCC42966108D00E2EAF9 /* AboutViewController.swift */, + CEF0604E29510A26001D2CEA /* HomeViewController.swift */, + ); + path = ViewController; + sourceTree = ""; + }; + B38FD6BE2A7738AF00DF1043 /* Model */ = { + isa = PBXGroup; + children = ( + CEF0605129510A27001D2CEA /* LanguageImport.swift */, + ); + path = Model; + sourceTree = ""; + }; + B38FD6BF2A7738BD00DF1043 /* Protocol */ = { + isa = PBXGroup; + children = ( + CEB77942295E503F00D7BF35 /* NewLanguageScreenProtocol.swift */, + ); + path = Protocol; + sourceTree = ""; + }; + B38FD6C02A773AED00DF1043 /* View */ = { isa = PBXGroup; children = ( B3E01CEC298F260F004D86C1 /* TrainingView.swift */, + B38FD6C32A7740E700DF1043 /* TrainingEmptyView.swift */, + ); + path = View; + sourceTree = ""; + }; + B38FD6C12A773AF100DF1043 /* ViewController */ = { + isa = PBXGroup; + children = ( B3E01CEE298F2A7F004D86C1 /* TrainingViewController.swift */, ); + path = ViewController; + sourceTree = ""; + }; + B3E01CEB298F25FF004D86C1 /* Training */ = { + isa = PBXGroup; + children = ( + B38FD6C12A773AF100DF1043 /* ViewController */, + B38FD6C02A773AED00DF1043 /* View */, + ); path = Training; sourceTree = ""; }; @@ -298,14 +363,11 @@ E37D1706261BCC22006C1F71 /* Home Screen */ = { isa = PBXGroup; children = ( - CE431525295E08F4000F7FA2 /* CollectionViewCell.swift */, - CEF0604E29510A26001D2CEA /* HomeViewController.swift */, - CEF0604F29510A26001D2CEA /* HomeViewModel.swift */, - CEF0605729510CD3001D2CEA /* HomeLanguageHeaderView.swift */, - CEF0605029510A26001D2CEA /* LanguageCellViewModel.swift */, - CEF0605129510A27001D2CEA /* LanguageImport.swift */, - CEB77942295E503F00D7BF35 /* NewLanguageScreenProtocol.swift */, - CEA8BCC42966108D00E2EAF9 /* AboutViewController.swift */, + B38FD6BF2A7738BD00DF1043 /* Protocol */, + B38FD6BE2A7738AF00DF1043 /* Model */, + B38FD6BD2A77389A00DF1043 /* ViewController */, + B38FD6BC2A77388E00DF1043 /* ViewModel */, + B38FD6BB2A77388000DF1043 /* View */, ); path = "Home Screen"; sourceTree = ""; @@ -480,6 +542,7 @@ buildActionMask = 2147483647; files = ( B3E54224294FDBA60015FD9C /* UIAccessibility+Extensions.swift in Sources */, + B38FD6BA2A7721DB00DF1043 /* HomeEmptyView.swift in Sources */, CEF0605629510A27001D2CEA /* LanguageImport.swift in Sources */, B3E54220294FC3290015FD9C /* UIView+Extensions.swift in Sources */, CE49D67E2963440300A8DDEB /* UIButton+Extensions.swift in Sources */, @@ -493,6 +556,7 @@ B38C29DA294D68B4006FCDEA /* String+Extensions.swift in Sources */, CE0012FF2243F21C002F86DE /* UIViewController+Extensions.swift in Sources */, B38C29D4294D45F1006FCDEA /* Localizable.swift in Sources */, + B38FD6C42A7740E700DF1043 /* TrainingEmptyView.swift in Sources */, CE31ED79290AC4B100AD3300 /* AddWordDelegate.swift in Sources */, CE431526295E08F4000F7FA2 /* CollectionViewCell.swift in Sources */, E37D170B261BCD59006C1F71 /* VocabularyDateFormatter.swift in Sources */, diff --git a/VocabularyTrainer/Assets.xcassets/SadRobot.imageset/Contents.json b/VocabularyTrainer/Assets.xcassets/SadRobot.imageset/Contents.json new file mode 100644 index 0000000..a88f322 --- /dev/null +++ b/VocabularyTrainer/Assets.xcassets/SadRobot.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "SadRobot.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/VocabularyTrainer/Assets.xcassets/SadRobot.imageset/SadRobot.pdf b/VocabularyTrainer/Assets.xcassets/SadRobot.imageset/SadRobot.pdf new file mode 100644 index 0000000000000000000000000000000000000000..25eccf07c3e9737d388bf0d5569554560e9c4849 GIT binary patch literal 7674 zcmdU!+m0K@5r*&QDdxt2eWBSt9{|IEb+BM0f*mOr28>)#6fLd8UCK);u>JJ;{+{6s zxnklKU?2zuXotn_>gqcDb(qh-fBMZMJLImjz3F$afA0GJ%P;$@zyJ1r(_j7Y-Rqw> z>jN}CSAX5yzCFC_9SdJhq~~|L5ARPlwD03@ZO^#z75wg2xBK_2yUp$Tx3k~B`f6hJ z>ci_pJM^2~-OWUMx!LbN+^siz9Wk$b{CM|k|6^|k(>}{XwsA-<_-gu`%uucO-t_-~ z8GHAKyUpsRyL!6$*Y$ey^7-Tb$*a?E>wWi2XFuZkXg+5C&6O~?kep4uO>rnLMq~Q* zO=kw@a)@YhsICT!riR2{Tl)R_wzDw|F<5VsL@v2R*WW<3L-O9{I$gy1-iA8Z>ay{@ z8@zQqjx-aEwSDBAWMH%I+R7s}hGJr2Wf^RY*4f_Gf#agBJ-Qf7_QknAVDDU#4cc$Z zkW$D#^wCS$5PVW__b1D zAg11jf$aekTGUhx|9VVVlZ{ndJ?4xy~jiz@~AGpaGe;jei4cYtT*ye^%vc-Bg9h%4Ra#ft)IOijF!JUe?gsk;LAb3z`jDxQ^Vqc5X zpkV@D5kv6T6e8L%DY=yUZI@6&Af(YosaTpI9Go?V2=^$Z1{0*Hl1+{BQ-@2{=2Q1+ z+YWauK9+?TlK^7!R0)B?pO7y82 z5Y5MGF(8n|6NrmH0()3X7VtzV_`xdFC#4P5;K5Q5cvh1qKx9TwSOxS0+!3k(9}4%z zVrpSR&J~OY;)i1D$Qe{kaCYo1)fZV13?SNF?Ohyl;y6z{fmId=zy{!`k^`q%F$Q7? zoW#0jt%$4nTsc_i=}al|B_ca|q-@3pnGsxI0cddyB1Z5U55q3^Rnv@hpSakn+uXjH z(jZSt_MMXXnDuemq6LjiSU;>7z^(tpVn9{KxBcPn!{&clBRsGUASDI|T9QE=_92+? z$mY_i8VfSxL!lbbhX=uWY-IpWHF(mQAyop7QxO9!8DN@k9(n=O@f&gsKtL(LqwC4& z)HE!>w}JEwQsXe>rvYp-#5D0wE}0lcjsc8CkD0m%U@xR;4smeygiJw>!fIs;Pbw6NOOcGBS@GcmjoReKI3S(j#-~ zGv3bH5Qqy^C6c($R8L5Qiz5QJL$hOYtNf0RJs~9Zuu{+l?U?8lU&c0tp*ylI7&-Ek zdO4lsR22AZrqmc!jsh$dj~KGwo53G-=tz=I+N!-rS>yFUT44^<-Y1Z^-IO2&Zn+&G zO0F2SgAs5H)n`_QpAJZvpb3Tgs1Ybp4Ip&c6%@snT;#t7vI21of*}NDs#^Cv-B+LZ3Ho7ao^r zXZw$J(*-1#1xE*E4G8{$Lh-^+vsIt{dU*cousUoS zqi3Q0S+DSRE6_4?t9Hs2zR%pUGK{f&OV{pr`+_wQDJ%=)sp6W6I}p0)Fz*j;9F^~|=LK7P?(z4)*_T)*G`c1e+K zH~$?|HP!Zsg{K~!Ub27r=XSlbZ$1KvTZ;x#tLM$ib!xFP#ZOhwOC>>3-I84(0Z={B zpY&=#c?67aXox6%N-e4MAy5}X#^*=|4R;NRk$g(g1+aQ*Um85>ebAVrDjn{+V?i`f zDYRQ*SxY1fQ;d-bRC!gXB%7p8CV8-&wl^SIAYZq#4Ty#-rI)g*fSpE+O>}sLN}3Xj za+@?V9AioG1vRntLH!zz<<=Rkf$e0WG@6z?om-AhGFlABcNDJ~6V0mmfu zd?>h(F7+V&Hd{c;qb<-8yinyO6D_&smrkDfcF!Nz{(ufocMtE~kd-!wKDnpJprdzc zeB?JXtdiC<{sDSaJxzY2gql@RQEu2uyIt@b#uI#@m&Gx-tH_#XplEKPMh$&tW+Y^3 zY(-C>Xc(9ZwJC!%?g}M-giJ4l&7!IZS~m(B_A~iFe>6>A;|?d5ttnzopc(>IVFEg7 z^iEYq0%r_B=|M-|HZyR+*CPG5`jU~MWkN!`VQ>Np6Ercdl(8xB5FYPlx7uf{j|e z4iJf|ZN3Wd!JvZGwBTG@aws&Q(oPeuQ0)*&COQ5E^10*t(c|4GdAvhn0#AiCBO1_)xO@m!;z_^^h|;DJ zs(-!agW%>=ylY4?lDClQqWMCAFJvZgtmR~N2m(lgopInylr*3TL>kwHyc`VQg-lfF z0IZ?2RJxlsD}%oby2v%nNFl;@zQjV^b|b5^{WAdY8>kNG&Xk2mo4Pfi&_rvJ{iI;x zmSCx5oVc86V-{u6(E3wHPo8c_ExddSP+(Hagx~>*Z@vsda6J$nQ_>9K7tA9y6`QQL z?Z|7Yh6tTAGBG~26sMZ}nD42_g0-Wz=4I1f^+?Cx2n7u-G;PQx6NucAS@0j`a$th) zQ%xyZ3C~u_yy+Gy5Wuubqg6)0ntlPp)A96*+M`bJl-8zc%uCOyv+N7QnY5gI>KYuU zY61M02#uXE4bOnK9K6s7e)edl4D8G+m#gU4k>f%;J^EOOD>(*X#H`#|(o2d5q17+a z_yV82IAAt8DSkHFrDUkl(inb7qnIQ?smEYk(0rd9AXo@A$#@$LD;^3;LsGG$0!r;L zG?FKLSl60lrjc~f+9RZB1z0P^gc<5qp$WH}sqq!1R!B-@s5#52aUfMY;z*Q?6@4aa zw4JjiN`o~nt?`>0W1NvJEJ@mot5QV)W0S%dev{g#;9#^dvTp`s9Koa?LDZhJm-if0 zoPtT3`eTtpx)UT&C%fCj=9V+nG#rWF>#f{@(3xl_y+xyq7tu?>zg)jTTq+)|Z12@{)RWx@ZU5*J zdnl*8mQka4>6-iH(B=M5R)^Jg_x61AuXmfDIv~t<@}BWSjmvbkhdzBImp(mRdHXn3 z3hn8HM8R`T0?*NrKJzMG$6&&9Qsm{seG=pSb5hW7?wo|H-WMWkV0ONWaQbK!?-J)# zhr8AFc5~NBb>BY42%qnFH=8f|&#&KnF String { return NSLocalizedString(self.rawValue, comment: "") diff --git a/VocabularyTrainer/Localizable/de.lproj/Localizable.strings b/VocabularyTrainer/Localizable/de.lproj/Localizable.strings index c153713..d794a90 100644 --- a/VocabularyTrainer/Localizable/de.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/de.lproj/Localizable.strings @@ -71,3 +71,5 @@ "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"; +"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."; diff --git a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings index 0b1a0ac..8e9ec3a 100644 --- a/VocabularyTrainer/Localizable/en.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/en.lproj/Localizable.strings @@ -74,3 +74,5 @@ "home_import_button_title" = "Import"; "home_export_button_title" = "Export"; "nextWord" = "Next word"; +"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."; diff --git a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings index af5bf38..383041c 100644 --- a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings @@ -71,3 +71,5 @@ "home_import_button_title" = "Import"; "home_export_button_title" = "Export"; "nextWord" = "अगला शब्द"; +"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."; diff --git a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings index 95a0de5..d0067d4 100644 --- a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings @@ -70,3 +70,5 @@ "home_import_button_title" = "Import"; "home_export_button_title" = "Export"; "nextWord" = "Volgende woord"; +"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."; diff --git a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings index deb5e1d..7e69eda 100644 --- a/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/pt-BR.lproj/Localizable.strings @@ -73,3 +73,5 @@ "home_import_button_title" = "Importar"; "home_export_button_title" = "Exportar"; "nextWord" = "Próxima palavra"; +"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."; diff --git a/VocabularyTrainer/Training/View/TrainingEmptyView.swift b/VocabularyTrainer/Training/View/TrainingEmptyView.swift new file mode 100644 index 0000000..f7447f5 --- /dev/null +++ b/VocabularyTrainer/Training/View/TrainingEmptyView.swift @@ -0,0 +1,100 @@ +// +// TrainingEmptyView.swift +// VocabularyTrainer +// +// Created by Mariana Brasil on 30/07/23. +// Copyright © 2023 mic. All rights reserved. +// + +import UIKit + +// MARK: - Delegate +protocol TrainingEmptyViewDelegate: AnyObject { + func tappedBarButton() +} + +final class TrainingEmptyView: UIView { + + typealias Colors = HomeViewModel.Colors + + weak var delegate: TrainingEmptyViewDelegate? + + // MARK: - Private properties + + /// Bar button to drag/close the view + private lazy var barButton: UIButton = { + let button: UIButton = .init(frame: .zero, + primaryAction: .init(handler: { [weak self] _ in + self?.delegate?.tappedBarButton() + })) + button.layer.cornerRadius = 3 + button.backgroundColor = .systemGray + return button + }() + + /// Image view showing the sad robot image. + private let imageView: UIImageView = { + let view = UIImageView() + view.translatesAutoresizingMaskIntoConstraints = false + view.contentMode = .scaleAspectFit + view.image = UIImage(named: "SadRobot") + view.clipsToBounds = true + view.isAccessibilityElement = false + return view + }() + + /// Empty label when the user don't have any language added. + private lazy var emptyLabel: UILabel = .createLabel(font: UIFontMetrics(forTextStyle: .body) + .scaledFont(for: .systemFont(ofSize: 14, weight: .regular)), + text: Localizable.emptyWord.localize(), + fontColor: Colors.subtitle, + textAlignment: .center) + + // MARK: - Initializer + + init() { + super.init(frame: .zero) + setupUI() + setupConstraints() + } + + required init?(coder: NSCoder) { nil } + + // MARK: - Setup + + private func setupUI() { + addSubviews([barButton, imageView, emptyLabel]) + startAnimation() + translatesAutoresizingMaskIntoConstraints = false + } + + private func setupConstraints() { + NSLayoutConstraint.activate([ + barButton.topAnchor.constraint(equalTo: self.topAnchor, constant: 16), + barButton.centerXAnchor.constraint(equalTo: self.centerXAnchor), + barButton.heightAnchor.constraint(equalToConstant: 5), + barButton.widthAnchor.constraint(equalToConstant: 40), + + imageView.leadingAnchor.constraint(equalTo: leadingAnchor), + imageView.topAnchor.constraint(equalTo: barButton.bottomAnchor, constant: 36), + imageView.trailingAnchor.constraint(equalTo: trailingAnchor), + imageView.heightAnchor.constraint(equalToConstant: 70), + imageView.widthAnchor.constraint(equalToConstant: 80), + + emptyLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 24), + emptyLabel.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 28), + emptyLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -24), + emptyLabel.bottomAnchor.constraint(equalTo: bottomAnchor), + ]) + } + + private func startAnimation() { + UIView.animate(withDuration: 1, animations: { [weak self] in + self?.imageView.frame.origin.y -= 5 + }){ [weak self] _ in + UIView.animateKeyframes(withDuration: 1, delay: 0.1, options: [.autoreverse, .repeat], animations: { + self?.imageView.frame.origin.y += 5 + }) + } + } +} diff --git a/VocabularyTrainer/Training/TrainingView.swift b/VocabularyTrainer/Training/View/TrainingView.swift similarity index 91% rename from VocabularyTrainer/Training/TrainingView.swift rename to VocabularyTrainer/Training/View/TrainingView.swift index 4d46f4d..6de26ef 100644 --- a/VocabularyTrainer/Training/TrainingView.swift +++ b/VocabularyTrainer/Training/View/TrainingView.swift @@ -8,10 +8,9 @@ import UIKit -// MARK: - Protocol +// MARK: - Delegate protocol TrainingViewDelegate: AnyObject { func tappedBarButton() - func setWordLabel() } // MARK: - Training View Class @@ -21,6 +20,7 @@ final class TrainingView: UIView { // MARK: - Private properties weak var delegate: TrainingViewDelegate? + // MARK: - Private properties private lazy var vocabularies: [String: String]? = [:] private lazy var vocabulariesProgresses: [String: Float]? = [:] @@ -153,17 +153,18 @@ final class TrainingView: UIView { guard let vocabs = UserDefaults.standard.dictionary(forKey: selectedLanguage) as? [String: String], let progresses = UserDefaults.standard.dictionary(forKey: "\(selectedLanguage)Progress") as? [String: Float]? else { - // empty case return } - vocabularies = vocabs vocabulariesProgresses = progresses self.selectedLanguage = selectedLanguage } private func setUpTraining() { + setUpResetTextField() + setUpDisabledCheckButton() + guard let vocabs = vocabularies, let progresses = vocabulariesProgresses else { return } @@ -222,16 +223,32 @@ final class TrainingView: UIView { UserDefaults.standard.set(progresses, forKey: "\(selectedLanguage)Progress") } + private func setUpResetTextField() { + answerTextField.text = .init() + answerTextField.borderStyle = .none + answerTextField.layer.borderWidth = 0 + } + + private func setUpDisabledCheckButton() { + checkButton.backgroundColor = .systemGray2 + checkButton.isEnabled = false + checkButton.setTitle(Localizable.check.localize(), for: .normal) + } + + private func setUpEnabledCheckButton() { + checkButton.backgroundColor = UIColor(named: "greenButton") + checkButton.isEnabled = true + checkButton.setTitle(Localizable.check.localize(), for: .normal) + } + @objc private func textFieldEvent() { guard let text = answerTextField.text else { return } if text.isEmptyOrWhitespace() { - checkButton.backgroundColor = .systemGray2 - checkButton.isEnabled = false + setUpDisabledCheckButton() } else { - checkButton.backgroundColor = UIColor(named: "greenButton") - checkButton.isEnabled = true + setUpEnabledCheckButton() } answerTextField.borderStyle = .none answerTextField.layer.borderWidth = 0 @@ -245,6 +262,11 @@ final class TrainingView: UIView { let solution: String? = isKey ? vocabs[key] : key + if checkButton.titleLabel?.text != Localizable.check.localize() { + setUpTraining() + return + } + if !usersAnswer.isEmpty, usersAnswer.uppercased() == solution?.uppercased() { rightAnswer(solution: solution, key: key) @@ -267,7 +289,6 @@ final class TrainingView: UIView { }) answerTextField.text = solution checkButton.setTitle(Localizable.nextWord.localize(), for: .normal) - debugPrint("AAAAAAA") } private func wrongAnswer(key: String) { diff --git a/VocabularyTrainer/Training/TrainingViewController.swift b/VocabularyTrainer/Training/ViewController/TrainingViewController.swift similarity index 53% rename from VocabularyTrainer/Training/TrainingViewController.swift rename to VocabularyTrainer/Training/ViewController/TrainingViewController.swift index c595a05..ad21f65 100644 --- a/VocabularyTrainer/Training/TrainingViewController.swift +++ b/VocabularyTrainer/Training/ViewController/TrainingViewController.swift @@ -18,7 +18,14 @@ final class TrainingViewController: UIViewController { private let selectedLanguage: String - private lazy var trainingView: UIView = TrainingView(selectedLanguage: selectedLanguage) + private lazy var trainingView: TrainingView = .init(selectedLanguage: selectedLanguage) + + private lazy var emptyView: TrainingEmptyView = .init() + + private var isWordsEmpty: Bool { + guard let dictionary = UserDefaults.standard.dictionary(forKey: selectedLanguage) else { return true } + return false + } // MARK: - Init @@ -26,7 +33,6 @@ final class TrainingViewController: UIViewController { self.selectedLanguage = language super.init(nibName: nil, bundle: nil) setUpUI() - setUpConstraints() hideKeyboardWhenTappedAround() } @@ -35,12 +41,15 @@ final class TrainingViewController: UIViewController { // MARK: - Private Methods private func setUpUI() { - view.addSubview(trainingView) view.backgroundColor = .systemBackground - trainingView.translatesAutoresizingMaskIntoConstraints = false + isWordsEmpty ? setUpEmptyView() : setUpSuccessView() } - private func setUpConstraints() { + private func setUpSuccessView() { + view.addSubview(trainingView) + trainingView.delegate = self + trainingView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ trainingView.topAnchor.constraint(equalTo: view.topAnchor), trainingView.leadingAnchor.constraint(equalTo: view.leadingAnchor), @@ -48,4 +57,22 @@ final class TrainingViewController: UIViewController { trainingView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } + + private func setUpEmptyView() { + view.addSubview(emptyView) + emptyView.delegate = self + emptyView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + emptyView.topAnchor.constraint(equalTo: view.topAnchor), + emptyView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + emptyView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + ]) + } +} + +extension TrainingViewController: TrainingViewDelegate, TrainingEmptyViewDelegate { + func tappedBarButton() { + dismiss(animated: true) + } } From ac1ace83abcf0fe8dae3cc2f5284045f7db40239 Mon Sep 17 00:00:00 2001 From: Mariana Brasil Date: Wed, 16 Aug 2023 18:28:09 -0300 Subject: [PATCH 6/8] Wip --- VocabularyTrainer.xcodeproj/project.pbxproj | 4 - .../Coordinator/MainCoordinator.swift | 2 - .../Localizable/de.lproj/Localizable.strings | 4 +- .../Localizable/hi.lproj/Localizable.strings | 4 +- .../Localizable/nl.lproj/Localizable.strings | 4 +- .../Training/View/TrainingView.swift | 7 +- .../TrainingViewController.swift | 7 +- .../TrainingViewController1.swift | 398 ------------------ 8 files changed, 11 insertions(+), 419 deletions(-) delete mode 100644 VocabularyTrainer/TrainingViewController1.swift diff --git a/VocabularyTrainer.xcodeproj/project.pbxproj b/VocabularyTrainer.xcodeproj/project.pbxproj index bac48d4..da7fa38 100644 --- a/VocabularyTrainer.xcodeproj/project.pbxproj +++ b/VocabularyTrainer.xcodeproj/project.pbxproj @@ -26,7 +26,6 @@ B3E54224294FDBA60015FD9C /* UIAccessibility+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E54223294FDBA60015FD9C /* UIAccessibility+Extensions.swift */; }; CE0012FF2243F21C002F86DE /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0012FE2243F21C002F86DE /* UIViewController+Extensions.swift */; }; CE05F622229F17AF0097E3BB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CE05F624229F17AF0097E3BB /* Localizable.strings */; }; - CE0FE4F82238585A00430FDE /* TrainingViewController1.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0FE4F72238585A00430FDE /* TrainingViewController1.swift */; }; CE2EB8272245406A006B1C6D /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE2EB8262245406A006B1C6D /* Launch Screen.storyboard */; }; CE31ED77290AC49F00AD3300 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE31ED76290AC49F00AD3300 /* AppDelegate.swift */; }; CE31ED79290AC4B100AD3300 /* AddWordDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE31ED78290AC4B100AD3300 /* AddWordDelegate.swift */; }; @@ -92,7 +91,6 @@ CE0012FE2243F21C002F86DE /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extensions.swift"; sourceTree = ""; }; CE05F623229F17AF0097E3BB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; CE05F625229F17C40097E3BB /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - CE0FE4F72238585A00430FDE /* TrainingViewController1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingViewController1.swift; sourceTree = ""; }; CE2EB8262245406A006B1C6D /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; CE31ED76290AC49F00AD3300 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; CE31ED78290AC4B100AD3300 /* AddWordDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddWordDelegate.swift; sourceTree = ""; }; @@ -324,7 +322,6 @@ B38C29DB294D6A70006FCDEA /* Extensions */, B3606D1B294D3D3E009E62E9 /* NewLanguage */, B3657DFE290740F8000D76C8 /* AddWord */, - CE0FE4F72238585A00430FDE /* TrainingViewController1.swift */, B3E01CEB298F25FF004D86C1 /* Training */, CE2EB8262245406A006B1C6D /* Launch Screen.storyboard */, B3606D1E294D459E009E62E9 /* Localizable */, @@ -567,7 +564,6 @@ B3E5421D294FB17A0015FD9C /* ModalCloseButton.swift in Sources */, B38C29D8294D578C006FCDEA /* UILabel+Extensions.swift in Sources */, CEB77945295E563200D7BF35 /* UserDefaults+Extensions.swift in Sources */, - CE0FE4F82238585A00430FDE /* TrainingViewController1.swift in Sources */, 18943A0A29094F470017E1A2 /* LanguageScreenViewController.swift in Sources */, 28716F4F290EF54B00EACCA1 /* StoryBoarded.swift in Sources */, CE86C5822235C971008A5B73 /* Helper.swift in Sources */, diff --git a/VocabularyTrainer/Coordinator/MainCoordinator.swift b/VocabularyTrainer/Coordinator/MainCoordinator.swift index 116e868..b87f29d 100644 --- a/VocabularyTrainer/Coordinator/MainCoordinator.swift +++ b/VocabularyTrainer/Coordinator/MainCoordinator.swift @@ -19,9 +19,7 @@ class MainCoordinator: Coordinator { } func start() { - // let homeVC = HomeScreenViewController() let homeVC = HomeViewController(viewModel: HomeViewModel(coordinator: self)) - // homeVC.coordinator = self navigationController.pushViewController(homeVC, animated: false) } diff --git a/VocabularyTrainer/Localizable/de.lproj/Localizable.strings b/VocabularyTrainer/Localizable/de.lproj/Localizable.strings index d794a90..a02f2e1 100644 --- a/VocabularyTrainer/Localizable/de.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/de.lproj/Localizable.strings @@ -71,5 +71,5 @@ "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"; -"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."; +"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."; diff --git a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings index 383041c..8172344 100644 --- a/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/hi.lproj/Localizable.strings @@ -71,5 +71,5 @@ "home_import_button_title" = "Import"; "home_export_button_title" = "Export"; "nextWord" = "अगला शब्द"; -"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."; +"emptyLanguage" = "आपके पास अभी तक कोई भाषाएँ अभ्यास करने के लिए उपलब्ध नहीं हैं! \n + बटन दबाकर अपनी सीखने की यात्रा शुरू करें।"; +"emptyWord" = "आपके पास अभी तक कोई शब्द अभ्यास करने के लिए नहीं हैं! \n नए शब्द जोड़ने के लिए संपादित बटन दबाएं।"; diff --git a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings index d0067d4..6e44e3f 100644 --- a/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings +++ b/VocabularyTrainer/Localizable/nl.lproj/Localizable.strings @@ -70,5 +70,5 @@ "home_import_button_title" = "Import"; "home_export_button_title" = "Export"; "nextWord" = "Volgende woord"; -"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."; +"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."; diff --git a/VocabularyTrainer/Training/View/TrainingView.swift b/VocabularyTrainer/Training/View/TrainingView.swift index 6de26ef..e530974 100644 --- a/VocabularyTrainer/Training/View/TrainingView.swift +++ b/VocabularyTrainer/Training/View/TrainingView.swift @@ -13,13 +13,12 @@ protocol TrainingViewDelegate: AnyObject { func tappedBarButton() } -// MARK: - Training View Class +// MARK: - Training View final class TrainingView: UIView { - // MARK: - Private properties - weak var delegate: TrainingViewDelegate? + // MARK: - Private properties private lazy var vocabularies: [String: String]? = [:] @@ -282,8 +281,6 @@ final class TrainingView: UIView { UIView.animate(withDuration: 0.2, animations: { [weak self] in self?.answerTextField.layer.borderColor = UIColor(named: "greenButton")?.cgColor self?.answerTextField.layer.borderWidth = 1 - //self.checkInputButton.alpha = 0.0 - //self.takeALookButton.alpha = 0.0 }, completion: { _ in self.successHapticFeedback() }) diff --git a/VocabularyTrainer/Training/ViewController/TrainingViewController.swift b/VocabularyTrainer/Training/ViewController/TrainingViewController.swift index ad21f65..3479a73 100644 --- a/VocabularyTrainer/Training/ViewController/TrainingViewController.swift +++ b/VocabularyTrainer/Training/ViewController/TrainingViewController.swift @@ -23,15 +23,14 @@ final class TrainingViewController: UIViewController { private lazy var emptyView: TrainingEmptyView = .init() private var isWordsEmpty: Bool { - guard let dictionary = UserDefaults.standard.dictionary(forKey: selectedLanguage) else { return true } - return false + return UserDefaults.standard.dictionary(forKey: selectedLanguage) == nil } // MARK: - Init init(with language: String) { - self.selectedLanguage = language - super.init(nibName: nil, bundle: nil) + self.selectedLanguage = language + super.init(nibName: nil, bundle: nil) setUpUI() hideKeyboardWhenTappedAround() } diff --git a/VocabularyTrainer/TrainingViewController1.swift b/VocabularyTrainer/TrainingViewController1.swift deleted file mode 100644 index 9ba147c..0000000 --- a/VocabularyTrainer/TrainingViewController1.swift +++ /dev/null @@ -1,398 +0,0 @@ -// -// TrainingViewController.swift -// VocabularyTrainer -// -// Created by skrr on 12.03.19. -// Copyright © 2019 mic. All rights reserved. -// - -import UIKit - -class TrainingViewController1: UIViewController { - - private let selectedLanguage: String - var vocabularies: [String: String]? - var vocabulariesProgresses: [String: Float]? - var isKeyShown: Bool? - var currentKey: String? - var coordinator: MainCoordinator? - - var wrongAnswerButton = UIButton() - var rightAnswerButton = UIButton() - var nextButton = UIButton() - var checkInputButton = UIButton() - var takeALookButton = UIButton() - - var currentVocabulary = UILabel() - var answerInput = UITextField() - var currentTrainingHeader = UILabel() - - let checkLookStackView = UIStackView() - let rightWrongStackView = UIStackView() - - let defaultInputBackground = UIColor.systemBackground.withAlphaComponent(0.5) - - // MARK: - Init - - init(with language: String) { - self.selectedLanguage = language - super.init(nibName: nil, bundle: nil) - setButtonActions() - setViewHierarchy() - setConstraints() - } - - required init?(coder: NSCoder) { nil } - - private func setButtonActions() { - wrongAnswerButton.addTarget(self, action: #selector(wrongAnswerTapped(_:)), for: .touchUpInside) - rightAnswerButton.addTarget(self, action: #selector(rightAnswerTapped(_:)), for: .touchUpInside) - nextButton.addTarget(self, action: #selector(nextButtonTapped(_:)), for: .touchUpInside) - checkInputButton.addTarget(self, action: #selector(checkInputTapped(_:)), for: .touchUpInside) - takeALookButton.addTarget(self, action: #selector(takeALookTapped(_:)), for: .touchUpInside) - } - - private func setViewHierarchy() { - - let rightWrongButtons = [wrongAnswerButton, rightAnswerButton] - let checkTakeLookButtons = [checkInputButton, takeALookButton] - - rightWrongButtons.forEach { rightWrongStackView.addArrangedSubview($0) } - checkTakeLookButtons.forEach { checkLookStackView.addArrangedSubview($0) } - rightWrongStackView.distribution = .fillEqually - rightWrongStackView.spacing = 16 - checkLookStackView.distribution = .fillEqually - checkLookStackView.spacing = 16 - - [ - currentTrainingHeader, - currentVocabulary, - answerInput, - checkLookStackView, - rightWrongStackView, - nextButton - ].forEach { view.addSubview($0) } - } - - private func setConstraints() { - [ - // inside rightWrongStackView - wrongAnswerButton, rightAnswerButton, - // inside checkLookStackView - checkInputButton, takeALookButton, - - currentTrainingHeader, - currentVocabulary, - answerInput, - checkLookStackView, - rightWrongStackView, - nextButton - ].forEach { $0.translatesAutoresizingMaskIntoConstraints = false } - - NSLayoutConstraint.activate([ - currentTrainingHeader.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor), - currentTrainingHeader.centerXAnchor.constraint(equalTo: view.centerXAnchor), - - currentVocabulary.topAnchor.constraint(equalTo: currentTrainingHeader.bottomAnchor, constant: 16), - currentVocabulary.centerXAnchor.constraint(equalTo: view.centerXAnchor), - - answerInput.topAnchor.constraint(equalTo: currentVocabulary.bottomAnchor, constant: 16), - answerInput.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 16), - answerInput.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -16), - - checkLookStackView.topAnchor.constraint(equalTo: answerInput.bottomAnchor, constant: 16), - checkLookStackView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 16), - checkLookStackView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -16), - - rightWrongStackView.topAnchor.constraint(equalTo: answerInput.bottomAnchor, constant: 16), - rightWrongStackView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 16), - rightWrongStackView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -16), - - nextButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -32), - nextButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 44), - nextButton.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 16), - nextButton.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -16), - - wrongAnswerButton.heightAnchor.constraint(greaterThanOrEqualToConstant: Layout.defaultButtonHeight), - rightAnswerButton.heightAnchor.constraint(greaterThanOrEqualToConstant: Layout.defaultButtonHeight), - checkInputButton.heightAnchor.constraint(greaterThanOrEqualToConstant: Layout.defaultButtonHeight), - takeALookButton.heightAnchor.constraint(greaterThanOrEqualToConstant: Layout.defaultButtonHeight) - ]) - - } - - override func viewDidLoad() { - super.viewDidLoad() - setup() - } - - private func setup() { - - currentVocabulary.font = .preferredFont(forTextStyle: .title1) - setGradientBackground(view: view) - currentTrainingHeader.numberOfLines = 0 - currentTrainingHeader.lineBreakMode = .byWordWrapping - currentTrainingHeader.text = """ - \(NSLocalizedString("Training:", comment: "Training:")) - \(selectedLanguage) - """ - - styleButtons() - pickNewVocabAndUpdateView() - self.rightAnswerButton.isHidden = true - self.wrongAnswerButton.isHidden = true - - answerInput.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged) - answerInput.backgroundColor = defaultInputBackground - answerInput.font = UIFont.preferredFont(forTextStyle: .title1) - - hideKeyboardWhenTappedAround() - localize() - } - - func reloadVocabulariesAndProgresses() { - let language = selectedLanguage - - guard let vocabs = UserDefaults.standard.dictionary(forKey: language) as? [String: String] else { - print("no vocabularies found") - return - } - - guard let progresses = UserDefaults.standard.dictionary(forKey: "\(language)Progress") as? [String: Float]? else { - print("no progresses found") - return - } - - vocabularies = vocabs - vocabulariesProgresses = progresses - } - - func getTotalProgressFrom(_ vocabulariesProgresses: [String: Float]) -> Float { - var result = Float(0) - - for progress in vocabulariesProgresses { - result += progress.value - } - - return result - } - - func pickRandomKeyFrom(_ vocabularies: [String: String], withProgresses vocabulariesProgresses: [String: Float], totalProgress: Float) -> String { - let randomThreshold = Float.random(in: 0...totalProgress) - // print(randomThreshold) - var summedUpProgresses = Float(0) - var resultKey = "" - - for (key, value) in vocabulariesProgresses { - summedUpProgresses += value - if summedUpProgresses > randomThreshold { - resultKey = key - print("key's progress: \(value)") - break - } - } - return resultKey - } - - func pickNewVocabAndUpdateView() { - - resetAnswerInput() - answerInput.text = "" - - reloadVocabulariesAndProgresses() - guard let vocabs = vocabularies else {print("no vocabularies"); return} - guard let progresses = vocabulariesProgresses else {print("no progresses"); return } - - let totalProgress = getTotalProgressFrom(progresses) - - currentKey = pickRandomKeyFrom(vocabs, withProgresses: progresses, totalProgress: totalProgress) - - guard let key = currentKey else {print("no key"); return} - - print("all vocabs \(vocabs)") - print("all progresses \(progresses)") - print("randomkey: \(key)") - if (Int.random(in: 0...1) == 0) { - currentVocabulary.text = key - isKeyShown = true - } else { - currentVocabulary.text = vocabs[key] - isKeyShown = false - } - nextButton.setTitle(NSLocalizedString("Skip word", comment: "Skip word"), for: .normal) - } - - @objc func nextButtonTapped(_ sender: Any) { - pickNewVocabAndUpdateView() - } - - @objc func rightAnswerTapped(_ sender: Any) { - guard let key = currentKey else {print("no current key"); return} - changeWordsProbability(increase: false, key: key) - pickNewVocabAndUpdateView() - } - - @objc func wrongAnswerTapped(_ sender: Any) { - guard let key = currentKey else {print("no current key"); return} - changeWordsProbability(increase: true, key: key) - pickNewVocabAndUpdateView() - } - - @objc func checkInputTapped(_ sender: Any) { - - guard let usersAnswer = answerInput.text else { print("no answer given"); return } -// guard let solution = vocabularies?[vocabulary] else {print("no solution found"); return} - var solution: String? - guard let isKey = isKeyShown else {print("no key"); return} - guard let key = currentKey else {print("no current key"); return} - guard let vocabs = vocabularies else {print("no vocabularies"); return} - - if isKey { - solution = vocabs[key] - } else { - solution = key - } - - if !usersAnswer.isEmpty { - if usersAnswer.uppercased() == solution?.uppercased() { - - // update progress - changeWordsProbability(increase: false, key: key) - - print("right") - UIView.animate(withDuration: 0.2, animations: { - self.answerInput.backgroundColor = BackgroundColor.green - self.checkInputButton.alpha = 0.0 - self.takeALookButton.alpha = 0.0 - }, completion: { _ in - self.checkInputButton.isHidden = true - self.takeALookButton.isHidden = true - }) - showToast(message: NSLocalizedString("That's right! 🤠", comment: "That's right! 🤠"), yCoord: 400.0) - answerInput.text = solution - nextButton.setTitle("Next word", for: .normal) - } else { - - // update progress - changeWordsProbability(increase: true, key: key) - - print("wrong, right is \(String(describing: solution))") - UIView.animate(withDuration: 0.2, animations: { - self.answerInput.backgroundColor = BackgroundColor.red - }) - showToast(message: NSLocalizedString("That's wrong 😕", comment: "That's wrong 😕"), yCoord: 400.0) - } - } - } - - @objc func takeALookTapped(_ sender: Any) { - guard let key = currentKey else {print("no current key"); return} - var solution: String - guard let isKey = isKeyShown else {print("no key"); return} - - if isKey { - solution = vocabularies?[key] ?? "nothing given" - } else { - solution = key - } - - answerInput.text = solution - - UIView.animate(withDuration: 0.2, animations: { - self.answerInput.backgroundColor = BackgroundColor.blue - self.checkInputButton.alpha = 0.0 - self.takeALookButton.alpha = 0.0 - }, completion: { _ in - self.rightAnswerButton.isHidden = false - self.wrongAnswerButton.isHidden = false - self.checkInputButton.isHidden = true - self.takeALookButton.isHidden = true - - UIView.animate(withDuration: 0.2, animations: { - self.view.layoutIfNeeded() - self.rightAnswerButton.alpha = 1.0 - self.wrongAnswerButton.alpha = 1.0 - }) - - }) - } - - @objc func textFieldDidChange(_ textField: UITextField) { - resetAnswerInput() - } - - func resetAnswerInput() { - UIView.animate(withDuration: 0.2, animations: { - self.rightAnswerButton.alpha = 0.0 - self.wrongAnswerButton.alpha = 0.0 - self.answerInput.backgroundColor = self.defaultInputBackground - }, completion: { _ in - self.rightAnswerButton.isHidden = true - self.wrongAnswerButton.isHidden = true - self.checkInputButton.isHidden = false - self.takeALookButton.isHidden = false - - UIView.animate(withDuration: 0.1, animations: { - self.checkInputButton.alpha = 1.0 - self.takeALookButton.alpha = 1.0 - self.view.layoutIfNeeded() - }) - }) - } - - func styleButtons() { - rightAnswerButton.backgroundColor = BackgroundColor.green - rightAnswerButton.layer.cornerRadius = 5.0 - - wrongAnswerButton.backgroundColor = BackgroundColor.red - wrongAnswerButton.layer.cornerRadius = 5.0 - - checkInputButton.backgroundColor = BackgroundColor.blue - checkInputButton.layer.cornerRadius = 5.0 - checkInputButton.setTitleColor(.black, for: .normal) - - takeALookButton.backgroundColor = BackgroundColor.blue - takeALookButton.layer.cornerRadius = 5.0 - takeALookButton.setTitleColor(.black, for: .normal) - - nextButton.backgroundColor = BackgroundColor.yellow - nextButton.layer.cornerRadius = 5.0 - nextButton.setTitleColor(.black, for: .normal) - - } - - func changeWordsProbability(increase: Bool, key: String) { - guard var progresses = vocabulariesProgresses else {print("no progresses"); return} - - guard let key = currentKey else {print("no current key"); return} - guard let progress = progresses[key] else {print("no progress"); return} - - let language = selectedLanguage - - if increase { - progresses[key] = progress+Float(10.0) - } else { - if (progress-Float(3.0) > 0) { - progresses[key] = progress-Float(3.0) - } else { - progresses[key] = 1.0 - } - } - UserDefaults.standard.set(progresses, forKey: "\(language)Progress") - - } - - func localize() { - answerInput.placeholder = NSLocalizedString("answer", comment: "answer") - checkInputButton.setTitle(NSLocalizedString("Check", comment: "Check"), for: .normal) - takeALookButton.setTitle(NSLocalizedString("Take a look", comment: "Take a look"), for: .normal) - nextButton.setTitle(NSLocalizedString("Skip word", comment: "Skip word"), for: .normal) - - rightAnswerButton.setTitle(NSLocalizedString("👍 I was right", comment: "👍 I was right"), for: .normal) - wrongAnswerButton.setTitle(NSLocalizedString("👎 I was wrong", comment: "👎 I was wrong"), for: .normal) - } - - // TODO: Export when pressed Backbutton or closed app (app delegate!) -} - -extension TrainingViewController: StoryBoarded {} From d577eafd3eed4bb2f673163e262de628af05856d Mon Sep 17 00:00:00 2001 From: Mariana Brasil Date: Wed, 16 Aug 2023 22:45:47 -0300 Subject: [PATCH 7/8] Fix color at dark mode --- .../Colors/grayButton.colorset/Contents.json | 18 ++++++++++++++++++ .../Training/View/TrainingView.swift | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/VocabularyTrainer/Assets.xcassets/Colors/grayButton.colorset/Contents.json b/VocabularyTrainer/Assets.xcassets/Colors/grayButton.colorset/Contents.json index f66d5ab..5c50be9 100644 --- a/VocabularyTrainer/Assets.xcassets/Colors/grayButton.colorset/Contents.json +++ b/VocabularyTrainer/Assets.xcassets/Colors/grayButton.colorset/Contents.json @@ -11,6 +11,24 @@ } }, "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB9", + "green" : "0xB9", + "red" : "0xB9" + } + }, + "idiom" : "universal" } ], "info" : { diff --git a/VocabularyTrainer/Training/View/TrainingView.swift b/VocabularyTrainer/Training/View/TrainingView.swift index d0faf62..0e87c56 100644 --- a/VocabularyTrainer/Training/View/TrainingView.swift +++ b/VocabularyTrainer/Training/View/TrainingView.swift @@ -115,7 +115,7 @@ final class TrainingView: UIView { button.addGestureRecognizer(longPressRecognizer) longPressRecognizer.minimumPressDuration = 0.05 button.layer.cornerRadius = 3 - button.backgroundColor = UIColor(named: "grayButton") + button.backgroundColor = .darkGray button.accessibilityTraits = .button button.setTitle(Localizable.takeLook.localize(), for: .normal) button.titleLabel?.font = .preferredFont(forTextStyle: .caption1) @@ -371,7 +371,7 @@ final class TrainingView: UIView { answerTextField.text = solution } else if gestureRecognizer.state == .ended { answerTextField.text = nil - takeLookButton.backgroundColor = UIColor(named: "grayButton") + takeLookButton.backgroundColor = .darkGray } } From e63c898eebd3805d9311ce0b89860f45ca6b8a96 Mon Sep 17 00:00:00 2001 From: Mariana Brasil Date: Sat, 19 Aug 2023 19:41:03 -0300 Subject: [PATCH 8/8] Fix bundle id --- VocabularyTrainer.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/VocabularyTrainer.xcodeproj/project.pbxproj b/VocabularyTrainer.xcodeproj/project.pbxproj index 152046c..89ced17 100644 --- a/VocabularyTrainer.xcodeproj/project.pbxproj +++ b/VocabularyTrainer.xcodeproj/project.pbxproj @@ -764,7 +764,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 972LY7PTVT; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = VocabularyTrainer/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -772,7 +772,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.3.1; - PRODUCT_BUNDLE_IDENTIFIER = st.mic.VocabularyTrainer.Mariana; + PRODUCT_BUNDLE_IDENTIFIER = st.mic.VocabularyTrainer; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; @@ -788,7 +788,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 972LY7PTVT; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = VocabularyTrainer/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -796,7 +796,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.3.1; - PRODUCT_BUNDLE_IDENTIFIER = st.mic.VocabularyTrainer.Mariana; + PRODUCT_BUNDLE_IDENTIFIER = st.mic.VocabularyTrainer; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0;